* src/mcs51/gen.c (outBitC): optimized for no 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
1861     {
1862       if (getDataSize (result))
1863         {
1864           emitcode ("clr", "a");
1865           emitcode ("rlc", "a");
1866           outAcc (result);
1867         }
1868     }
1869 }
1870
1871 /*-----------------------------------------------------------------*/
1872 /* toBoolean - emit code for orl a,operator(sizeop)                */
1873 /*-----------------------------------------------------------------*/
1874 static void
1875 toBoolean (operand * oper)
1876 {
1877   int size = AOP_SIZE (oper) - 1;
1878   int offset = 1;
1879   bool AccUsed = FALSE;
1880   bool pushedB;
1881
1882   while (!AccUsed && size--)
1883     {
1884       AccUsed |= aopGetUsesAcc(oper, offset++);
1885     }
1886
1887   size = AOP_SIZE (oper) - 1;
1888   offset = 1;
1889   MOVA (aopGet (oper, 0, FALSE, FALSE));
1890   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1891     {
1892       pushedB = pushB ();
1893       emitcode("mov", "b,a");
1894       while (--size)
1895         {
1896           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1897           emitcode ("orl", "b,a");
1898         }
1899       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1900       emitcode ("orl", "a,b");
1901       popB (pushedB);
1902     }
1903   else
1904     {
1905       while (size--)
1906         {
1907           emitcode ("orl", "a,%s",
1908                     aopGet (oper, offset++, FALSE, FALSE));
1909         }
1910     }
1911 }
1912
1913 /*-----------------------------------------------------------------*/
1914 /* toCarry - make boolean and move into carry                      */
1915 /*-----------------------------------------------------------------*/
1916 static void
1917 toCarry (operand * oper)
1918 {
1919   /* if the operand is a literal then
1920      we know what the value is */
1921   if (AOP_TYPE (oper) == AOP_LIT)
1922     {
1923       if ((int) operandLitValue (oper))
1924         SETC;
1925       else
1926         CLRC;
1927     }
1928   else if (AOP_TYPE (oper) == AOP_CRY)
1929     {
1930       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1931     }
1932   else
1933     {
1934       /* or the operand into a */
1935       toBoolean (oper);
1936       /* set C, if a >= 1 */
1937       emitcode ("add", "a,#0xff");
1938     }
1939 }
1940
1941 /*-----------------------------------------------------------------*/
1942 /* assignBit - assign operand to bit operand                       */
1943 /*-----------------------------------------------------------------*/
1944 static void
1945 assignBit (operand * result, operand * right)
1946 {
1947   /* if the right side is a literal then
1948      we know what the value is */
1949   if (AOP_TYPE (right) == AOP_LIT)
1950     {
1951       if ((int) operandLitValue (right))
1952         aopPut (result, one, 0);
1953       else
1954         aopPut (result, zero, 0);
1955     }
1956   else
1957     {
1958       toCarry (right);
1959       aopPut (result, "c", 0);
1960     }
1961 }
1962
1963
1964 /*-------------------------------------------------------------------*/
1965 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1966 /*-------------------------------------------------------------------*/
1967 static char *
1968 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1969 {
1970   char * l;
1971
1972   if (aopGetUsesAcc (oper, offset))
1973     {
1974       emitcode("mov", "b,a");
1975       MOVA (aopGet (oper, offset, bit16, dname));
1976       emitcode("xch", "a,b");
1977       aopPut (oper, "a", offset);
1978       emitcode("xch", "a,b");
1979       l = "b";
1980     }
1981   else
1982     {
1983       l = aopGet (oper, offset, bit16, dname);
1984       emitcode("xch", "a,%s", l);
1985     }
1986   return l;
1987 }
1988
1989
1990 /*-----------------------------------------------------------------*/
1991 /* genNot - generate code for ! operation                          */
1992 /*-----------------------------------------------------------------*/
1993 static void
1994 genNot (iCode * ic)
1995 {
1996   symbol *tlbl;
1997
1998   D (emitcode (";", "genNot"));
1999
2000   /* assign asmOps to operand & result */
2001   aopOp (IC_LEFT (ic), ic, FALSE);
2002   aopOp (IC_RESULT (ic), ic, TRUE);
2003
2004   /* if in bit space then a special case */
2005   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2006     {
2007       /* if left==result then cpl bit */
2008       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2009         {
2010           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2011         }
2012       else
2013         {
2014           toCarry (IC_LEFT (ic));
2015           emitcode ("cpl", "c");
2016           outBitC (IC_RESULT (ic));
2017         }
2018       goto release;
2019     }
2020
2021   toBoolean (IC_LEFT (ic));
2022
2023   /* set C, if a == 0 */
2024   tlbl = newiTempLabel (NULL);
2025   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2026   emitLabel (tlbl);
2027   outBitC (IC_RESULT (ic));
2028
2029 release:
2030   /* release the aops */
2031   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2032   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2033 }
2034
2035
2036 /*-----------------------------------------------------------------*/
2037 /* genCpl - generate code for complement                           */
2038 /*-----------------------------------------------------------------*/
2039 static void
2040 genCpl (iCode * ic)
2041 {
2042   int offset = 0;
2043   int size;
2044   symbol *tlbl;
2045   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2046
2047   D(emitcode (";", "genCpl"));
2048
2049   /* assign asmOps to operand & result */
2050   aopOp (IC_LEFT (ic), ic, FALSE);
2051   aopOp (IC_RESULT (ic), ic, TRUE);
2052
2053   /* special case if in bit space */
2054   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2055     {
2056       char *l;
2057
2058       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2059           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2060         {
2061           /* promotion rules are responsible for this strange result:
2062              bit -> int -> ~int -> bit
2063              uchar -> int -> ~int -> bit
2064           */
2065           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2066           goto release;
2067         }
2068
2069       tlbl=newiTempLabel(NULL);
2070       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2071       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2072           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2073           IS_AOP_PREG (IC_LEFT (ic)))
2074         {
2075           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2076         }
2077       else
2078         {
2079           MOVA (l);
2080           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2081         }
2082       emitLabel (tlbl);
2083       outBitC (IC_RESULT(ic));
2084       goto release;
2085     }
2086
2087   size = AOP_SIZE (IC_RESULT (ic));
2088   while (size--)
2089     {
2090       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2091       MOVA (l);
2092       emitcode ("cpl", "a");
2093       aopPut (IC_RESULT (ic), "a", offset++);
2094     }
2095
2096
2097 release:
2098   /* release the aops */
2099   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2100   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2101 }
2102
2103 /*-----------------------------------------------------------------*/
2104 /* genUminusFloat - unary minus for floating points                */
2105 /*-----------------------------------------------------------------*/
2106 static void
2107 genUminusFloat (operand * op, operand * result)
2108 {
2109   int size, offset = 0;
2110   char *l;
2111
2112   D (emitcode (";", "genUminusFloat"));
2113
2114   /* for this we just copy and then flip the bit */
2115
2116   size = AOP_SIZE (op) - 1;
2117
2118   while (size--)
2119     {
2120       aopPut (result,
2121               aopGet (op, offset, FALSE, FALSE),
2122               offset);
2123       offset++;
2124     }
2125
2126   l = aopGet (op, offset, FALSE, FALSE);
2127   MOVA (l);
2128
2129   emitcode ("cpl", "acc.7");
2130   aopPut (result, "a", offset);
2131 }
2132
2133 /*-----------------------------------------------------------------*/
2134 /* genUminus - unary minus code generation                         */
2135 /*-----------------------------------------------------------------*/
2136 static void
2137 genUminus (iCode * ic)
2138 {
2139   int offset, size;
2140   sym_link *optype;
2141
2142   D (emitcode (";", "genUminus"));
2143
2144   /* assign asmops */
2145   aopOp (IC_LEFT (ic), ic, FALSE);
2146   aopOp (IC_RESULT (ic), ic, TRUE);
2147
2148   /* if both in bit space then special
2149      case */
2150   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2151       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2152     {
2153
2154       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2155       emitcode ("cpl", "c");
2156       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2157       goto release;
2158     }
2159
2160   optype = operandType (IC_LEFT (ic));
2161
2162   /* if float then do float stuff */
2163   if (IS_FLOAT (optype))
2164     {
2165       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2166       goto release;
2167     }
2168
2169   /* otherwise subtract from zero */
2170   size = AOP_SIZE (IC_LEFT (ic));
2171   offset = 0;
2172   while (size--)
2173     {
2174       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2175       if (!strcmp (l, "a"))
2176         {
2177           if (offset == 0)
2178             SETC;
2179           emitcode ("cpl", "a");
2180           emitcode ("addc", "a,#0");
2181         }
2182       else
2183         {
2184           if (offset == 0)
2185             CLRC;
2186           emitcode ("clr", "a");
2187           emitcode ("subb", "a,%s", l);
2188         }
2189       aopPut (IC_RESULT (ic), "a", offset++);
2190     }
2191
2192   /* if any remaining bytes in the result */
2193   /* we just need to propagate the sign   */
2194   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2195     {
2196       emitcode ("rlc", "a");
2197       emitcode ("subb", "a,acc");
2198       while (size--)
2199         aopPut (IC_RESULT (ic), "a", offset++);
2200     }
2201
2202 release:
2203   /* release the aops */
2204   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2205   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2206 }
2207
2208 /*-----------------------------------------------------------------*/
2209 /* saveRegisters - will look for a call and save the registers     */
2210 /*-----------------------------------------------------------------*/
2211 static void
2212 saveRegisters (iCode * lic)
2213 {
2214   int i;
2215   iCode *ic;
2216   bitVect *rsave;
2217
2218   /* look for call */
2219   for (ic = lic; ic; ic = ic->next)
2220     if (ic->op == CALL || ic->op == PCALL)
2221       break;
2222
2223   if (!ic)
2224     {
2225       fprintf (stderr, "found parameter push with no function call\n");
2226       return;
2227     }
2228
2229   /* if the registers have been saved already or don't need to be then
2230      do nothing */
2231   if (ic->regsSaved)
2232     return;
2233   if (IS_SYMOP(IC_LEFT(ic)) &&
2234       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2235        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2236     return;
2237
2238   /* save the registers in use at this time but skip the
2239      ones for the result */
2240   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2241                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2242
2243   ic->regsSaved = 1;
2244   if (options.useXstack)
2245     {
2246       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2247       int nBits = bitVectnBitsOn (rsavebits);
2248       int count = bitVectnBitsOn (rsave);
2249
2250       if (nBits != 0)
2251         {
2252           count = count - nBits + 1;
2253           /* remove all but the first bits as they are pushed all at once */
2254           rsave = bitVectCplAnd (rsave, rsavebits);
2255           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2256         }
2257       freeBitVect (rsavebits);
2258
2259       if (count == 1)
2260         {
2261           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2262           if (reg->type == REG_BIT)
2263             {
2264               emitcode ("mov", "a,%s", reg->base);
2265             }
2266           else
2267             {
2268               emitcode ("mov", "a,%s", reg->name);
2269             }
2270           emitcode ("mov", "r0,%s", spname);
2271           emitcode ("inc", "%s", spname);// allocate before use
2272           emitcode ("movx", "@r0,a");
2273           if (bitVectBitValue (rsave, R0_IDX))
2274             emitcode ("mov", "r0,a");
2275         }
2276       else if (count != 0)
2277         {
2278           if (bitVectBitValue (rsave, R0_IDX))
2279             {
2280               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2281             }
2282           emitcode ("mov", "r0,%s", spname);
2283           MOVA ("r0");
2284           emitcode ("add", "a,#%d", count);
2285           emitcode ("mov", "%s,a", spname);
2286           for (i = 0; i < mcs51_nRegs; i++)
2287             {
2288               if (bitVectBitValue (rsave, i))
2289                 {
2290                   regs * reg = REG_WITH_INDEX (i);
2291                   if (i == R0_IDX)
2292                     {
2293                       emitcode ("pop", "acc");
2294                       emitcode ("push", "acc");
2295                     }
2296                   else if (reg->type == REG_BIT)
2297                     {
2298                       emitcode ("mov", "a,%s", reg->base);
2299                     }
2300                   else
2301                     {
2302                       emitcode ("mov", "a,%s", reg->name);
2303                     }
2304                   emitcode ("movx", "@r0,a");
2305                   if (--count)
2306                     {
2307                       emitcode ("inc", "r0");
2308                     }
2309                 }
2310             }
2311           if (bitVectBitValue (rsave, R0_IDX))
2312             {
2313               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2314             }
2315         }
2316     }
2317   else
2318     {
2319       bool bits_pushed = FALSE;
2320       for (i = 0; i < mcs51_nRegs; i++)
2321         {
2322           if (bitVectBitValue (rsave, i))
2323             {
2324               bits_pushed = pushReg (i, bits_pushed);
2325             }
2326         }
2327     }
2328   freeBitVect (rsave);
2329 }
2330
2331 /*-----------------------------------------------------------------*/
2332 /* unsaveRegisters - pop the pushed registers                      */
2333 /*-----------------------------------------------------------------*/
2334 static void
2335 unsaveRegisters (iCode * ic)
2336 {
2337   int i;
2338   bitVect *rsave;
2339
2340   /* restore the registers in use at this time but skip the
2341      ones for the result */
2342   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2343                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2344
2345   if (options.useXstack)
2346     {
2347       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2348       int nBits = bitVectnBitsOn (rsavebits);
2349       int count = bitVectnBitsOn (rsave);
2350
2351       if (nBits != 0)
2352         {
2353           count = count - nBits + 1;
2354           /* remove all but the first bits as they are popped all at once */
2355           rsave = bitVectCplAnd (rsave, rsavebits);
2356           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2357         }
2358       freeBitVect (rsavebits);
2359
2360       if (count == 1)
2361         {
2362           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2363           emitcode ("mov", "r0,%s", spname);
2364           emitcode ("dec", "r0");
2365           emitcode ("movx", "a,@r0");
2366           if (reg->type == REG_BIT)
2367             {
2368               emitcode ("mov", "%s,a", reg->base);
2369             }
2370           else
2371             {
2372               emitcode ("mov", "%s,a", reg->name);
2373             }
2374           emitcode ("dec", "%s", spname);
2375         }
2376       else if (count != 0)
2377         {
2378           emitcode ("mov", "r0,%s", spname);
2379           for (i = mcs51_nRegs; i >= 0; i--)
2380             {
2381               if (bitVectBitValue (rsave, i))
2382                 {
2383                   regs * reg = REG_WITH_INDEX (i);
2384                   emitcode ("dec", "r0");
2385                   emitcode ("movx", "a,@r0");
2386                   if (i == R0_IDX)
2387                     {
2388                       emitcode ("push", "acc");
2389                     }
2390                   else if (reg->type == REG_BIT)
2391                     {
2392                       emitcode ("mov", "%s,a", reg->base);
2393                     }
2394                   else
2395                     {
2396                       emitcode ("mov", "%s,a", reg->name);
2397                     }
2398                 }
2399             }
2400           emitcode ("mov", "%s,r0", spname);
2401           if (bitVectBitValue (rsave, R0_IDX))
2402             {
2403               emitcode ("pop", "ar0");
2404             }
2405         }
2406     }
2407   else
2408     {
2409       bool bits_popped = FALSE;
2410       for (i = mcs51_nRegs; i >= 0; i--)
2411         {
2412           if (bitVectBitValue (rsave, i))
2413             {
2414               bits_popped = popReg (i, bits_popped);
2415             }
2416         }
2417     }
2418   freeBitVect (rsave);
2419 }
2420
2421
2422 /*-----------------------------------------------------------------*/
2423 /* pushSide -                                                      */
2424 /*-----------------------------------------------------------------*/
2425 static void
2426 pushSide (operand * oper, int size)
2427 {
2428   int offset = 0;
2429   while (size--)
2430     {
2431       char *l = aopGet (oper, offset++, FALSE, TRUE);
2432       if (AOP_TYPE (oper) != AOP_REG &&
2433           AOP_TYPE (oper) != AOP_DIR &&
2434           strcmp (l, "a"))
2435         {
2436           MOVA (l);
2437           emitcode ("push", "acc");
2438         }
2439       else
2440         {
2441           emitcode ("push", "%s", l);
2442         }
2443     }
2444 }
2445
2446 /*-----------------------------------------------------------------*/
2447 /* assignResultValue - also indicates if acc is in use afterwards  */
2448 /*-----------------------------------------------------------------*/
2449 static bool
2450 assignResultValue (operand * oper, operand * func)
2451 {
2452   int offset = 0;
2453   int size = AOP_SIZE (oper);
2454   bool accuse = FALSE;
2455   bool pushedA = FALSE;
2456
2457   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2458     {
2459       outBitC (oper);
2460       return FALSE;
2461     }
2462
2463   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2464     {
2465       emitcode ("push", "acc");
2466       pushedA = TRUE;
2467     }
2468   while (size--)
2469     {
2470       if ((offset == 3) && pushedA)
2471         emitcode ("pop", "acc");
2472       accuse |= aopPut (oper, fReturn[offset], offset);
2473       offset++;
2474     }
2475   return accuse;
2476 }
2477
2478
2479 /*-----------------------------------------------------------------*/
2480 /* genXpush - pushes onto the external stack                       */
2481 /*-----------------------------------------------------------------*/
2482 static void
2483 genXpush (iCode * ic)
2484 {
2485   asmop *aop = newAsmop (0);
2486   regs *r;
2487   int size, offset = 0;
2488
2489   D (emitcode (";", "genXpush"));
2490
2491   aopOp (IC_LEFT (ic), ic, FALSE);
2492   r = getFreePtr (ic, &aop, FALSE);
2493
2494   size = AOP_SIZE (IC_LEFT (ic));
2495
2496   if (size == 1)
2497     {
2498       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2499       emitcode ("mov", "%s,%s", r->name, spname);
2500       emitcode ("inc", "%s", spname); // allocate space first
2501       emitcode ("movx", "@%s,a", r->name);
2502     }
2503   else
2504     {
2505       // allocate space first
2506       emitcode ("mov", "%s,%s", r->name, spname);
2507       MOVA (r->name);
2508       emitcode ("add", "a,#%d", size);
2509       emitcode ("mov", "%s,a", spname);
2510
2511       while (size--)
2512         {
2513           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2514           emitcode ("movx", "@%s,a", r->name);
2515           emitcode ("inc", "%s", r->name);
2516         }
2517     }
2518
2519   freeAsmop (NULL, aop, ic, TRUE);
2520   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2521 }
2522
2523 /*-----------------------------------------------------------------*/
2524 /* genIpush - generate code for pushing this gets a little complex */
2525 /*-----------------------------------------------------------------*/
2526 static void
2527 genIpush (iCode * ic)
2528 {
2529   int size, offset = 0;
2530   char *l;
2531   char *prev = "";
2532
2533   D (emitcode (";", "genIpush"));
2534
2535   /* if this is not a parm push : ie. it is spill push
2536      and spill push is always done on the local stack */
2537   if (!ic->parmPush)
2538     {
2539
2540       /* and the item is spilt then do nothing */
2541       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2542         return;
2543
2544       aopOp (IC_LEFT (ic), ic, FALSE);
2545       size = AOP_SIZE (IC_LEFT (ic));
2546       /* push it on the stack */
2547       while (size--)
2548         {
2549           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2550           if (*l == '#')
2551             {
2552               MOVA (l);
2553               l = "acc";
2554             }
2555           emitcode ("push", "%s", l);
2556         }
2557       return;
2558     }
2559
2560   /* this is a parameter push: in this case we call
2561      the routine to find the call and save those
2562      registers that need to be saved */
2563   saveRegisters (ic);
2564
2565   /* if use external stack then call the external
2566      stack pushing routine */
2567   if (options.useXstack)
2568     {
2569       genXpush (ic);
2570       return;
2571     }
2572
2573   /* then do the push */
2574   aopOp (IC_LEFT (ic), ic, FALSE);
2575
2576   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2577   size = AOP_SIZE (IC_LEFT (ic));
2578
2579   while (size--)
2580     {
2581       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2582       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2583           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2584         {
2585           if (strcmp (l, prev) || *l == '@')
2586             MOVA (l);
2587           emitcode ("push", "acc");
2588         }
2589       else
2590         {
2591           emitcode ("push", "%s", l);
2592         }
2593       prev = l;
2594     }
2595
2596   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2597 }
2598
2599 /*-----------------------------------------------------------------*/
2600 /* genIpop - recover the registers: can happen only for spilling   */
2601 /*-----------------------------------------------------------------*/
2602 static void
2603 genIpop (iCode * ic)
2604 {
2605   int size, offset;
2606
2607   D (emitcode (";", "genIpop"));
2608
2609   /* if the temp was not pushed then */
2610   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2611     return;
2612
2613   aopOp (IC_LEFT (ic), ic, FALSE);
2614   size = AOP_SIZE (IC_LEFT (ic));
2615   offset = (size - 1);
2616   while (size--)
2617     {
2618       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2619                                      FALSE, TRUE));
2620     }
2621
2622   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2623 }
2624
2625 /*-----------------------------------------------------------------*/
2626 /* saveRBank - saves an entire register bank on the stack          */
2627 /*-----------------------------------------------------------------*/
2628 static void
2629 saveRBank (int bank, iCode * ic, bool pushPsw)
2630 {
2631   int i;
2632   int count = 8 + (pushPsw ? 1 : 0);
2633   asmop *aop = NULL;
2634   regs *r = NULL;
2635
2636   if (options.useXstack)
2637     {
2638       if (!ic)
2639         {
2640           /* Assume r0 is available for use. */
2641           r = REG_WITH_INDEX (R0_IDX);
2642         }
2643       else
2644         {
2645           aop = newAsmop (0);
2646           r = getFreePtr (ic, &aop, FALSE);
2647         }
2648       // allocate space first
2649       emitcode ("mov", "%s,%s", r->name, spname);
2650       MOVA (r->name);
2651       emitcode ("add", "a,#%d", count);
2652       emitcode ("mov", "%s,a", spname);
2653     }
2654
2655   for (i = 0; i < 8; i++)
2656     {
2657       if (options.useXstack)
2658         {
2659           emitcode ("mov", "a,(%s+%d)",
2660                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2661           emitcode ("movx", "@%s,a", r->name);
2662           if (--count)
2663             emitcode ("inc", "%s", r->name);
2664         }
2665       else
2666         emitcode ("push", "(%s+%d)",
2667                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2668     }
2669
2670   if (pushPsw)
2671     {
2672       if (options.useXstack)
2673         {
2674           emitcode ("mov", "a,psw");
2675           emitcode ("movx", "@%s,a", r->name);
2676         }
2677       else
2678         {
2679           emitcode ("push", "psw");
2680         }
2681
2682       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2683     }
2684
2685   if (aop)
2686     {
2687       freeAsmop (NULL, aop, ic, TRUE);
2688     }
2689
2690   if (ic)
2691     {
2692       ic->bankSaved = 1;
2693     }
2694 }
2695
2696 /*-----------------------------------------------------------------*/
2697 /* unsaveRBank - restores the register bank from stack             */
2698 /*-----------------------------------------------------------------*/
2699 static void
2700 unsaveRBank (int bank, iCode * ic, bool popPsw)
2701 {
2702   int i;
2703   asmop *aop = NULL;
2704   regs *r = NULL;
2705
2706   if (options.useXstack)
2707     {
2708       if (!ic)
2709         {
2710           /* Assume r0 is available for use. */
2711           r = REG_WITH_INDEX (R0_IDX);;
2712         }
2713       else
2714         {
2715           aop = newAsmop (0);
2716           r = getFreePtr (ic, &aop, FALSE);
2717         }
2718       emitcode ("mov", "%s,%s", r->name, spname);
2719     }
2720
2721   if (popPsw)
2722     {
2723       if (options.useXstack)
2724         {
2725           emitcode ("dec", "%s", r->name);
2726           emitcode ("movx", "a,@%s", r->name);
2727           emitcode ("mov", "psw,a");
2728         }
2729       else
2730         {
2731           emitcode ("pop", "psw");
2732         }
2733     }
2734
2735   for (i = 7; i >= 0; i--)
2736     {
2737       if (options.useXstack)
2738         {
2739           emitcode ("dec", "%s", r->name);
2740           emitcode ("movx", "a,@%s", r->name);
2741           emitcode ("mov", "(%s+%d),a",
2742                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2743         }
2744       else
2745         {
2746           emitcode ("pop", "(%s+%d)",
2747                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2748         }
2749     }
2750
2751   if (options.useXstack)
2752     {
2753       emitcode ("mov", "%s,%s", spname, r->name);
2754     }
2755
2756   if (aop)
2757     {
2758       freeAsmop (NULL, aop, ic, TRUE);
2759     }
2760 }
2761
2762 /*-----------------------------------------------------------------*/
2763 /* genSend - gen code for SEND                                     */
2764 /*-----------------------------------------------------------------*/
2765 static void genSend(set *sendSet)
2766 {
2767   iCode *sic;
2768   int bit_count = 0;
2769
2770   /* first we do all bit parameters */
2771   for (sic = setFirstItem (sendSet); sic;
2772        sic = setNextItem (sendSet))
2773     {
2774       if (sic->argreg > 12)
2775         {
2776           int bit = sic->argreg-13;
2777
2778           aopOp (IC_LEFT (sic), sic, FALSE);
2779
2780           /* if left is a literal then
2781              we know what the value is */
2782           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2783             {
2784               if (((int) operandLitValue (IC_LEFT (sic))))
2785                   emitcode ("setb", "b[%d]", bit);
2786               else
2787                   emitcode ("clr", "b[%d]", bit);
2788             }
2789           else
2790             {
2791               /* we need to or */
2792               toCarry (IC_LEFT (sic));
2793               emitcode ("mov", "b[%d],c", bit);
2794             }
2795           bit_count++;
2796           BitBankUsed = 1;
2797
2798           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2799         }
2800     }
2801
2802   if (bit_count)
2803     {
2804       saveRegisters (setFirstItem (sendSet));
2805       emitcode ("mov", "bits,b");
2806     }
2807
2808   /* then we do all other parameters */
2809   for (sic = setFirstItem (sendSet); sic;
2810        sic = setNextItem (sendSet))
2811     {
2812       if (sic->argreg <= 12)
2813         {
2814           int size, offset = 0;
2815           aopOp (IC_LEFT (sic), sic, FALSE);
2816           size = AOP_SIZE (IC_LEFT (sic));
2817
2818           if (sic->argreg == 1)
2819             {
2820               while (size--)
2821                 {
2822                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2823                   if (strcmp (l, fReturn[offset]))
2824                     {
2825                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2826                     }
2827                   offset++;
2828                 }
2829             }
2830           else
2831             {
2832               while (size--)
2833                 {
2834                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2835                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2836                   offset++;
2837                 }
2838             }
2839           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2840         }
2841     }
2842 }
2843
2844 /*-----------------------------------------------------------------*/
2845 /* selectRegBank - emit code to select the register bank           */
2846 /*-----------------------------------------------------------------*/
2847 static void
2848 selectRegBank (short bank, bool keepFlags)
2849 {
2850   /* if f.e. result is in carry */
2851   if (keepFlags)
2852     {
2853       emitcode ("anl", "psw,#0xE7");
2854       if (bank)
2855         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2856     }
2857   else
2858     {
2859       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2860     }
2861 }
2862
2863 /*-----------------------------------------------------------------*/
2864 /* genCall - generates a call statement                            */
2865 /*-----------------------------------------------------------------*/
2866 static void
2867 genCall (iCode * ic)
2868 {
2869   sym_link *dtype;
2870   sym_link *etype;
2871 //  bool restoreBank = FALSE;
2872   bool swapBanks = FALSE;
2873   bool accuse = FALSE;
2874   bool accPushed = FALSE;
2875   bool resultInF0 = FALSE;
2876   bool assignResultGenerated = FALSE;
2877
2878   D (emitcode (";", "genCall"));
2879
2880   dtype = operandType (IC_LEFT (ic));
2881   etype = getSpec(dtype);
2882   /* if send set is not empty then assign */
2883   if (_G.sendSet)
2884     {
2885         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2886             genSend(reverseSet(_G.sendSet));
2887         } else {
2888             genSend(_G.sendSet);
2889         }
2890       _G.sendSet = NULL;
2891     }
2892
2893   /* if we are calling a not _naked function that is not using
2894      the same register bank then we need to save the
2895      destination registers on the stack */
2896   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2897       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2898        !IFFUNC_ISISR (dtype))
2899     {
2900       swapBanks = TRUE;
2901     }
2902
2903   /* if caller saves & we have not saved then */
2904   if (!ic->regsSaved)
2905       saveRegisters (ic);
2906
2907   if (swapBanks)
2908     {
2909         emitcode ("mov", "psw,#0x%02x",
2910            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2911     }
2912
2913   /* make the call */
2914   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2915     {
2916       if (IFFUNC_CALLEESAVES(dtype))
2917         {
2918           werror (E_BANKED_WITH_CALLEESAVES);
2919         }
2920       else
2921         {
2922           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2923                      OP_SYMBOL (IC_LEFT (ic))->rname :
2924                      OP_SYMBOL (IC_LEFT (ic))->name);
2925
2926           emitcode ("mov", "r0,#%s", l);
2927           emitcode ("mov", "r1,#(%s >> 8)", l);
2928           emitcode ("mov", "r2,#(%s >> 16)", l);
2929           emitcode ("lcall", "__sdcc_banked_call");
2930         }
2931     }
2932   else
2933     {
2934       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2935                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2936                                 OP_SYMBOL (IC_LEFT (ic))->name));
2937     }
2938
2939   if (swapBanks)
2940     {
2941       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2942     }
2943
2944   /* if we need assign a result value */
2945   if ((IS_ITEMP (IC_RESULT (ic)) &&
2946        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2947        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2948         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2949         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2950       IS_TRUE_SYMOP (IC_RESULT (ic)))
2951     {
2952
2953       _G.accInUse++;
2954       aopOp (IC_RESULT (ic), ic, FALSE);
2955       _G.accInUse--;
2956
2957       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2958       assignResultGenerated = TRUE;
2959
2960       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2961     }
2962
2963   /* adjust the stack for parameters if required */
2964   if (ic->parmBytes)
2965     {
2966       int i;
2967       if (ic->parmBytes > 3)
2968         {
2969           if (accuse)
2970             {
2971               emitcode ("push", "acc");
2972               accPushed = TRUE;
2973             }
2974           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2975               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2976               !assignResultGenerated)
2977             {
2978               emitcode ("mov", "F0,c");
2979               resultInF0 = TRUE;
2980             }
2981
2982           emitcode ("mov", "a,%s", spname);
2983           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2984           emitcode ("mov", "%s,a", spname);
2985
2986           /* unsaveRegisters from xstack needs acc, but */
2987           /* unsaveRegisters from stack needs this popped */
2988           if (accPushed && !options.useXstack)
2989             {
2990               emitcode ("pop", "acc");
2991               accPushed = FALSE;
2992             }
2993         }
2994       else
2995         for (i = 0; i < ic->parmBytes; i++)
2996           emitcode ("dec", "%s", spname);
2997     }
2998
2999   /* if we had saved some registers then unsave them */
3000   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3001     {
3002       if (accuse && !accPushed && options.useXstack)
3003         {
3004           /* xstack needs acc, but doesn't touch normal stack */
3005           emitcode ("push", "acc");
3006           accPushed = TRUE;
3007         }
3008       unsaveRegisters (ic);
3009     }
3010
3011 //  /* if register bank was saved then pop them */
3012 //  if (restoreBank)
3013 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3014
3015   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3016     {
3017       if (resultInF0)
3018           emitcode ("mov", "c,F0");
3019
3020       aopOp (IC_RESULT (ic), ic, FALSE);
3021       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3022       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3023     }
3024
3025   if (accPushed)
3026     emitcode ("pop", "acc");
3027 }
3028
3029 /*-----------------------------------------------------------------*/
3030 /* genPcall - generates a call by pointer statement                */
3031 /*-----------------------------------------------------------------*/
3032 static void
3033 genPcall (iCode * ic)
3034 {
3035   sym_link *dtype;
3036   sym_link *etype;
3037   symbol *rlbl = newiTempLabel (NULL);
3038 //  bool restoreBank=FALSE;
3039   bool swapBanks = FALSE;
3040   bool resultInF0 = FALSE;
3041
3042   D (emitcode (";", "genPcall"));
3043
3044   dtype = operandType (IC_LEFT (ic))->next;
3045   etype = getSpec(dtype);
3046   /* if caller saves & we have not saved then */
3047   if (!ic->regsSaved)
3048     saveRegisters (ic);
3049
3050   /* if we are calling a not _naked function that is not using
3051      the same register bank then we need to save the
3052      destination registers on the stack */
3053   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3054       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3055       !IFFUNC_ISISR (dtype))
3056     {
3057 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3058 //    restoreBank=TRUE;
3059       swapBanks = TRUE;
3060       // need caution message to user here
3061     }
3062
3063   if (IS_LITERAL (etype))
3064     {
3065       /* if send set is not empty then assign */
3066       if (_G.sendSet)
3067         {
3068           genSend(reverseSet(_G.sendSet));
3069           _G.sendSet = NULL;
3070         }
3071
3072       if (swapBanks)
3073         {
3074           emitcode ("mov", "psw,#0x%02x",
3075            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3076         }
3077
3078       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3079         {
3080           if (IFFUNC_CALLEESAVES (dtype))
3081             {
3082               werror (E_BANKED_WITH_CALLEESAVES);
3083             }
3084           else
3085             {
3086               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3087
3088               emitcode ("mov", "r0,#%s", l);
3089               emitcode ("mov", "r1,#(%s >> 8)", l);
3090               emitcode ("mov", "r2,#(%s >> 16)", l);
3091               emitcode ("lcall", "__sdcc_banked_call");
3092             }
3093         }
3094       else
3095         {
3096           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3097         }
3098     }
3099   else
3100     {
3101       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3102         {
3103           if (IFFUNC_CALLEESAVES (dtype))
3104             {
3105               werror (E_BANKED_WITH_CALLEESAVES);
3106             }
3107           else
3108             {
3109               aopOp (IC_LEFT (ic), ic, FALSE);
3110
3111               if (!swapBanks)
3112                 {
3113                   /* what if aopGet needs r0 or r1 ??? */
3114                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3115                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3116                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3117                 }
3118               else
3119                 {
3120                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3121                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3122                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3123                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3124                 }
3125
3126               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3127
3128               /* if send set is not empty then assign */
3129               if (_G.sendSet)
3130                 {
3131                   genSend(reverseSet(_G.sendSet));
3132                   _G.sendSet = NULL;
3133                 }
3134
3135               if (swapBanks)
3136                 {
3137                   emitcode ("mov", "psw,#0x%02x",
3138                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3139                 }
3140
3141               /* make the call */
3142               emitcode ("lcall", "__sdcc_banked_call");
3143             }
3144         }
3145       else if (_G.sendSet)
3146         {
3147           /* push the return address on to the stack */
3148           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3149           emitcode ("push", "acc");
3150           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3151           emitcode ("push", "acc");
3152
3153           /* now push the calling address */
3154           aopOp (IC_LEFT (ic), ic, FALSE);
3155
3156           pushSide (IC_LEFT (ic), FPTRSIZE);
3157
3158           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3159
3160           /* if send set is not empty the assign */
3161           if (_G.sendSet)
3162             {
3163               genSend(reverseSet(_G.sendSet));
3164               _G.sendSet = NULL;
3165             }
3166
3167           if (swapBanks)
3168             {
3169               emitcode ("mov", "psw,#0x%02x",
3170                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3171             }
3172
3173           /* make the call */
3174           emitcode ("ret", "");
3175           emitLabel (rlbl);
3176         }
3177       else /* the send set is empty */
3178         {
3179           char *l;
3180           /* now get the calling address into dptr */
3181           aopOp (IC_LEFT (ic), ic, FALSE);
3182
3183           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3184           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3185             {
3186               emitcode ("mov", "r0,%s", l);
3187               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3188               emitcode ("mov", "dph,%s", l);
3189               emitcode ("mov", "dpl,r0");
3190             }
3191           else
3192             {
3193               emitcode ("mov", "dpl,%s", l);
3194               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3195               emitcode ("mov", "dph,%s", l);
3196             }
3197
3198           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3199
3200           if (swapBanks)
3201             {
3202               emitcode ("mov", "psw,#0x%02x",
3203                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3204             }
3205
3206           /* make the call */
3207           emitcode ("lcall", "__sdcc_call_dptr");
3208         }
3209     }
3210   if (swapBanks)
3211     {
3212       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3213     }
3214
3215   /* if we need assign a result value */
3216   if ((IS_ITEMP (IC_RESULT (ic)) &&
3217        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3218        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3219         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3220       IS_TRUE_SYMOP (IC_RESULT (ic)))
3221     {
3222
3223       _G.accInUse++;
3224       aopOp (IC_RESULT (ic), ic, FALSE);
3225       _G.accInUse--;
3226
3227       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3228
3229       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3230     }
3231
3232   /* adjust the stack for parameters if required */
3233   if (ic->parmBytes)
3234     {
3235       int i;
3236       if (ic->parmBytes > 3)
3237         {
3238           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3239               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3240             {
3241               emitcode ("mov", "F0,c");
3242               resultInF0 = TRUE;
3243             }
3244
3245           emitcode ("mov", "a,%s", spname);
3246           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3247           emitcode ("mov", "%s,a", spname);
3248         }
3249       else
3250         for (i = 0; i < ic->parmBytes; i++)
3251           emitcode ("dec", "%s", spname);
3252     }
3253
3254 //  /* if register bank was saved then unsave them */
3255 //  if (restoreBank)
3256 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3257
3258   /* if we had saved some registers then unsave them */
3259   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3260     unsaveRegisters (ic);
3261
3262   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3263     {
3264       if (resultInF0)
3265           emitcode ("mov", "c,F0");
3266
3267       aopOp (IC_RESULT (ic), ic, FALSE);
3268       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3269       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3270     }
3271 }
3272
3273 /*-----------------------------------------------------------------*/
3274 /* resultRemat - result  is rematerializable                       */
3275 /*-----------------------------------------------------------------*/
3276 static int
3277 resultRemat (iCode * ic)
3278 {
3279   if (SKIP_IC (ic) || ic->op == IFX)
3280     return 0;
3281
3282   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3283     {
3284       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3285       if (sym->remat && !POINTER_SET (ic))
3286         return 1;
3287     }
3288
3289   return 0;
3290 }
3291
3292 /*-----------------------------------------------------------------*/
3293 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3294 /*-----------------------------------------------------------------*/
3295 static int
3296 regsCmp(void *p1, void *p2)
3297 {
3298   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3299 }
3300
3301 static bool
3302 inExcludeList (char *s)
3303 {
3304   const char *p = setFirstItem(options.excludeRegsSet);
3305
3306   if (p == NULL || STRCASECMP(p, "none") == 0)
3307     return FALSE;
3308
3309
3310   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3311 }
3312
3313 /*-----------------------------------------------------------------*/
3314 /* genFunction - generated code for function entry                 */
3315 /*-----------------------------------------------------------------*/
3316 static void
3317 genFunction (iCode * ic)
3318 {
3319   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3320   sym_link *ftype;
3321   bool     switchedPSW = FALSE;
3322   int      calleesaves_saved_register = -1;
3323   int      stackAdjust = sym->stack;
3324   int      accIsFree = sym->recvSize < 4;
3325   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3326   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3327
3328   _G.nRegsSaved = 0;
3329   /* create the function header */
3330   emitcode (";", "-----------------------------------------");
3331   emitcode (";", " function %s", sym->name);
3332   emitcode (";", "-----------------------------------------");
3333
3334   emitcode ("", "%s:", sym->rname);
3335   lineCurr->isLabel = 1;
3336   ftype = operandType (IC_LEFT (ic));
3337   _G.currentFunc = sym;
3338
3339   if (IFFUNC_ISNAKED(ftype))
3340   {
3341       emitcode(";", "naked function: no prologue.");
3342       return;
3343   }
3344
3345   /* here we need to generate the equates for the
3346      register bank if required */
3347   if (FUNC_REGBANK (ftype) != rbank)
3348     {
3349       int i;
3350
3351       rbank = FUNC_REGBANK (ftype);
3352       for (i = 0; i < mcs51_nRegs; i++)
3353         {
3354           if (regs8051[i].type != REG_BIT)
3355             {
3356               if (strcmp (regs8051[i].base, "0") == 0)
3357                 emitcode ("", "%s = 0x%02x",
3358                           regs8051[i].dname,
3359                           8 * rbank + regs8051[i].offset);
3360               else
3361                 emitcode ("", "%s = %s + 0x%02x",
3362                           regs8051[i].dname,
3363                           regs8051[i].base,
3364                           8 * rbank + regs8051[i].offset);
3365             }
3366         }
3367     }
3368
3369   /* if this is an interrupt service routine then
3370      save acc, b, dpl, dph  */
3371   if (IFFUNC_ISISR (sym->type))
3372     {
3373       bitVect *rsavebits;
3374
3375       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3376       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3377         {
3378           emitcode ("push", "bits");
3379           BitBankUsed = 1;
3380         }
3381       freeBitVect (rsavebits);
3382
3383       if (!inExcludeList ("acc"))
3384         emitcode ("push", "acc");
3385       if (!inExcludeList ("b"))
3386         emitcode ("push", "b");
3387       if (!inExcludeList ("dpl"))
3388         emitcode ("push", "dpl");
3389       if (!inExcludeList ("dph"))
3390         emitcode ("push", "dph");
3391       /* if this isr has no bank i.e. is going to
3392          run with bank 0 , then we need to save more
3393          registers :-) */
3394       if (!FUNC_REGBANK (sym->type))
3395         {
3396           int i;
3397
3398           /* if this function does not call any other
3399              function then we can be economical and
3400              save only those registers that are used */
3401           if (!IFFUNC_HASFCALL(sym->type))
3402             {
3403               /* if any registers used */
3404               if (sym->regsUsed)
3405                 {
3406                   /* save the registers used */
3407                   for (i = 0; i < sym->regsUsed->size; i++)
3408                     {
3409                       if (bitVectBitValue (sym->regsUsed, i))
3410                         pushReg (i, TRUE);
3411                     }
3412                 }
3413             }
3414           else
3415             {
3416               /* this function has a function call. We cannot
3417                  determine register usage so we will have to push the
3418                  entire bank */
3419                 saveRBank (0, ic, FALSE);
3420                 if (options.parms_in_bank1) {
3421                     for (i=0; i < 8 ; i++ ) {
3422                         emitcode ("push","%s",rb1regs[i]);
3423                     }
3424                 }
3425             }
3426         }
3427       else
3428         {
3429             /* This ISR uses a non-zero bank.
3430              *
3431              * We assume that the bank is available for our
3432              * exclusive use.
3433              *
3434              * However, if this ISR calls a function which uses some
3435              * other bank, we must save that bank entirely.
3436              */
3437             unsigned long banksToSave = 0;
3438
3439             if (IFFUNC_HASFCALL(sym->type))
3440             {
3441
3442 #define MAX_REGISTER_BANKS 4
3443
3444                 iCode *i;
3445                 int ix;
3446
3447                 for (i = ic; i; i = i->next)
3448                 {
3449                     if (i->op == ENDFUNCTION)
3450                     {
3451                         /* we got to the end OK. */
3452                         break;
3453                     }
3454
3455                     if (i->op == CALL)
3456                     {
3457                         sym_link *dtype;
3458
3459                         dtype = operandType (IC_LEFT(i));
3460                         if (dtype
3461                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3462                         {
3463                              /* Mark this bank for saving. */
3464                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3465                              {
3466                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3467                              }
3468                              else
3469                              {
3470                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3471                              }
3472
3473                              /* And note that we don't need to do it in
3474                               * genCall.
3475                               */
3476                              i->bankSaved = 1;
3477                         }
3478                     }
3479                     if (i->op == PCALL)
3480                     {
3481                         /* This is a mess; we have no idea what
3482                          * register bank the called function might
3483                          * use.
3484                          *
3485                          * The only thing I can think of to do is
3486                          * throw a warning and hope.
3487                          */
3488                         werror(W_FUNCPTR_IN_USING_ISR);
3489                     }
3490                 }
3491
3492                 if (banksToSave && options.useXstack)
3493                 {
3494                     /* Since we aren't passing it an ic,
3495                      * saveRBank will assume r0 is available to abuse.
3496                      *
3497                      * So switch to our (trashable) bank now, so
3498                      * the caller's R0 isn't trashed.
3499                      */
3500                     emitcode ("push", "psw");
3501                     emitcode ("mov", "psw,#0x%02x",
3502                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3503                     switchedPSW = TRUE;
3504                 }
3505
3506                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3507                 {
3508                      if (banksToSave & (1 << ix))
3509                      {
3510                          saveRBank(ix, NULL, FALSE);
3511                      }
3512                 }
3513             }
3514             // TODO: this needs a closer look
3515             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3516         }
3517
3518       /* Set the register bank to the desired value if nothing else */
3519       /* has done so yet. */
3520       if (!switchedPSW)
3521         {
3522           emitcode ("push", "psw");
3523           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3524         }
3525     }
3526   else
3527     {
3528       /* This is a non-ISR function. The caller has already switched register */
3529       /* banks, if necessary, so just handle the callee-saves option. */
3530
3531       /* if callee-save to be used for this function
3532          then save the registers being used in this function */
3533       if (IFFUNC_CALLEESAVES(sym->type))
3534         {
3535           int i;
3536
3537           /* if any registers used */
3538           if (sym->regsUsed)
3539             {
3540               bool bits_pushed = FALSE;
3541               /* save the registers used */
3542               for (i = 0; i < sym->regsUsed->size; i++)
3543                 {
3544                   if (bitVectBitValue (sym->regsUsed, i))
3545                     {
3546                       /* remember one saved register for later usage */
3547                       if (calleesaves_saved_register < 0)
3548                         calleesaves_saved_register = i;
3549                       bits_pushed = pushReg (i, bits_pushed);
3550                       _G.nRegsSaved++;
3551                     }
3552                 }
3553             }
3554         }
3555     }
3556
3557   if (fReentrant)
3558     {
3559       if (options.useXstack)
3560         {
3561           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3562             {
3563               emitcode ("mov", "r0,%s", spname);
3564               emitcode ("inc", "%s", spname);
3565               emitcode ("xch", "a,_bpx");
3566               emitcode ("movx", "@r0,a");
3567               emitcode ("inc", "r0");
3568               emitcode ("mov", "a,r0");
3569               emitcode ("xch", "a,_bpx");
3570             }
3571           if (sym->stack)
3572             {
3573               emitcode ("push", "_bp");     /* save the callers stack  */
3574               emitcode ("mov", "_bp,sp");
3575             }
3576         }
3577       else
3578         {
3579           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3580             {
3581               /* set up the stack */
3582               emitcode ("push", "_bp");     /* save the callers stack  */
3583               emitcode ("mov", "_bp,sp");
3584             }
3585         }
3586     }
3587
3588   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3589   /* before setting up the stack frame completely. */
3590   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3591     {
3592       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3593
3594       if (rsym->isitmp)
3595         {
3596           if (rsym && rsym->regType == REG_CND)
3597             rsym = NULL;
3598           if (rsym && (rsym->accuse || rsym->ruonly))
3599             rsym = NULL;
3600           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3601             rsym = rsym->usl.spillLoc;
3602         }
3603
3604       /* If the RECEIVE operand immediately spills to the first entry on the */
3605       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3606       /* rather than the usual @r0/r1 machinations. */
3607       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3608         {
3609           int ofs;
3610
3611           _G.current_iCode = ric;
3612           D(emitcode (";", "genReceive"));
3613           for (ofs=0; ofs < sym->recvSize; ofs++)
3614             {
3615               if (!strcmp (fReturn[ofs], "a"))
3616                 emitcode ("push", "acc");
3617               else
3618                 emitcode ("push", fReturn[ofs]);
3619             }
3620           stackAdjust -= sym->recvSize;
3621           if (stackAdjust<0)
3622             {
3623               assert (stackAdjust>=0);
3624               stackAdjust = 0;
3625             }
3626           _G.current_iCode = ic;
3627           ric->generated = 1;
3628           accIsFree = 1;
3629         }
3630       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3631       /* to free up the accumulator. */
3632       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3633         {
3634           int ofs;
3635
3636           _G.current_iCode = ric;
3637           D(emitcode (";", "genReceive"));
3638           for (ofs=0; ofs < sym->recvSize; ofs++)
3639             {
3640               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3641             }
3642           _G.current_iCode = ic;
3643           ric->generated = 1;
3644           accIsFree = 1;
3645         }
3646     }
3647
3648   /* adjust the stack for the function */
3649   if (stackAdjust)
3650     {
3651       int i = stackAdjust;
3652       if (i > 256)
3653         werror (W_STACK_OVERFLOW, sym->name);
3654
3655       if (i > 3 && accIsFree)
3656         {
3657           emitcode ("mov", "a,sp");
3658           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3659           emitcode ("mov", "sp,a");
3660         }
3661       else if (i > 5)
3662         {
3663           /* The accumulator is not free, so we will need another register */
3664           /* to clobber. No need to worry about a possible conflict with */
3665           /* the above early RECEIVE optimizations since they would have */
3666           /* freed the accumulator if they were generated. */
3667
3668           if (IFFUNC_CALLEESAVES(sym->type))
3669             {
3670               /* if it's a callee-saves function we need a saved register */
3671               if (calleesaves_saved_register >= 0)
3672                 {
3673                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3674                   emitcode ("mov", "a,sp");
3675                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3676                   emitcode ("mov", "sp,a");
3677                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3678                 }
3679               else
3680                 /* do it the hard way */
3681                 while (i--)
3682                   emitcode ("inc", "sp");
3683             }
3684           else
3685             {
3686               /* not callee-saves, we can clobber r0 */
3687               emitcode ("mov", "r0,a");
3688               emitcode ("mov", "a,sp");
3689               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3690               emitcode ("mov", "sp,a");
3691               emitcode ("mov", "a,r0");
3692             }
3693         }
3694       else
3695         while (i--)
3696           emitcode ("inc", "sp");
3697     }
3698
3699   if (sym->xstack)
3700     {
3701       char i = ((char) sym->xstack & 0xff);
3702
3703       if (i > 3 && accIsFree)
3704         {
3705           emitcode ("mov", "a,_spx");
3706           emitcode ("add", "a,#0x%02x", i & 0xff);
3707           emitcode ("mov", "_spx,a");
3708         }
3709       else if (i > 5)
3710         {
3711           emitcode ("push", "acc");
3712           emitcode ("mov", "a,_spx");
3713           emitcode ("add", "a,#0x%02x", i & 0xff);
3714           emitcode ("mov", "_spx,a");
3715           emitcode ("pop", "acc");
3716         }
3717       else
3718         {
3719           while (i--)
3720             emitcode ("inc", "_spx");
3721         }
3722     }
3723
3724   /* if critical function then turn interrupts off */
3725   if (IFFUNC_ISCRITICAL (ftype))
3726     {
3727       symbol *tlbl = newiTempLabel (NULL);
3728       emitcode ("setb", "c");
3729       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3730       emitcode ("clr", "c");
3731       emitLabel (tlbl);
3732       emitcode ("push", "psw"); /* save old ea via c in psw */
3733     }
3734 }
3735
3736 /*-----------------------------------------------------------------*/
3737 /* genEndFunction - generates epilogue for functions               */
3738 /*-----------------------------------------------------------------*/
3739 static void
3740 genEndFunction (iCode * ic)
3741 {
3742   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3743   lineNode *lnp = lineCurr;
3744   bitVect  *regsUsed;
3745   bitVect  *regsUsedPrologue;
3746   bitVect  *regsUnneeded;
3747   int      idx;
3748
3749   _G.currentFunc = NULL;
3750   if (IFFUNC_ISNAKED(sym->type))
3751   {
3752       emitcode(";", "naked function: no epilogue.");
3753       if (options.debug && currFunc)
3754         debugFile->writeEndFunction (currFunc, ic, 0);
3755       return;
3756   }
3757
3758   if (IFFUNC_ISCRITICAL (sym->type))
3759     {
3760       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3761         {
3762           emitcode ("rlc", "a");   /* save c in a */
3763           emitcode ("pop", "psw"); /* restore ea via c in psw */
3764           emitcode ("mov", "ea,c");
3765           emitcode ("rrc", "a");   /* restore c from a */
3766         }
3767       else
3768         {
3769           emitcode ("pop", "psw"); /* restore ea via c in psw */
3770           emitcode ("mov", "ea,c");
3771         }
3772     }
3773
3774   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3775     {
3776       if (options.useXstack)
3777         {
3778           if (sym->stack)
3779             {
3780               emitcode ("mov", "sp,_bp");
3781               emitcode ("pop", "_bp");
3782             }
3783           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3784             {
3785               emitcode ("xch", "a,_bpx");
3786               emitcode ("mov", "r0,a");
3787               emitcode ("dec", "r0");
3788               emitcode ("movx", "a,@r0");
3789               emitcode ("xch", "a,_bpx");
3790               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3791             }
3792         }
3793       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3794         {
3795           if (sym->stack)
3796             emitcode ("mov", "sp,_bp");
3797           emitcode ("pop", "_bp");
3798         }
3799     }
3800
3801   /* restore the register bank  */
3802   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3803   {
3804     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3805      || !options.useXstack)
3806     {
3807         /* Special case of ISR using non-zero bank with useXstack
3808          * is handled below.
3809          */
3810         emitcode ("pop", "psw");
3811     }
3812   }
3813
3814   if (IFFUNC_ISISR (sym->type))
3815     {
3816       bitVect *rsavebits;
3817
3818       /* now we need to restore the registers */
3819       /* if this isr has no bank i.e. is going to
3820          run with bank 0 , then we need to save more
3821          registers :-) */
3822       if (!FUNC_REGBANK (sym->type))
3823         {
3824           int i;
3825           /* if this function does not call any other
3826              function then we can be economical and
3827              save only those registers that are used */
3828           if (!IFFUNC_HASFCALL(sym->type))
3829             {
3830               /* if any registers used */
3831               if (sym->regsUsed)
3832                 {
3833                   /* save the registers used */
3834                   for (i = sym->regsUsed->size; i >= 0; i--)
3835                     {
3836                       if (bitVectBitValue (sym->regsUsed, i))
3837                         popReg (i, TRUE);
3838                     }
3839                 }
3840             }
3841           else
3842             {
3843               if (options.parms_in_bank1) {
3844                   for (i = 7 ; i >= 0 ; i-- ) {
3845                       emitcode ("pop","%s",rb1regs[i]);
3846                   }
3847               }
3848               /* this function has a function call. We cannot
3849                  determine register usage so we will have to pop the
3850                  entire bank */
3851               unsaveRBank (0, ic, FALSE);
3852             }
3853         }
3854         else
3855         {
3856             /* This ISR uses a non-zero bank.
3857              *
3858              * Restore any register banks saved by genFunction
3859              * in reverse order.
3860              */
3861             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3862             int ix;
3863
3864             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3865             {
3866                 if (savedBanks & (1 << ix))
3867                 {
3868                     unsaveRBank(ix, NULL, FALSE);
3869                 }
3870             }
3871
3872             if (options.useXstack)
3873             {
3874                 /* Restore bank AFTER calling unsaveRBank,
3875                  * since it can trash r0.
3876                  */
3877                 emitcode ("pop", "psw");
3878             }
3879         }
3880
3881       if (!inExcludeList ("dph"))
3882         emitcode ("pop", "dph");
3883       if (!inExcludeList ("dpl"))
3884         emitcode ("pop", "dpl");
3885       if (!inExcludeList ("b"))
3886         emitcode ("pop", "b");
3887       if (!inExcludeList ("acc"))
3888         emitcode ("pop", "acc");
3889
3890       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3891       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3892         emitcode ("pop", "bits");
3893       freeBitVect (rsavebits);
3894
3895       /* if debug then send end of function */
3896       if (options.debug && currFunc)
3897         {
3898           debugFile->writeEndFunction (currFunc, ic, 1);
3899         }
3900
3901       emitcode ("reti", "");
3902     }
3903   else
3904     {
3905       if (IFFUNC_CALLEESAVES(sym->type))
3906         {
3907           int i;
3908
3909           /* if any registers used */
3910           if (sym->regsUsed)
3911             {
3912               /* save the registers used */
3913               for (i = sym->regsUsed->size; i >= 0; i--)
3914                 {
3915                   if (bitVectBitValue (sym->regsUsed, i) ||
3916                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3917                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3918                 }
3919             }
3920           else if (mcs51_ptrRegReq)
3921             {
3922               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3923               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3924             }
3925
3926         }
3927
3928       /* if debug then send end of function */
3929       if (options.debug && currFunc)
3930         {
3931           debugFile->writeEndFunction (currFunc, ic, 1);
3932         }
3933
3934       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3935         {
3936           emitcode ("ljmp", "__sdcc_banked_ret");
3937         }
3938       else
3939         {
3940           emitcode ("ret", "");
3941         }
3942     }
3943
3944   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3945     return;
3946
3947   /* If this was an interrupt handler using bank 0 that called another */
3948   /* function, then all registers must be saved; nothing to optimized. */
3949   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3950       && !FUNC_REGBANK(sym->type))
3951     return;
3952
3953   /* There are no push/pops to optimize if not callee-saves or ISR */
3954   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3955     return;
3956
3957   /* If there were stack parameters, we cannot optimize without also    */
3958   /* fixing all of the stack offsets; this is too dificult to consider. */
3959   if (FUNC_HASSTACKPARM(sym->type))
3960     return;
3961
3962   /* Compute the registers actually used */
3963   regsUsed = newBitVect (mcs51_nRegs);
3964   regsUsedPrologue = newBitVect (mcs51_nRegs);
3965   while (lnp)
3966     {
3967       if (lnp->ic && lnp->ic->op == FUNCTION)
3968         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3969       else
3970         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3971
3972       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3973           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3974         break;
3975       if (!lnp->prev)
3976         break;
3977       lnp = lnp->prev;
3978     }
3979
3980   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3981       && !bitVectBitValue (regsUsed, CND_IDX))
3982     {
3983       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3984       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3985           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3986         bitVectUnSetBit (regsUsed, CND_IDX);
3987     }
3988   else
3989     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3990
3991   /* If this was an interrupt handler that called another function */
3992   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3993   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3994     {
3995       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3997       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3998       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3999       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4000     }
4001
4002   /* Remove the unneeded push/pops */
4003   regsUnneeded = newBitVect (mcs51_nRegs);
4004   while (lnp)
4005     {
4006       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4007         {
4008           if (!strncmp(lnp->line, "push", 4))
4009             {
4010               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4011               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4012                 {
4013                   connectLine (lnp->prev, lnp->next);
4014                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4015                 }
4016             }
4017           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4018             {
4019               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4020               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4021                 {
4022                   connectLine (lnp->prev, lnp->next);
4023                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4024                 }
4025             }
4026         }
4027       lnp = lnp->next;
4028     }
4029
4030   for (idx = 0; idx < regsUnneeded->size; idx++)
4031     if (bitVectBitValue (regsUnneeded, idx))
4032       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4033
4034   freeBitVect (regsUnneeded);
4035   freeBitVect (regsUsed);
4036   freeBitVect (regsUsedPrologue);
4037 }
4038
4039 /*-----------------------------------------------------------------*/
4040 /* genRet - generate code for return statement                     */
4041 /*-----------------------------------------------------------------*/
4042 static void
4043 genRet (iCode * ic)
4044 {
4045   int size, offset = 0, pushed = 0;
4046
4047   D (emitcode (";", "genRet"));
4048
4049   /* if we have no return value then
4050      just generate the "ret" */
4051   if (!IC_LEFT (ic))
4052     goto jumpret;
4053
4054   /* we have something to return then
4055      move the return value into place */
4056   aopOp (IC_LEFT (ic), ic, FALSE);
4057   size = AOP_SIZE (IC_LEFT (ic));
4058
4059   if (IS_BIT(_G.currentFunc->etype))
4060     {
4061       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4062         toCarry (IC_LEFT (ic));
4063     }
4064   else
4065     {
4066       while (size--)
4067         {
4068           char *l;
4069           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4070             {
4071               /* #NOCHANGE */
4072               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4073               emitcode ("push", "%s", l);
4074               pushed++;
4075             }
4076           else
4077             {
4078               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4079               if (strcmp (fReturn[offset], l))
4080                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4081             }
4082         }
4083
4084       while (pushed)
4085         {
4086           pushed--;
4087           if (strcmp (fReturn[pushed], "a"))
4088             emitcode ("pop", fReturn[pushed]);
4089           else
4090             emitcode ("pop", "acc");
4091         }
4092     }
4093   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4094
4095 jumpret:
4096   /* generate a jump to the return label
4097      if the next is not the return statement */
4098   if (!(ic->next && ic->next->op == LABEL &&
4099         IC_LABEL (ic->next) == returnLabel))
4100
4101     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4102
4103 }
4104
4105 /*-----------------------------------------------------------------*/
4106 /* genLabel - generates a label                                    */
4107 /*-----------------------------------------------------------------*/
4108 static void
4109 genLabel (iCode * ic)
4110 {
4111   /* special case never generate */
4112   if (IC_LABEL (ic) == entryLabel)
4113     return;
4114
4115   emitLabel (IC_LABEL (ic));
4116 }
4117
4118 /*-----------------------------------------------------------------*/
4119 /* genGoto - generates a ljmp                                      */
4120 /*-----------------------------------------------------------------*/
4121 static void
4122 genGoto (iCode * ic)
4123 {
4124   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4125 }
4126
4127 /*-----------------------------------------------------------------*/
4128 /* findLabelBackwards: walks back through the iCode chain looking  */
4129 /* for the given label. Returns number of iCode instructions     */
4130 /* between that label and given ic.          */
4131 /* Returns zero if label not found.          */
4132 /*-----------------------------------------------------------------*/
4133 static int
4134 findLabelBackwards (iCode * ic, int key)
4135 {
4136   int count = 0;
4137
4138   while (ic->prev)
4139     {
4140       ic = ic->prev;
4141       count++;
4142
4143       /* If we have any pushes or pops, we cannot predict the distance.
4144          I don't like this at all, this should be dealt with in the
4145          back-end */
4146       if (ic->op == IPUSH || ic->op == IPOP) {
4147         return 0;
4148       }
4149
4150       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4151         {
4152           return count;
4153         }
4154     }
4155
4156   return 0;
4157 }
4158
4159 /*-----------------------------------------------------------------*/
4160 /* genPlusIncr :- does addition with increment if possible         */
4161 /*-----------------------------------------------------------------*/
4162 static bool
4163 genPlusIncr (iCode * ic)
4164 {
4165   unsigned int icount;
4166   unsigned int size = getDataSize (IC_RESULT (ic));
4167
4168   /* will try to generate an increment */
4169   /* if the right side is not a literal
4170      we cannot */
4171   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4172     return FALSE;
4173
4174   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4175
4176   D(emitcode (";","genPlusIncr"));
4177
4178   /* if increment >=16 bits in register or direct space */
4179   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4180         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4181         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4182       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4183       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4184       (size > 1) &&
4185       (icount == 1))
4186     {
4187       symbol *tlbl;
4188       int emitTlbl;
4189       int labelRange;
4190
4191       /* If the next instruction is a goto and the goto target
4192        * is < 10 instructions previous to this, we can generate
4193        * jumps straight to that target.
4194        */
4195       if (ic->next && ic->next->op == GOTO
4196           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4197           && labelRange <= 10)
4198         {
4199           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4200           tlbl = IC_LABEL (ic->next);
4201           emitTlbl = 0;
4202         }
4203       else
4204         {
4205           tlbl = newiTempLabel (NULL);
4206           emitTlbl = 1;
4207         }
4208       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4209       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4210           IS_AOP_PREG (IC_RESULT (ic)))
4211         emitcode ("cjne", "%s,#0x00,%05d$",
4212                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4213                   tlbl->key + 100);
4214       else
4215         {
4216           emitcode ("clr", "a");
4217           emitcode ("cjne", "a,%s,%05d$",
4218                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4219                     tlbl->key + 100);
4220         }
4221
4222       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4223       if (size > 2)
4224         {
4225           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4226               IS_AOP_PREG (IC_RESULT (ic)))
4227             emitcode ("cjne", "%s,#0x00,%05d$",
4228                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4229                       tlbl->key + 100);
4230           else
4231             emitcode ("cjne", "a,%s,%05d$",
4232                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4233                       tlbl->key + 100);
4234
4235           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4236         }
4237       if (size > 3)
4238         {
4239           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4240               IS_AOP_PREG (IC_RESULT (ic)))
4241             emitcode ("cjne", "%s,#0x00,%05d$",
4242                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4243                       tlbl->key + 100);
4244           else
4245             {
4246               emitcode ("cjne", "a,%s,%05d$",
4247                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4248                         tlbl->key + 100);
4249             }
4250           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4251         }
4252
4253       if (emitTlbl)
4254         {
4255           emitLabel (tlbl);
4256         }
4257       return TRUE;
4258     }
4259
4260   /* if result is dptr */
4261   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4262       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4263       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4264       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4265     {
4266       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4267         return FALSE;
4268
4269       if (icount > 9)
4270         return FALSE;
4271
4272       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4273         return FALSE;
4274
4275       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4276       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4277       while (icount--)
4278         emitcode ("inc", "dptr");
4279
4280       return TRUE;
4281     }
4282
4283   /* if the literal value of the right hand side
4284      is greater than 4 then it is not worth it */
4285   if (icount > 4)
4286     return FALSE;
4287
4288   /* if the sizes are greater than 1 then we cannot */
4289   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4290       AOP_SIZE (IC_LEFT (ic)) > 1)
4291     return FALSE;
4292
4293   /* we can if the aops of the left & result match or
4294      if they are in registers and the registers are the
4295      same */
4296   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4297     {
4298       if (icount > 3)
4299         {
4300           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4301           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4302           aopPut (IC_RESULT (ic), "a", 0);
4303         }
4304       else
4305         {
4306           while (icount--)
4307             {
4308               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4309             }
4310         }
4311
4312       return TRUE;
4313     }
4314
4315   if (icount == 1)
4316     {
4317       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4318       emitcode ("inc", "a");
4319       aopPut (IC_RESULT (ic), "a", 0);
4320       return TRUE;
4321     }
4322
4323   return FALSE;
4324 }
4325
4326 /*-----------------------------------------------------------------*/
4327 /* outBitAcc - output a bit in acc                                 */
4328 /*-----------------------------------------------------------------*/
4329 static void
4330 outBitAcc (operand * result)
4331 {
4332   symbol *tlbl = newiTempLabel (NULL);
4333   /* if the result is a bit */
4334   if (AOP_TYPE (result) == AOP_CRY)
4335     {
4336       aopPut (result, "a", 0);
4337     }
4338   else
4339     {
4340       emitcode ("jz", "%05d$", tlbl->key + 100);
4341       emitcode ("mov", "a,%s", one);
4342       emitLabel (tlbl);
4343       outAcc (result);
4344     }
4345 }
4346
4347 /*-----------------------------------------------------------------*/
4348 /* genPlusBits - generates code for addition of two bits           */
4349 /*-----------------------------------------------------------------*/
4350 static void
4351 genPlusBits (iCode * ic)
4352 {
4353   D (emitcode (";", "genPlusBits"));
4354
4355   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4356   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4357     {
4358       symbol *lbl = newiTempLabel (NULL);
4359       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4360       emitcode ("cpl", "c");
4361       emitLabel (lbl);
4362       outBitC (IC_RESULT (ic));
4363     }
4364   else
4365     {
4366       emitcode ("clr", "a");
4367       emitcode ("rlc", "a");
4368       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4369       emitcode ("addc", "a,%s", zero);
4370       outAcc (IC_RESULT (ic));
4371     }
4372 }
4373
4374 #if 0
4375 /* This is the original version of this code.
4376
4377  * This is being kept around for reference,
4378  * because I am not entirely sure I got it right...
4379  */
4380 static void
4381 adjustArithmeticResult (iCode * ic)
4382 {
4383   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4384       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4385       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4386     aopPut (IC_RESULT (ic),
4387             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4388             2);
4389
4390   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4391       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4392       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4393     aopPut (IC_RESULT (ic),
4394             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4395             2);
4396
4397   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4398       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4399       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4400       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4401       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4402     {
4403       char buffer[5];
4404       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4405       aopPut (IC_RESULT (ic), buffer, 2);
4406     }
4407 }
4408 #else
4409 /* This is the pure and virtuous version of this code.
4410  * I'm pretty certain it's right, but not enough to toss the old
4411  * code just yet...
4412  */
4413 static void
4414 adjustArithmeticResult (iCode * ic)
4415 {
4416   if (opIsGptr (IC_RESULT (ic)) &&
4417       opIsGptr (IC_LEFT (ic)) &&
4418       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4419     {
4420       aopPut (IC_RESULT (ic),
4421               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4422               GPTRSIZE - 1);
4423     }
4424
4425   if (opIsGptr (IC_RESULT (ic)) &&
4426       opIsGptr (IC_RIGHT (ic)) &&
4427       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4428     {
4429       aopPut (IC_RESULT (ic),
4430               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4431               GPTRSIZE - 1);
4432     }
4433
4434   if (opIsGptr (IC_RESULT (ic)) &&
4435       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4436       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4437       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4438       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4439     {
4440       char buffer[5];
4441       SNPRINTF (buffer, sizeof(buffer),
4442                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4443       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4444     }
4445 }
4446 #endif
4447
4448 /*-----------------------------------------------------------------*/
4449 /* genPlus - generates code for addition                           */
4450 /*-----------------------------------------------------------------*/
4451 static void
4452 genPlus (iCode * ic)
4453 {
4454   int size, offset = 0;
4455   int skip_bytes = 0;
4456   char *add = "add";
4457   bool swappedLR = FALSE;
4458   operand *leftOp, *rightOp;
4459   operand * op;
4460
4461   D (emitcode (";", "genPlus"));
4462
4463   /* special cases :- */
4464
4465   aopOp (IC_LEFT (ic), ic, FALSE);
4466   aopOp (IC_RIGHT (ic), ic, FALSE);
4467   aopOp (IC_RESULT (ic), ic, TRUE);
4468
4469   /* if literal, literal on the right or
4470      if left requires ACC or right is already
4471      in ACC */
4472   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4473       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4474       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4475     {
4476       operand *t = IC_RIGHT (ic);
4477       IC_RIGHT (ic) = IC_LEFT (ic);
4478       IC_LEFT (ic) = t;
4479       swappedLR = TRUE;
4480     }
4481
4482   /* if both left & right are in bit
4483      space */
4484   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4485       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4486     {
4487       genPlusBits (ic);
4488       goto release;
4489     }
4490
4491   /* if left in bit space & right literal */
4492   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4493       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4494     {
4495       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4496       /* if result in bit space */
4497       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4498         {
4499           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4500             emitcode ("cpl", "c");
4501           outBitC (IC_RESULT (ic));
4502         }
4503       else
4504         {
4505           size = getDataSize (IC_RESULT (ic));
4506           while (size--)
4507             {
4508               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4509               emitcode ("addc", "a,%s", zero);
4510               aopPut (IC_RESULT (ic), "a", offset++);
4511             }
4512         }
4513       goto release;
4514     }
4515
4516   /* if I can do an increment instead
4517      of add then GOOD for ME */
4518   if (genPlusIncr (ic) == TRUE)
4519     goto release;
4520
4521   size = getDataSize (IC_RESULT (ic));
4522   leftOp = IC_LEFT(ic);
4523   rightOp = IC_RIGHT(ic);
4524   op = IC_LEFT(ic);
4525
4526   /* if this is an add for an array access
4527      at a 256 byte boundary */
4528   if ( 2 == size
4529        && AOP_TYPE (op) == AOP_IMMD
4530        && IS_SYMOP (op)
4531        && IS_SPEC (OP_SYM_ETYPE (op))
4532        && SPEC_ABSA (OP_SYM_ETYPE (op))
4533        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4534      )
4535     {
4536       D(emitcode (";", "genPlus aligned array"));
4537       aopPut (IC_RESULT (ic),
4538               aopGet (rightOp, 0, FALSE, FALSE),
4539               0);
4540
4541       if( 1 == getDataSize (IC_RIGHT (ic)) )
4542         {
4543           aopPut (IC_RESULT (ic),
4544                   aopGet (leftOp, 1, FALSE, FALSE),
4545                   1);
4546         }
4547       else
4548         {
4549           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4550           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4551           aopPut (IC_RESULT (ic), "a", 1);
4552         }
4553       goto release;
4554     }
4555
4556   /* if the lower bytes of a literal are zero skip the addition */
4557   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4558     {
4559        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4560               (skip_bytes+1 < size))
4561          {
4562            skip_bytes++;
4563          }
4564        if (skip_bytes)
4565          D(emitcode (";", "genPlus shortcut"));
4566     }
4567
4568   while (size--)
4569     {
4570       if( offset >= skip_bytes )
4571         {
4572           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4573             {
4574               bool pushedB;
4575               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4576               pushedB = pushB ();
4577               emitcode("xch", "a,b");
4578               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4579               emitcode (add, "a,b");
4580               popB (pushedB);
4581             }
4582           else if (aopGetUsesAcc (leftOp, offset))
4583             {
4584               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4585               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4586             }
4587           else
4588             {
4589               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4590               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4591             }
4592           aopPut (IC_RESULT (ic), "a", offset);
4593           add = "addc";  /* further adds must propagate carry */
4594         }
4595       else
4596         {
4597           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4598               isOperandVolatile (IC_RESULT (ic), FALSE))
4599             {
4600               /* just move */
4601               aopPut (IC_RESULT (ic),
4602                       aopGet (leftOp, offset, FALSE, FALSE),
4603                       offset);
4604             }
4605         }
4606       offset++;
4607     }
4608
4609   adjustArithmeticResult (ic);
4610
4611 release:
4612   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4613   if (!swappedLR)
4614     {
4615       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4616       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4617     }
4618   else
4619     {
4620       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4621       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4622     }
4623 }
4624
4625 /*-----------------------------------------------------------------*/
4626 /* genMinusDec :- does subtraction with decrement if possible      */
4627 /*-----------------------------------------------------------------*/
4628 static bool
4629 genMinusDec (iCode * ic)
4630 {
4631   unsigned int icount;
4632   unsigned int size = getDataSize (IC_RESULT (ic));
4633
4634   /* will try to generate an increment */
4635   /* if the right side is not a literal
4636      we cannot */
4637   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4638     return FALSE;
4639
4640   /* if the literal value of the right hand side
4641      is greater than 4 then it is not worth it */
4642   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4643     return FALSE;
4644
4645   D (emitcode (";", "genMinusDec"));
4646
4647   /* if decrement >=16 bits in register or direct space */
4648   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4649         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4650         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4651       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4652       (size > 1) &&
4653       (icount == 1))
4654     {
4655       symbol *tlbl;
4656       int emitTlbl;
4657       int labelRange;
4658
4659       /* If the next instruction is a goto and the goto target
4660        * is <= 10 instructions previous to this, we can generate
4661        * jumps straight to that target.
4662        */
4663       if (ic->next && ic->next->op == GOTO
4664           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4665           && labelRange <= 10)
4666         {
4667           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4668           tlbl = IC_LABEL (ic->next);
4669           emitTlbl = 0;
4670         }
4671       else
4672         {
4673           tlbl = newiTempLabel (NULL);
4674           emitTlbl = 1;
4675         }
4676
4677       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4678       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4679           IS_AOP_PREG (IC_RESULT (ic)))
4680         emitcode ("cjne", "%s,#0xff,%05d$"
4681                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4682                   ,tlbl->key + 100);
4683       else
4684         {
4685           emitcode ("mov", "a,#0xff");
4686           emitcode ("cjne", "a,%s,%05d$"
4687                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4688                     ,tlbl->key + 100);
4689         }
4690       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4691       if (size > 2)
4692         {
4693           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4694               IS_AOP_PREG (IC_RESULT (ic)))
4695             emitcode ("cjne", "%s,#0xff,%05d$"
4696                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4697                       ,tlbl->key + 100);
4698           else
4699             {
4700               emitcode ("cjne", "a,%s,%05d$"
4701                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4702                         ,tlbl->key + 100);
4703             }
4704           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4705         }
4706       if (size > 3)
4707         {
4708           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4709               IS_AOP_PREG (IC_RESULT (ic)))
4710             emitcode ("cjne", "%s,#0xff,%05d$"
4711                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4712                       ,tlbl->key + 100);
4713           else
4714             {
4715               emitcode ("cjne", "a,%s,%05d$"
4716                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4717                         ,tlbl->key + 100);
4718             }
4719           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4720         }
4721       if (emitTlbl)
4722         {
4723           emitLabel (tlbl);
4724         }
4725       return TRUE;
4726     }
4727
4728   /* if the sizes are greater than 1 then we cannot */
4729   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4730       AOP_SIZE (IC_LEFT (ic)) > 1)
4731     return FALSE;
4732
4733   /* we can if the aops of the left & result match or
4734      if they are in registers and the registers are the
4735      same */
4736   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4737     {
4738       char *l;
4739
4740       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4741         {
4742           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4743           l = "a";
4744         }
4745       else
4746         {
4747           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4748         }
4749
4750       while (icount--)
4751         {
4752           emitcode ("dec", "%s", l);
4753         }
4754
4755       if (AOP_NEEDSACC (IC_RESULT (ic)))
4756         aopPut (IC_RESULT (ic), "a", 0);
4757
4758       return TRUE;
4759     }
4760
4761   if (icount == 1)
4762     {
4763       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4764       emitcode ("dec", "a");
4765       aopPut (IC_RESULT (ic), "a", 0);
4766       return TRUE;
4767     }
4768
4769   return FALSE;
4770 }
4771
4772 /*-----------------------------------------------------------------*/
4773 /* addSign - complete with sign                                    */
4774 /*-----------------------------------------------------------------*/
4775 static void
4776 addSign (operand * result, int offset, int sign)
4777 {
4778   int size = (getDataSize (result) - offset);
4779   if (size > 0)
4780     {
4781       if (sign)
4782         {
4783           emitcode ("rlc", "a");
4784           emitcode ("subb", "a,acc");
4785           while (size--)
4786             {
4787               aopPut (result, "a", offset++);
4788             }
4789         }
4790       else
4791         {
4792           while (size--)
4793             {
4794               aopPut (result, zero, offset++);
4795             }
4796         }
4797     }
4798 }
4799
4800 /*-----------------------------------------------------------------*/
4801 /* genMinusBits - generates code for subtraction  of two bits      */
4802 /*-----------------------------------------------------------------*/
4803 static void
4804 genMinusBits (iCode * ic)
4805 {
4806   symbol *lbl = newiTempLabel (NULL);
4807
4808   D (emitcode (";", "genMinusBits"));
4809
4810   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4811     {
4812       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4813       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4814       emitcode ("cpl", "c");
4815       emitLabel (lbl);
4816       outBitC (IC_RESULT (ic));
4817     }
4818   else
4819     {
4820       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4821       emitcode ("subb", "a,acc");
4822       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4823       emitcode ("inc", "a");
4824       emitLabel (lbl);
4825       aopPut (IC_RESULT (ic), "a", 0);
4826       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4827     }
4828 }
4829
4830 /*-----------------------------------------------------------------*/
4831 /* genMinus - generates code for subtraction                       */
4832 /*-----------------------------------------------------------------*/
4833 static void
4834 genMinus (iCode * ic)
4835 {
4836   int size, offset = 0;
4837
4838   D (emitcode (";", "genMinus"));
4839
4840   aopOp (IC_LEFT (ic), ic, FALSE);
4841   aopOp (IC_RIGHT (ic), ic, FALSE);
4842   aopOp (IC_RESULT (ic), ic, TRUE);
4843
4844   /* special cases :- */
4845   /* if both left & right are in bit space */
4846   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4847       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4848     {
4849       genMinusBits (ic);
4850       goto release;
4851     }
4852
4853   /* if I can do an decrement instead
4854      of subtract then GOOD for ME */
4855   if (genMinusDec (ic) == TRUE)
4856     goto release;
4857
4858   size = getDataSize (IC_RESULT (ic));
4859
4860   /* if literal, add a,#-lit, else normal subb */
4861   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4862     {
4863       unsigned long lit = 0L;
4864       bool useCarry = FALSE;
4865
4866       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4867       lit = -(long) lit;
4868
4869       while (size--)
4870         {
4871           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4872             {
4873               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4874               if (!offset && !size && lit== (unsigned long) -1)
4875                 {
4876                   emitcode ("dec", "a");
4877                 }
4878               else if (!useCarry)
4879                 {
4880                   /* first add without previous c */
4881                   emitcode ("add", "a,#0x%02x",
4882                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4883                   useCarry = TRUE;
4884                 }
4885               else
4886                 {
4887                   emitcode ("addc", "a,#0x%02x",
4888                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4889                 }
4890               aopPut (IC_RESULT (ic), "a", offset++);
4891             }
4892           else
4893             {
4894               /* no need to add zeroes */
4895               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4896                 {
4897                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4898                           offset);
4899                 }
4900               offset++;
4901             }
4902         }
4903     }
4904   else
4905     {
4906       operand *leftOp, *rightOp;
4907
4908       leftOp = IC_LEFT(ic);
4909       rightOp = IC_RIGHT(ic);
4910
4911       while (size--)
4912         {
4913           if (aopGetUsesAcc(rightOp, offset)) {
4914             if (aopGetUsesAcc(leftOp, offset)) {
4915               bool pushedB;
4916
4917               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4918               pushedB = pushB ();
4919               emitcode ("mov", "b,a");
4920               if (offset == 0)
4921                 CLRC;
4922               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4923               emitcode ("subb", "a,b");
4924               popB (pushedB);
4925             } else {
4926               /* reverse subtraction with 2's complement */
4927               if (offset == 0)
4928                 emitcode( "setb", "c");
4929               else
4930                 emitcode( "cpl", "c");
4931               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4932               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4933               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4934               emitcode("cpl", "a");
4935               if (size) /* skip if last byte */
4936                 emitcode( "cpl", "c");
4937             }
4938           } else {
4939             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4940             if (offset == 0)
4941               CLRC;
4942             emitcode ("subb", "a,%s",
4943                       aopGet(rightOp, offset, FALSE, TRUE));
4944           }
4945
4946           aopPut (IC_RESULT (ic), "a", offset++);
4947         }
4948     }
4949
4950   adjustArithmeticResult (ic);
4951
4952 release:
4953   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4954   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4955   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4956 }
4957
4958
4959 /*-----------------------------------------------------------------*/
4960 /* genMultbits :- multiplication of bits                           */
4961 /*-----------------------------------------------------------------*/
4962 static void
4963 genMultbits (operand * left,
4964              operand * right,
4965              operand * result)
4966 {
4967   D (emitcode (";", "genMultbits"));
4968
4969   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4970   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4971   outBitC (result);
4972 }
4973
4974 /*-----------------------------------------------------------------*/
4975 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4976 /*-----------------------------------------------------------------*/
4977 static void
4978 genMultOneByte (operand * left,
4979                 operand * right,
4980                 operand * result)
4981 {
4982   symbol *lbl;
4983   int size = AOP_SIZE (result);
4984   bool runtimeSign, compiletimeSign;
4985   bool lUnsigned, rUnsigned, pushedB;
4986
4987   D (emitcode (";", "genMultOneByte"));
4988
4989   if (size < 1 || size > 2)
4990     {
4991       /* this should never happen */
4992       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4993                AOP_SIZE(result), __FILE__, lineno);
4994       exit (1);
4995     }
4996
4997   /* (if two literals: the value is computed before) */
4998   /* if one literal, literal on the right */
4999   if (AOP_TYPE (left) == AOP_LIT)
5000     {
5001       operand *t = right;
5002       right = left;
5003       left = t;
5004       /* emitcode (";", "swapped left and right"); */
5005     }
5006   /* if no literal, unsigned on the right: shorter code */
5007   if (   AOP_TYPE (right) != AOP_LIT
5008       && SPEC_USIGN (getSpec (operandType (left))))
5009     {
5010       operand *t = right;
5011       right = left;
5012       left = t;
5013     }
5014
5015   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5016   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5017
5018   pushedB = pushB ();
5019
5020   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5021                    no need to take care about the signedness! */
5022       || (lUnsigned && rUnsigned))
5023     {
5024       /* just an unsigned 8 * 8 = 8 multiply
5025          or 8u * 8u = 16u */
5026       /* emitcode (";","unsigned"); */
5027       /* TODO: check for accumulator clash between left & right aops? */
5028
5029       if (AOP_TYPE (right) == AOP_LIT)
5030         {
5031           /* moving to accumulator first helps peepholes */
5032           MOVA (aopGet (left, 0, FALSE, FALSE));
5033           MOVB (aopGet (right, 0, FALSE, FALSE));
5034         }
5035       else
5036         {
5037           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5038           MOVA (aopGet (left, 0, FALSE, FALSE));
5039         }
5040
5041       emitcode ("mul", "ab");
5042       aopPut (result, "a", 0);
5043       if (size == 2)
5044         aopPut (result, "b", 1);
5045
5046       popB (pushedB);
5047       return;
5048     }
5049
5050   /* we have to do a signed multiply */
5051   /* emitcode (";", "signed"); */
5052
5053   /* now sign adjust for both left & right */
5054
5055   /* let's see what's needed: */
5056   /* apply negative sign during runtime */
5057   runtimeSign = FALSE;
5058   /* negative sign from literals */
5059   compiletimeSign = FALSE;
5060
5061   if (!lUnsigned)
5062     {
5063       if (AOP_TYPE(left) == AOP_LIT)
5064         {
5065           /* signed literal */
5066           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5067           if (val < 0)
5068             compiletimeSign = TRUE;
5069         }
5070       else
5071         /* signed but not literal */
5072         runtimeSign = TRUE;
5073     }
5074
5075   if (!rUnsigned)
5076     {
5077       if (AOP_TYPE(right) == AOP_LIT)
5078         {
5079           /* signed literal */
5080           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5081           if (val < 0)
5082             compiletimeSign ^= TRUE;
5083         }
5084       else
5085         /* signed but not literal */
5086         runtimeSign = TRUE;
5087     }
5088
5089   /* initialize F0, which stores the runtime sign */
5090   if (runtimeSign)
5091     {
5092       if (compiletimeSign)
5093         emitcode ("setb", "F0"); /* set sign flag */
5094       else
5095         emitcode ("clr", "F0"); /* reset sign flag */
5096     }
5097
5098   /* save the signs of the operands */
5099   if (AOP_TYPE(right) == AOP_LIT)
5100     {
5101       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5102
5103       if (!rUnsigned && val < 0)
5104         emitcode ("mov", "b,#0x%02x", -val);
5105       else
5106         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5107     }
5108   else /* ! literal */
5109     {
5110       if (rUnsigned)  /* emitcode (";", "signed"); */
5111         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5112       else
5113         {
5114           MOVA (aopGet (right, 0, FALSE, FALSE));
5115           lbl = newiTempLabel (NULL);
5116           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5117           emitcode ("cpl", "F0"); /* complement sign flag */
5118           emitcode ("cpl", "a");  /* 2's complement */
5119           emitcode ("inc", "a");
5120           emitLabel (lbl);
5121           emitcode ("mov", "b,a");
5122         }
5123     }
5124
5125   if (AOP_TYPE(left) == AOP_LIT)
5126     {
5127       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5128
5129       if (!lUnsigned && val < 0)
5130         emitcode ("mov", "a,#0x%02x", -val);
5131       else
5132         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5133     }
5134   else /* ! literal */
5135     {
5136       MOVA (aopGet (left, 0, FALSE, FALSE));
5137
5138       if (!lUnsigned)
5139         {
5140           lbl = newiTempLabel (NULL);
5141           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5142           emitcode ("cpl", "F0"); /* complement sign flag */
5143           emitcode ("cpl", "a"); /* 2's complement */
5144           emitcode ("inc", "a");
5145           emitLabel (lbl);
5146         }
5147     }
5148
5149   /* now the multiplication */
5150   emitcode ("mul", "ab");
5151   if (runtimeSign || compiletimeSign)
5152     {
5153       lbl = newiTempLabel (NULL);
5154       if (runtimeSign)
5155         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5156       emitcode ("cpl", "a"); /* lsb 2's complement */
5157       if (size != 2)
5158         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5159       else
5160         {
5161           emitcode ("add", "a,#1"); /* this sets carry flag */
5162           emitcode ("xch", "a,b");
5163           emitcode ("cpl", "a"); /* msb 2's complement */
5164           emitcode ("addc", "a,#0");
5165           emitcode ("xch", "a,b");
5166         }
5167       emitLabel (lbl);
5168     }
5169   aopPut (result, "a", 0);
5170   if (size == 2)
5171     aopPut (result, "b", 1);
5172
5173   popB (pushedB);
5174 }
5175
5176 /*-----------------------------------------------------------------*/
5177 /* genMult - generates code for multiplication                     */
5178 /*-----------------------------------------------------------------*/
5179 static void
5180 genMult (iCode * ic)
5181 {
5182   operand *left = IC_LEFT (ic);
5183   operand *right = IC_RIGHT (ic);
5184   operand *result = IC_RESULT (ic);
5185
5186   D (emitcode (";", "genMult"));
5187
5188   /* assign the asmops */
5189   aopOp (left, ic, FALSE);
5190   aopOp (right, ic, FALSE);
5191   aopOp (result, ic, TRUE);
5192
5193   /* special cases first */
5194   /* both are bits */
5195   if (AOP_TYPE (left) == AOP_CRY &&
5196       AOP_TYPE (right) == AOP_CRY)
5197     {
5198       genMultbits (left, right, result);
5199       goto release;
5200     }
5201
5202   /* if both are of size == 1 */
5203 #if 0 // one of them can be a sloc shared with the result
5204     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5205 #else
5206   if (getSize(operandType(left)) == 1 &&
5207       getSize(operandType(right)) == 1)
5208 #endif
5209     {
5210       genMultOneByte (left, right, result);
5211       goto release;
5212     }
5213
5214   /* should have been converted to function call */
5215     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5216              getSize(OP_SYMBOL(right)->type));
5217   assert (0);
5218
5219 release:
5220   freeAsmop (result, NULL, ic, TRUE);
5221   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5222   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5223 }
5224
5225 /*-----------------------------------------------------------------*/
5226 /* genDivbits :- division of bits                                  */
5227 /*-----------------------------------------------------------------*/
5228 static void
5229 genDivbits (operand * left,
5230             operand * right,
5231             operand * result)
5232 {
5233   char *l;
5234   bool pushedB;
5235
5236   D(emitcode (";", "genDivbits"));
5237
5238   pushedB = pushB ();
5239
5240   /* the result must be bit */
5241   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5242   l = aopGet (left, 0, FALSE, FALSE);
5243
5244   MOVA (l);
5245
5246   emitcode ("div", "ab");
5247   emitcode ("rrc", "a");
5248
5249   popB (pushedB);
5250
5251   aopPut (result, "c", 0);
5252 }
5253
5254 /*-----------------------------------------------------------------*/
5255 /* genDivOneByte : 8 bit division                                  */
5256 /*-----------------------------------------------------------------*/
5257 static void
5258 genDivOneByte (operand * left,
5259                operand * right,
5260                operand * result)
5261 {
5262   bool lUnsigned, rUnsigned, pushedB;
5263   bool runtimeSign, compiletimeSign;
5264   bool accuse = FALSE;
5265   bool pushedA = FALSE;
5266   symbol *lbl;
5267   int size, offset;
5268
5269   D(emitcode (";", "genDivOneByte"));
5270
5271   /* Why is it necessary that genDivOneByte() can return an int result?
5272      Have a look at:
5273
5274         volatile unsigned char uc;
5275         volatile signed char sc1, sc2;
5276         volatile int i;
5277
5278         uc  = 255;
5279         sc1 = -1;
5280         i = uc / sc1;
5281
5282      Or:
5283
5284         sc1 = -128;
5285         sc2 = -1;
5286         i = sc1 / sc2;
5287
5288      In all cases a one byte result would overflow, the following cast to int
5289      would return the wrong result.
5290
5291      Two possible solution:
5292         a) cast operands to int, if ((unsigned) / (signed)) or
5293            ((signed) / (signed))
5294         b) return an 16 bit signed int; this is what we're doing here!
5295   */
5296
5297   size = AOP_SIZE (result) - 1;
5298   offset = 1;
5299   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5300   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5301
5302   pushedB = pushB ();
5303
5304   /* signed or unsigned */
5305   if (lUnsigned && rUnsigned)
5306     {
5307       /* unsigned is easy */
5308       MOVB (aopGet (right, 0, FALSE, FALSE));
5309       MOVA (aopGet (left, 0, FALSE, FALSE));
5310       emitcode ("div", "ab");
5311       aopPut (result, "a", 0);
5312       while (size--)
5313         aopPut (result, zero, offset++);
5314
5315       popB (pushedB);
5316       return;
5317     }
5318
5319   /* signed is a little bit more difficult */
5320
5321   /* now sign adjust for both left & right */
5322
5323   /* let's see what's needed: */
5324   /* apply negative sign during runtime */
5325   runtimeSign = FALSE;
5326   /* negative sign from literals */
5327   compiletimeSign = FALSE;
5328
5329   if (!lUnsigned)
5330     {
5331       if (AOP_TYPE(left) == AOP_LIT)
5332         {
5333           /* signed literal */
5334           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5335           if (val < 0)
5336             compiletimeSign = TRUE;
5337         }
5338       else
5339         /* signed but not literal */
5340         runtimeSign = TRUE;
5341     }
5342
5343   if (!rUnsigned)
5344     {
5345       if (AOP_TYPE(right) == AOP_LIT)
5346         {
5347           /* signed literal */
5348           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5349           if (val < 0)
5350             compiletimeSign ^= TRUE;
5351         }
5352       else
5353         /* signed but not literal */
5354         runtimeSign = TRUE;
5355     }
5356
5357   /* initialize F0, which stores the runtime sign */
5358   if (runtimeSign)
5359     {
5360       if (compiletimeSign)
5361         emitcode ("setb", "F0"); /* set sign flag */
5362       else
5363         emitcode ("clr", "F0"); /* reset sign flag */
5364     }
5365
5366   /* save the signs of the operands */
5367   if (AOP_TYPE(right) == AOP_LIT)
5368     {
5369       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5370
5371       if (!rUnsigned && val < 0)
5372         emitcode ("mov", "b,#0x%02x", -val);
5373       else
5374         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5375     }
5376   else /* ! literal */
5377     {
5378       if (rUnsigned)
5379         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5380       else
5381         {
5382           MOVA (aopGet (right, 0, FALSE, FALSE));
5383           lbl = newiTempLabel (NULL);
5384           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5385           emitcode ("cpl", "F0"); /* complement sign flag */
5386           emitcode ("cpl", "a");  /* 2's complement */
5387           emitcode ("inc", "a");
5388           emitLabel (lbl);
5389           emitcode ("mov", "b,a");
5390         }
5391     }
5392
5393   if (AOP_TYPE(left) == AOP_LIT)
5394     {
5395       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5396
5397       if (!lUnsigned && val < 0)
5398         emitcode ("mov", "a,#0x%02x", -val);
5399       else
5400         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5401     }
5402   else /* ! literal */
5403     {
5404       MOVA (aopGet (left, 0, FALSE, FALSE));
5405
5406       if (!lUnsigned)
5407         {
5408           lbl = newiTempLabel (NULL);
5409           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5410           emitcode ("cpl", "F0"); /* complement sign flag */
5411           emitcode ("cpl", "a");  /* 2's complement */
5412           emitcode ("inc", "a");
5413           emitLabel (lbl);
5414         }
5415     }
5416
5417   /* now the division */
5418   emitcode ("div", "ab");
5419
5420   if (runtimeSign || compiletimeSign)
5421     {
5422       lbl = newiTempLabel (NULL);
5423       if (runtimeSign)
5424         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5425       emitcode ("cpl", "a"); /* lsb 2's complement */
5426       emitcode ("inc", "a");
5427       emitLabel (lbl);
5428
5429       accuse = aopPut (result, "a", 0);
5430       if (size > 0)
5431         {
5432           /* msb is 0x00 or 0xff depending on the sign */
5433           if (runtimeSign)
5434             {
5435               if (accuse)
5436                 {
5437                   emitcode ("push", "acc");
5438                   pushedA = TRUE;
5439                 }
5440               emitcode ("mov", "c,F0");
5441               emitcode ("subb", "a,acc");
5442               while (size--)
5443                 aopPut (result, "a", offset++);
5444             }
5445           else /* compiletimeSign */
5446             {
5447               if (aopPutUsesAcc (result, "#0xFF", offset))
5448                 {
5449                   emitcode ("push", "acc");
5450                   pushedA = TRUE;
5451                 }
5452               while (size--)
5453                 aopPut (result, "#0xff", offset++);
5454             }
5455         }
5456     }
5457   else
5458     {
5459       aopPut (result, "a", 0);
5460       while (size--)
5461         aopPut (result, zero, offset++);
5462     }
5463
5464   if (pushedA)
5465     emitcode ("pop", "acc");
5466   popB (pushedB);
5467 }
5468
5469 /*-----------------------------------------------------------------*/
5470 /* genDiv - generates code for division                            */
5471 /*-----------------------------------------------------------------*/
5472 static void
5473 genDiv (iCode * ic)
5474 {
5475   operand *left = IC_LEFT (ic);
5476   operand *right = IC_RIGHT (ic);
5477   operand *result = IC_RESULT (ic);
5478
5479   D (emitcode (";", "genDiv"));
5480
5481   /* assign the asmops */
5482   aopOp (left, ic, FALSE);
5483   aopOp (right, ic, FALSE);
5484   aopOp (result, ic, TRUE);
5485
5486   /* special cases first */
5487   /* both are bits */
5488   if (AOP_TYPE (left) == AOP_CRY &&
5489       AOP_TYPE (right) == AOP_CRY)
5490     {
5491       genDivbits (left, right, result);
5492       goto release;
5493     }
5494
5495   /* if both are of size == 1 */
5496   if (AOP_SIZE (left) == 1 &&
5497       AOP_SIZE (right) == 1)
5498     {
5499       genDivOneByte (left, right, result);
5500       goto release;
5501     }
5502
5503   /* should have been converted to function call */
5504   assert (0);
5505 release:
5506   freeAsmop (result, NULL, ic, TRUE);
5507   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5508   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5509 }
5510
5511 /*-----------------------------------------------------------------*/
5512 /* genModbits :- modulus of bits                                   */
5513 /*-----------------------------------------------------------------*/
5514 static void
5515 genModbits (operand * left,
5516             operand * right,
5517             operand * result)
5518 {
5519   char *l;
5520   bool pushedB;
5521
5522   D (emitcode (";", "genModbits"));
5523
5524   pushedB = pushB ();
5525
5526   /* the result must be bit */
5527   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5528   l = aopGet (left, 0, FALSE, FALSE);
5529
5530   MOVA (l);
5531
5532   emitcode ("div", "ab");
5533   emitcode ("mov", "a,b");
5534   emitcode ("rrc", "a");
5535
5536   popB (pushedB);
5537
5538   aopPut (result, "c", 0);
5539 }
5540
5541 /*-----------------------------------------------------------------*/
5542 /* genModOneByte : 8 bit modulus                                   */
5543 /*-----------------------------------------------------------------*/
5544 static void
5545 genModOneByte (operand * left,
5546                operand * right,
5547                operand * result)
5548 {
5549   bool lUnsigned, rUnsigned, pushedB;
5550   bool runtimeSign, compiletimeSign;
5551   symbol *lbl;
5552   int size, offset;
5553
5554   D (emitcode (";", "genModOneByte"));
5555
5556   size = AOP_SIZE (result) - 1;
5557   offset = 1;
5558   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5559   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5560
5561   /* if right is a literal, check it for 2^n */
5562   if (AOP_TYPE(right) == AOP_LIT)
5563     {
5564       unsigned char val = abs((int) operandLitValue(right));
5565       symbol *lbl2 = NULL;
5566
5567       switch (val)
5568         {
5569           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5570           case 2:
5571           case 4:
5572           case 8:
5573           case 16:
5574           case 32:
5575           case 64:
5576           case 128:
5577             if (lUnsigned)
5578               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5579                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5580               /* because iCode should have been changed to genAnd  */
5581               /* see file "SDCCopt.c", function "convertToFcall()" */
5582
5583             MOVA (aopGet (left, 0, FALSE, FALSE));
5584             emitcode ("mov", "c,acc.7");
5585             emitcode ("anl", "a,#0x%02x", val - 1);
5586             lbl = newiTempLabel (NULL);
5587             emitcode ("jz", "%05d$", (lbl->key + 100));
5588             emitcode ("jnc", "%05d$", (lbl->key + 100));
5589             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5590             if (size)
5591               {
5592                 int size2 = size;
5593                 int offs2 = offset;
5594
5595                 aopPut (result, "a", 0);
5596                 while (size2--)
5597                   aopPut (result, "#0xff", offs2++);
5598                 lbl2 = newiTempLabel (NULL);
5599                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5600               }
5601             emitLabel (lbl);
5602             aopPut (result, "a", 0);
5603             while (size--)
5604               aopPut (result, zero, offset++);
5605             if (lbl2)
5606               {
5607                 emitLabel (lbl2);
5608               }
5609             return;
5610
5611           default:
5612             break;
5613         }
5614     }
5615
5616   pushedB = pushB ();
5617
5618   /* signed or unsigned */
5619   if (lUnsigned && rUnsigned)
5620     {
5621       /* unsigned is easy */
5622       MOVB (aopGet (right, 0, FALSE, FALSE));
5623       MOVA (aopGet (left, 0, FALSE, FALSE));
5624       emitcode ("div", "ab");
5625       aopPut (result, "b", 0);
5626       while (size--)
5627         aopPut (result, zero, offset++);
5628
5629       popB (pushedB);
5630       return;
5631     }
5632
5633   /* signed is a little bit more difficult */
5634
5635   /* now sign adjust for both left & right */
5636
5637   /* modulus: sign of the right operand has no influence on the result! */
5638   if (AOP_TYPE(right) == AOP_LIT)
5639     {
5640       signed char val = (char) operandLitValue(right);
5641
5642       if (!rUnsigned && val < 0)
5643         emitcode ("mov", "b,#0x%02x", -val);
5644       else
5645         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5646     }
5647   else /* not literal */
5648     {
5649       if (rUnsigned)
5650         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5651       else
5652         {
5653           MOVA (aopGet (right, 0, FALSE, FALSE));
5654           lbl = newiTempLabel (NULL);
5655           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5656           emitcode ("cpl", "a"); /* 2's complement */
5657           emitcode ("inc", "a");
5658           emitLabel (lbl);
5659           emitcode ("mov", "b,a");
5660         }
5661     }
5662
5663   /* let's see what's needed: */
5664   /* apply negative sign during runtime */
5665   runtimeSign = FALSE;
5666   /* negative sign from literals */
5667   compiletimeSign = FALSE;
5668
5669   /* sign adjust left side */
5670   if (AOP_TYPE(left) == AOP_LIT)
5671     {
5672       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5673
5674       if (!lUnsigned && val < 0)
5675         {
5676           compiletimeSign = TRUE; /* set sign flag */
5677           emitcode ("mov", "a,#0x%02x", -val);
5678         }
5679       else
5680         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5681     }
5682   else /* ! literal */
5683     {
5684       MOVA (aopGet (left, 0, FALSE, FALSE));
5685
5686       if (!lUnsigned)
5687         {
5688           runtimeSign = TRUE;
5689           emitcode ("clr", "F0"); /* clear sign flag */
5690
5691           lbl = newiTempLabel (NULL);
5692           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5693           emitcode ("setb", "F0"); /* set sign flag */
5694           emitcode ("cpl", "a");   /* 2's complement */
5695           emitcode ("inc", "a");
5696           emitLabel (lbl);
5697         }
5698     }
5699
5700   /* now the modulus */
5701   emitcode ("div", "ab");
5702
5703   if (runtimeSign || compiletimeSign)
5704     {
5705       emitcode ("mov", "a,b");
5706       lbl = newiTempLabel (NULL);
5707       if (runtimeSign)
5708         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5709       emitcode ("cpl", "a"); /* 2's complement */
5710       emitcode ("inc", "a");
5711       emitLabel (lbl);
5712
5713       aopPut (result, "a", 0);
5714       if (size > 0)
5715         {
5716           /* msb is 0x00 or 0xff depending on the sign */
5717           if (runtimeSign)
5718             {
5719               emitcode ("mov", "c,F0");
5720               emitcode ("subb", "a,acc");
5721               while (size--)
5722                 aopPut (result, "a", offset++);
5723             }
5724           else /* compiletimeSign */
5725             while (size--)
5726               aopPut (result, "#0xff", offset++);
5727         }
5728     }
5729   else
5730     {
5731       aopPut (result, "b", 0);
5732       while (size--)
5733         aopPut (result, zero, offset++);
5734     }
5735
5736   popB (pushedB);
5737 }
5738
5739 /*-----------------------------------------------------------------*/
5740 /* genMod - generates code for division                            */
5741 /*-----------------------------------------------------------------*/
5742 static void
5743 genMod (iCode * ic)
5744 {
5745   operand *left = IC_LEFT (ic);
5746   operand *right = IC_RIGHT (ic);
5747   operand *result = IC_RESULT (ic);
5748
5749   D (emitcode (";", "genMod"));
5750
5751   /* assign the asmops */
5752   aopOp (left, ic, FALSE);
5753   aopOp (right, ic, FALSE);
5754   aopOp (result, ic, TRUE);
5755
5756   /* special cases first */
5757   /* both are bits */
5758   if (AOP_TYPE (left) == AOP_CRY &&
5759       AOP_TYPE (right) == AOP_CRY)
5760     {
5761       genModbits (left, right, result);
5762       goto release;
5763     }
5764
5765   /* if both are of size == 1 */
5766   if (AOP_SIZE (left) == 1 &&
5767       AOP_SIZE (right) == 1)
5768     {
5769       genModOneByte (left, right, result);
5770       goto release;
5771     }
5772
5773   /* should have been converted to function call */
5774   assert (0);
5775
5776 release:
5777   freeAsmop (result, NULL, ic, TRUE);
5778   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5779   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5780 }
5781
5782 /*-----------------------------------------------------------------*/
5783 /* genIfxJump :- will create a jump depending on the ifx           */
5784 /*-----------------------------------------------------------------*/
5785 static void
5786 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5787 {
5788   symbol *jlbl;
5789   symbol *tlbl = newiTempLabel (NULL);
5790   char *inst;
5791
5792   D (emitcode (";", "genIfxJump"));
5793
5794   /* if true label then we jump if condition
5795      supplied is true */
5796   if (IC_TRUE (ic))
5797     {
5798       jlbl = IC_TRUE (ic);
5799       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5800                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5801     }
5802   else
5803     {
5804       /* false label is present */
5805       jlbl = IC_FALSE (ic);
5806       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5807                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5808     }
5809   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5810     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5811   else
5812     emitcode (inst, "%05d$", tlbl->key + 100);
5813   freeForBranchAsmop (result);
5814   freeForBranchAsmop (right);
5815   freeForBranchAsmop (left);
5816   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5817   emitLabel (tlbl);
5818
5819   /* mark the icode as generated */
5820   ic->generated = 1;
5821 }
5822
5823 /*-----------------------------------------------------------------*/
5824 /* genCmp :- greater or less than comparison                       */
5825 /*-----------------------------------------------------------------*/
5826 static void
5827 genCmp (operand * left, operand * right,
5828         operand * result, iCode * ifx, int sign, iCode *ic)
5829 {
5830   int size, offset = 0;
5831   unsigned long lit = 0L;
5832   bool rightInB;
5833
5834   D (emitcode (";", "genCmp"));
5835
5836   /* if left & right are bit variables */
5837   if (AOP_TYPE (left) == AOP_CRY &&
5838       AOP_TYPE (right) == AOP_CRY)
5839     {
5840       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5841       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5842     }
5843   else
5844     {
5845       /* subtract right from left if at the
5846          end the carry flag is set then we know that
5847          left is greater than right */
5848       size = max (AOP_SIZE (left), AOP_SIZE (right));
5849
5850       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5851       if ((size == 1) && !sign &&
5852           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5853         {
5854           symbol *lbl = newiTempLabel (NULL);
5855           emitcode ("cjne", "%s,%s,%05d$",
5856                     aopGet (left, offset, FALSE, FALSE),
5857                     aopGet (right, offset, FALSE, FALSE),
5858                     lbl->key + 100);
5859           emitLabel (lbl);
5860         }
5861       else
5862         {
5863           if (AOP_TYPE (right) == AOP_LIT)
5864             {
5865               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5866               /* optimize if(x < 0) or if(x >= 0) */
5867               if (lit == 0L)
5868                 {
5869                   if (!sign)
5870                     {
5871                       CLRC;
5872                     }
5873                   else
5874                     {
5875                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5876                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5877                         {
5878                           genIfxJump (ifx, "acc.7", left, right, result);
5879                           freeAsmop (right, NULL, ic, TRUE);
5880                           freeAsmop (left, NULL, ic, TRUE);
5881
5882                           return;
5883                         }
5884                       else
5885                         {
5886                           emitcode ("rlc", "a");
5887                         }
5888                     }
5889                   goto release;
5890                 }
5891               else
5892                 {//nonzero literal
5893                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5894                   while (size && (bytelit == 0))
5895                     {
5896                       offset++;
5897                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5898                       size--;
5899                     }
5900                   CLRC;
5901                   while (size--)
5902                     {
5903                       MOVA (aopGet (left, offset, FALSE, FALSE));
5904                       if (sign && size == 0)
5905                         {
5906                           emitcode ("xrl", "a,#0x80");
5907                           emitcode ("subb", "a,#0x%02x",
5908                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5909                         }
5910                       else
5911                         {
5912                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5913                         }
5914                       offset++;
5915                     }
5916                   goto release;
5917                 }
5918             }
5919           CLRC;
5920           while (size--)
5921             {
5922               bool pushedB = FALSE;
5923               rightInB = aopGetUsesAcc(right, offset);
5924               if (rightInB)
5925                 {
5926                   pushedB = pushB ();
5927                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5928                 }
5929               MOVA (aopGet (left, offset, FALSE, FALSE));
5930               if (sign && size == 0)
5931                 {
5932                   emitcode ("xrl", "a,#0x80");
5933                   if (!rightInB)
5934                     {
5935                       pushedB = pushB ();
5936                       rightInB++;
5937                       MOVB (aopGet (right, offset, FALSE, FALSE));
5938                     }
5939                   emitcode ("xrl", "b,#0x80");
5940                   emitcode ("subb", "a,b");
5941                 }
5942               else
5943                 {
5944                   if (rightInB)
5945                     emitcode ("subb", "a,b");
5946                   else
5947                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5948                 }
5949               if (rightInB)
5950                 popB (pushedB);
5951               offset++;
5952             }
5953         }
5954     }
5955
5956 release:
5957   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5958   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5959   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5960     {
5961       outBitC (result);
5962     }
5963   else
5964     {
5965       /* if the result is used in the next
5966          ifx conditional branch then generate
5967          code a little differently */
5968       if (ifx)
5969         {
5970           genIfxJump (ifx, "c", NULL, NULL, result);
5971         }
5972       else
5973         {
5974           outBitC (result);
5975         }
5976       /* leave the result in acc */
5977     }
5978 }
5979
5980 /*-----------------------------------------------------------------*/
5981 /* genCmpGt :- greater than comparison                             */
5982 /*-----------------------------------------------------------------*/
5983 static void
5984 genCmpGt (iCode * ic, iCode * ifx)
5985 {
5986   operand *left, *right, *result;
5987   sym_link *letype, *retype;
5988   int sign;
5989
5990   D (emitcode (";", "genCmpGt"));
5991
5992   left = IC_LEFT (ic);
5993   right = IC_RIGHT (ic);
5994   result = IC_RESULT (ic);
5995
5996   letype = getSpec (operandType (left));
5997   retype = getSpec (operandType (right));
5998   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5999            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6000   /* assign the asmops */
6001   aopOp (result, ic, TRUE);
6002   aopOp (left, ic, FALSE);
6003   aopOp (right, ic, FALSE);
6004
6005   genCmp (right, left, result, ifx, sign, ic);
6006
6007   freeAsmop (result, NULL, ic, TRUE);
6008 }
6009
6010 /*-----------------------------------------------------------------*/
6011 /* genCmpLt - less than comparisons                                */
6012 /*-----------------------------------------------------------------*/
6013 static void
6014 genCmpLt (iCode * ic, iCode * ifx)
6015 {
6016   operand *left, *right, *result;
6017   sym_link *letype, *retype;
6018   int sign;
6019
6020   D (emitcode (";", "genCmpLt"));
6021
6022   left = IC_LEFT (ic);
6023   right = IC_RIGHT (ic);
6024   result = IC_RESULT (ic);
6025
6026   letype = getSpec (operandType (left));
6027   retype = getSpec (operandType (right));
6028   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6029            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6030   /* assign the asmops */
6031   aopOp (result, ic, TRUE);
6032   aopOp (left, ic, FALSE);
6033   aopOp (right, ic, FALSE);
6034
6035   genCmp (left, right, result, ifx, sign, ic);
6036
6037   freeAsmop (result, NULL, ic, TRUE);
6038 }
6039
6040 /*-----------------------------------------------------------------*/
6041 /* gencjneshort - compare and jump if not equal                    */
6042 /*-----------------------------------------------------------------*/
6043 static void
6044 gencjneshort (operand * left, operand * right, symbol * lbl)
6045 {
6046   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6047   int offset = 0;
6048   unsigned long lit = 0L;
6049
6050   D (emitcode (";", "gencjneshort"));
6051
6052   /* if the left side is a literal or
6053      if the right is in a pointer register and left
6054      is not */
6055   if ((AOP_TYPE (left) == AOP_LIT)  ||
6056       (AOP_TYPE (left) == AOP_IMMD) ||
6057       (AOP_TYPE (left) == AOP_DIR)  ||
6058       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6059     {
6060       operand *t = right;
6061       right = left;
6062       left = t;
6063     }
6064
6065   if (AOP_TYPE (right) == AOP_LIT)
6066     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6067
6068   /* if the right side is a literal then anything goes */
6069   if (AOP_TYPE (right) == AOP_LIT &&
6070       AOP_TYPE (left) != AOP_DIR  &&
6071       AOP_TYPE (left) != AOP_IMMD)
6072     {
6073       while (size--)
6074         {
6075           emitcode ("cjne", "%s,%s,%05d$",
6076                     aopGet (left, offset, FALSE, FALSE),
6077                     aopGet (right, offset, FALSE, FALSE),
6078                     lbl->key + 100);
6079           offset++;
6080         }
6081     }
6082
6083   /* if the right side is in a register or in direct space or
6084      if the left is a pointer register & right is not */
6085   else if (AOP_TYPE (right) == AOP_REG ||
6086            AOP_TYPE (right) == AOP_DIR ||
6087            AOP_TYPE (right) == AOP_LIT ||
6088            AOP_TYPE (right) == AOP_IMMD ||
6089            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6090            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6091     {
6092       while (size--)
6093         {
6094           MOVA (aopGet (left, offset, FALSE, FALSE));
6095           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6096               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6097             emitcode ("jnz", "%05d$", lbl->key + 100);
6098           else
6099             emitcode ("cjne", "a,%s,%05d$",
6100                       aopGet (right, offset, FALSE, TRUE),
6101                       lbl->key + 100);
6102           offset++;
6103         }
6104     }
6105   else
6106     {
6107       /* right is a pointer reg need both a & b */
6108       while (size--)
6109         {
6110           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6111           wassertl(!BINUSE, "B was in use");
6112           MOVB (aopGet (left, offset, FALSE, FALSE));
6113           MOVA (aopGet (right, offset, FALSE, FALSE));
6114           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6115           offset++;
6116         }
6117     }
6118 }
6119
6120 /*-----------------------------------------------------------------*/
6121 /* gencjne - compare and jump if not equal                         */
6122 /*-----------------------------------------------------------------*/
6123 static void
6124 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6125 {
6126   symbol *tlbl = newiTempLabel (NULL);
6127
6128   D (emitcode (";", "gencjne"));
6129
6130   gencjneshort (left, right, lbl);
6131
6132   if (useCarry)
6133       SETC;
6134   else
6135       MOVA (one);
6136   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6137   emitLabel (lbl);
6138   if (useCarry)
6139       CLRC;
6140   else
6141       MOVA (zero);
6142   emitLabel (tlbl);
6143 }
6144
6145 /*-----------------------------------------------------------------*/
6146 /* genCmpEq - generates code for equal to                          */
6147 /*-----------------------------------------------------------------*/
6148 static void
6149 genCmpEq (iCode * ic, iCode * ifx)
6150 {
6151   bool swappedLR = FALSE;
6152   operand *left, *right, *result;
6153
6154   D (emitcode (";", "genCmpEq"));
6155
6156   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6157   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6158   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6159
6160   /* if literal, literal on the right or
6161      if the right is in a pointer register and left
6162      is not */
6163   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6164       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6165     {
6166       operand *t = IC_RIGHT (ic);
6167       IC_RIGHT (ic) = IC_LEFT (ic);
6168       IC_LEFT (ic) = t;
6169       swappedLR = TRUE;
6170     }
6171
6172   if (ifx && !AOP_SIZE (result))
6173     {
6174       symbol *tlbl;
6175       /* if they are both bit variables */
6176       if (AOP_TYPE (left) == AOP_CRY &&
6177           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6178         {
6179           if (AOP_TYPE (right) == AOP_LIT)
6180             {
6181               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6182               if (lit == 0L)
6183                 {
6184                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6185                   emitcode ("cpl", "c");
6186                 }
6187               else if (lit == 1L)
6188                 {
6189                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6190                 }
6191               else
6192                 {
6193                   emitcode ("clr", "c");
6194                 }
6195               /* AOP_TYPE(right) == AOP_CRY */
6196             }
6197           else
6198             {
6199               symbol *lbl = newiTempLabel (NULL);
6200               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6201               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6202               emitcode ("cpl", "c");
6203               emitLabel (lbl);
6204             }
6205           /* if true label then we jump if condition
6206              supplied is true */
6207           tlbl = newiTempLabel (NULL);
6208           if (IC_TRUE (ifx))
6209             {
6210               emitcode ("jnc", "%05d$", tlbl->key + 100);
6211               freeForBranchAsmop (result);
6212               freeForBranchAsmop (right);
6213               freeForBranchAsmop (left);
6214               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6215             }
6216           else
6217             {
6218               emitcode ("jc", "%05d$", tlbl->key + 100);
6219               freeForBranchAsmop (result);
6220               freeForBranchAsmop (right);
6221               freeForBranchAsmop (left);
6222               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6223             }
6224           emitLabel (tlbl);
6225         }
6226       else
6227         {
6228           tlbl = newiTempLabel (NULL);
6229           gencjneshort (left, right, tlbl);
6230           if (IC_TRUE (ifx))
6231             {
6232               freeForBranchAsmop (result);
6233               freeForBranchAsmop (right);
6234               freeForBranchAsmop (left);
6235               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6236               emitLabel (tlbl);
6237             }
6238           else
6239             {
6240               symbol *lbl = newiTempLabel (NULL);
6241               emitcode ("sjmp", "%05d$", lbl->key + 100);
6242               emitLabel (tlbl);
6243               freeForBranchAsmop (result);
6244               freeForBranchAsmop (right);
6245               freeForBranchAsmop (left);
6246               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6247               emitLabel (lbl);
6248             }
6249         }
6250       /* mark the icode as generated */
6251       ifx->generated = 1;
6252       goto release;
6253     }
6254
6255   /* if they are both bit variables */
6256   if (AOP_TYPE (left) == AOP_CRY &&
6257       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6258     {
6259       if (AOP_TYPE (right) == AOP_LIT)
6260         {
6261           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6262           if (lit == 0L)
6263             {
6264               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6265               emitcode ("cpl", "c");
6266             }
6267           else if (lit == 1L)
6268             {
6269               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6270             }
6271           else
6272             {
6273               emitcode ("clr", "c");
6274             }
6275           /* AOP_TYPE(right) == AOP_CRY */
6276         }
6277       else
6278         {
6279           symbol *lbl = newiTempLabel (NULL);
6280           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6281           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6282           emitcode ("cpl", "c");
6283           emitLabel (lbl);
6284         }
6285       /* c = 1 if egal */
6286       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6287         {
6288           outBitC (result);
6289           goto release;
6290         }
6291       if (ifx)
6292         {
6293           genIfxJump (ifx, "c", left, right, result);
6294           goto release;
6295         }
6296       /* if the result is used in an arithmetic operation
6297          then put the result in place */
6298       outBitC (result);
6299     }
6300   else
6301     {
6302       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6303         {
6304           gencjne (left, right, newiTempLabel (NULL), TRUE);
6305           aopPut (result, "c", 0);
6306           goto release;
6307         }
6308       gencjne (left, right, newiTempLabel (NULL), FALSE);
6309       if (ifx)
6310         {
6311           genIfxJump (ifx, "a", left, right, result);
6312           goto release;
6313         }
6314       /* if the result is used in an arithmetic operation
6315          then put the result in place */
6316       if (AOP_TYPE (result) != AOP_CRY)
6317         outAcc (result);
6318       /* leave the result in acc */
6319     }
6320
6321 release:
6322   freeAsmop (result, NULL, ic, TRUE);
6323   if (!swappedLR)
6324     {
6325       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327     }
6328   else
6329     {
6330       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6331       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6332     }
6333 }
6334
6335 /*-----------------------------------------------------------------*/
6336 /* ifxForOp - returns the icode containing the ifx for operand     */
6337 /*-----------------------------------------------------------------*/
6338 static iCode *
6339 ifxForOp (operand * op, iCode * ic)
6340 {
6341   /* if true symbol then needs to be assigned */
6342   if (IS_TRUE_SYMOP (op))
6343     return NULL;
6344
6345   /* if this has register type condition and
6346      the next instruction is ifx with the same operand
6347      and live to of the operand is upto the ifx only then */
6348   if (ic->next &&
6349       ic->next->op == IFX &&
6350       IC_COND (ic->next)->key == op->key &&
6351       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6352     return ic->next;
6353
6354   return NULL;
6355 }
6356
6357 /*-----------------------------------------------------------------*/
6358 /* hasInc - operand is incremented before any other use            */
6359 /*-----------------------------------------------------------------*/
6360 static iCode *
6361 hasInc (operand *op, iCode *ic, int osize)
6362 {
6363   sym_link *type = operandType(op);
6364   sym_link *retype = getSpec (type);
6365   iCode *lic = ic->next;
6366   int isize ;
6367
6368   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6369   if (!IS_SYMOP(op)) return NULL;
6370
6371   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6372   if (IS_AGGREGATE(type->next)) return NULL;
6373   if (osize != (isize = getSize(type->next))) return NULL;
6374
6375   while (lic) {
6376     /* if operand of the form op = op + <sizeof *op> */
6377     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6378         isOperandEqual(IC_RESULT(lic),op) &&
6379         isOperandLiteral(IC_RIGHT(lic)) &&
6380         operandLitValue(IC_RIGHT(lic)) == isize) {
6381       return lic;
6382     }
6383     /* if the operand used or deffed */
6384     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6385       return NULL;
6386     }
6387     /* if GOTO or IFX */
6388     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6389     lic = lic->next;
6390   }
6391   return NULL;
6392 }
6393
6394 /*-----------------------------------------------------------------*/
6395 /* genAndOp - for && operation                                     */
6396 /*-----------------------------------------------------------------*/
6397 static void
6398 genAndOp (iCode * ic)
6399 {
6400   operand *left, *right, *result;
6401   symbol *tlbl;
6402
6403   D (emitcode (";", "genAndOp"));
6404
6405   /* note here that && operations that are in an
6406      if statement are taken away by backPatchLabels
6407      only those used in arthmetic operations remain */
6408   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6409   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6410   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6411
6412   /* if both are bit variables */
6413   if (AOP_TYPE (left) == AOP_CRY &&
6414       AOP_TYPE (right) == AOP_CRY)
6415     {
6416       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6417       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6418       outBitC (result);
6419     }
6420   else
6421     {
6422       tlbl = newiTempLabel (NULL);
6423       toBoolean (left);
6424       emitcode ("jz", "%05d$", tlbl->key + 100);
6425       toBoolean (right);
6426       emitLabel (tlbl);
6427       outBitAcc (result);
6428     }
6429
6430   freeAsmop (result, NULL, ic, TRUE);
6431   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6432   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6433 }
6434
6435
6436 /*-----------------------------------------------------------------*/
6437 /* genOrOp - for || operation                                      */
6438 /*-----------------------------------------------------------------*/
6439 static void
6440 genOrOp (iCode * ic)
6441 {
6442   operand *left, *right, *result;
6443   symbol *tlbl;
6444
6445   D (emitcode (";", "genOrOp"));
6446
6447   /* note here that || operations that are in an
6448      if statement are taken away by backPatchLabels
6449      only those used in arthmetic operations remain */
6450   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6451   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6452   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6453
6454   /* if both are bit variables */
6455   if (AOP_TYPE (left) == AOP_CRY &&
6456       AOP_TYPE (right) == AOP_CRY)
6457     {
6458       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6459       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6460       outBitC (result);
6461     }
6462   else
6463     {
6464       tlbl = newiTempLabel (NULL);
6465       toBoolean (left);
6466       emitcode ("jnz", "%05d$", tlbl->key + 100);
6467       toBoolean (right);
6468       emitLabel (tlbl);
6469       outBitAcc (result);
6470     }
6471
6472   freeAsmop (result, NULL, ic, TRUE);
6473   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6474   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6475 }
6476
6477 /*-----------------------------------------------------------------*/
6478 /* isLiteralBit - test if lit == 2^n                               */
6479 /*-----------------------------------------------------------------*/
6480 static int
6481 isLiteralBit (unsigned long lit)
6482 {
6483   unsigned long pw[32] =
6484   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6485    0x100L, 0x200L, 0x400L, 0x800L,
6486    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6487    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6488    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6489    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6490    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6491   int idx;
6492
6493   for (idx = 0; idx < 32; idx++)
6494     if (lit == pw[idx])
6495       return idx + 1;
6496   return 0;
6497 }
6498
6499 /*-----------------------------------------------------------------*/
6500 /* continueIfTrue -                                                */
6501 /*-----------------------------------------------------------------*/
6502 static void
6503 continueIfTrue (iCode * ic)
6504 {
6505   if (IC_TRUE (ic))
6506     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6507   ic->generated = 1;
6508 }
6509
6510 /*-----------------------------------------------------------------*/
6511 /* jmpIfTrue -                                                     */
6512 /*-----------------------------------------------------------------*/
6513 static void
6514 jumpIfTrue (iCode * ic)
6515 {
6516   if (!IC_TRUE (ic))
6517     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6518   ic->generated = 1;
6519 }
6520
6521 /*-----------------------------------------------------------------*/
6522 /* jmpTrueOrFalse -                                                */
6523 /*-----------------------------------------------------------------*/
6524 static void
6525 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6526 {
6527   // ugly but optimized by peephole
6528   if (IC_TRUE (ic))
6529     {
6530       symbol *nlbl = newiTempLabel (NULL);
6531       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6532       emitLabel (tlbl);
6533       freeForBranchAsmop (result);
6534       freeForBranchAsmop (right);
6535       freeForBranchAsmop (left);
6536       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6537       emitLabel (nlbl);
6538     }
6539   else
6540     {
6541       freeForBranchAsmop (result);
6542       freeForBranchAsmop (right);
6543       freeForBranchAsmop (left);
6544       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6545       emitLabel (tlbl);
6546     }
6547   ic->generated = 1;
6548 }
6549
6550 /*-----------------------------------------------------------------*/
6551 /* genAnd  - code for and                                          */
6552 /*-----------------------------------------------------------------*/
6553 static void
6554 genAnd (iCode * ic, iCode * ifx)
6555 {
6556   operand *left, *right, *result;
6557   int size, offset = 0;
6558   unsigned long lit = 0L;
6559   int bytelit = 0;
6560   char buffer[10];
6561
6562   D (emitcode (";", "genAnd"));
6563
6564   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6565   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6566   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6567
6568 #ifdef DEBUG_TYPE
6569   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6570             AOP_TYPE (result),
6571             AOP_TYPE (left), AOP_TYPE (right));
6572   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6573             AOP_SIZE (result),
6574             AOP_SIZE (left), AOP_SIZE (right));
6575 #endif
6576
6577   /* if left is a literal & right is not then exchange them */
6578   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6579       AOP_NEEDSACC (left))
6580     {
6581       operand *tmp = right;
6582       right = left;
6583       left = tmp;
6584     }
6585
6586   /* if result = right then exchange left and right */
6587   if (sameRegs (AOP (result), AOP (right)))
6588     {
6589       operand *tmp = right;
6590       right = left;
6591       left = tmp;
6592     }
6593
6594   /* if right is bit then exchange them */
6595   if (AOP_TYPE (right) == AOP_CRY &&
6596       AOP_TYPE (left) != AOP_CRY)
6597     {
6598       operand *tmp = right;
6599       right = left;
6600       left = tmp;
6601     }
6602   if (AOP_TYPE (right) == AOP_LIT)
6603     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6604
6605   size = AOP_SIZE (result);
6606
6607   // if(bit & yy)
6608   // result = bit & yy;
6609   if (AOP_TYPE (left) == AOP_CRY)
6610     {
6611       // c = bit & literal;
6612       if (AOP_TYPE (right) == AOP_LIT)
6613         {
6614           if (lit & 1)
6615             {
6616               if (size && sameRegs (AOP (result), AOP (left)))
6617                 // no change
6618                 goto release;
6619               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6620             }
6621           else
6622             {
6623               // bit(result) = 0;
6624               if (size && (AOP_TYPE (result) == AOP_CRY))
6625                 {
6626                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6627                   goto release;
6628                 }
6629               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6630                 {
6631                   jumpIfTrue (ifx);
6632                   goto release;
6633                 }
6634               emitcode ("clr", "c");
6635             }
6636         }
6637       else
6638         {
6639           if (AOP_TYPE (right) == AOP_CRY)
6640             {
6641               // c = bit & bit;
6642               if (IS_OP_ACCUSE (left))
6643                 {
6644                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6645                 }
6646               else
6647                 {
6648                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6649                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6650                 }
6651             }
6652           else
6653             {
6654               // c = bit & val;
6655               MOVA (aopGet (right, 0, FALSE, FALSE));
6656               // c = lsb
6657               emitcode ("rrc", "a");
6658               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6659             }
6660         }
6661       // bit = c
6662       // val = c
6663       if (size)
6664         outBitC (result);
6665       // if(bit & ...)
6666       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6667         genIfxJump (ifx, "c", left, right, result);
6668       goto release;
6669     }
6670
6671   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6672   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6673   if ((AOP_TYPE (right) == AOP_LIT) &&
6674       (AOP_TYPE (result) == AOP_CRY) &&
6675       (AOP_TYPE (left) != AOP_CRY))
6676     {
6677       int posbit = isLiteralBit (lit);
6678       /* left &  2^n */
6679       if (posbit)
6680         {
6681           posbit--;
6682           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6683           // bit = left & 2^n
6684           if (size)
6685             {
6686               switch (posbit & 0x07)
6687                 {
6688                   case 0: emitcode ("rrc", "a");
6689                           break;
6690                   case 7: emitcode ("rlc", "a");
6691                           break;
6692                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6693                           break;
6694                 }
6695             }
6696           // if(left &  2^n)
6697           else
6698             {
6699               if (ifx)
6700                 {
6701                   SNPRINTF (buffer, sizeof(buffer),
6702                             "acc.%d", posbit & 0x07);
6703                   genIfxJump (ifx, buffer, left, right, result);
6704                 }
6705               else
6706                 {// what is this case? just found it in ds390/gen.c
6707                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6708                 }
6709               goto release;
6710             }
6711         }
6712       else
6713         {
6714           symbol *tlbl = newiTempLabel (NULL);
6715           int sizel = AOP_SIZE (left);
6716           if (size)
6717             emitcode ("setb", "c");
6718           while (sizel--)
6719             {
6720               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6721                 {
6722                   MOVA (aopGet (left, offset, FALSE, FALSE));
6723                   // byte ==  2^n ?
6724                   if ((posbit = isLiteralBit (bytelit)) != 0)
6725                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6726                   else
6727                     {
6728                       if (bytelit != 0x0FFL)
6729                         emitcode ("anl", "a,%s",
6730                                   aopGet (right, offset, FALSE, TRUE));
6731                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6732                     }
6733                 }
6734               offset++;
6735             }
6736           // bit = left & literal
6737           if (size)
6738             {
6739               emitcode ("clr", "c");
6740               emitLabel (tlbl);
6741             }
6742           // if(left & literal)
6743           else
6744             {
6745               if (ifx)
6746                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6747               else
6748                 emitLabel (tlbl);
6749               goto release;
6750             }
6751         }
6752       outBitC (result);
6753       goto release;
6754     }
6755
6756   /* if left is same as result */
6757   if (sameRegs (AOP (result), AOP (left)))
6758     {
6759       for (; size--; offset++)
6760         {
6761           if (AOP_TYPE (right) == AOP_LIT)
6762             {
6763               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6764               if (bytelit == 0x0FF)
6765                 {
6766                   /* dummy read of volatile operand */
6767                   if (isOperandVolatile (left, FALSE))
6768                     MOVA (aopGet (left, offset, FALSE, FALSE));
6769                   else
6770                     continue;
6771                 }
6772               else if (bytelit == 0)
6773                 {
6774                   aopPut (result, zero, offset);
6775                 }
6776               else if (IS_AOP_PREG (result))
6777                 {
6778                   MOVA (aopGet (left, offset, FALSE, TRUE));
6779                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6780                   aopPut (result, "a", offset);
6781                 }
6782               else
6783                 emitcode ("anl", "%s,%s",
6784                           aopGet (left, offset, FALSE, TRUE),
6785                           aopGet (right, offset, FALSE, FALSE));
6786             }
6787           else
6788             {
6789               if (AOP_TYPE (left) == AOP_ACC)
6790                 {
6791                   if (offset)
6792                     emitcode("mov", "a,b");
6793                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6794                 }
6795               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6796                 {
6797                   MOVB (aopGet (left, offset, FALSE, FALSE));
6798                   MOVA (aopGet (right, offset, FALSE, FALSE));
6799                   emitcode ("anl", "a,b");
6800                   aopPut (result, "a", offset);
6801                 }
6802               else if (aopGetUsesAcc (left, offset))
6803                 {
6804                   MOVA (aopGet (left, offset, FALSE, FALSE));
6805                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6806                   aopPut (result, "a", offset);
6807                 }
6808               else
6809                 {
6810                   MOVA (aopGet (right, offset, FALSE, FALSE));
6811                   if (IS_AOP_PREG (result))
6812                     {
6813                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6814                       aopPut (result, "a", offset);
6815                     }
6816                   else
6817                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6818                 }
6819             }
6820         }
6821     }
6822   else
6823     {
6824       // left & result in different registers
6825       if (AOP_TYPE (result) == AOP_CRY)
6826         {
6827           // result = bit
6828           // if(size), result in bit
6829           // if(!size && ifx), conditional oper: if(left & right)
6830           symbol *tlbl = newiTempLabel (NULL);
6831           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6832           if (size)
6833             emitcode ("setb", "c");
6834           while (sizer--)
6835             {
6836               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6837                   && AOP_TYPE(left)==AOP_ACC)
6838                 {
6839                   if (offset)
6840                     emitcode("mov", "a,b");
6841                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6842                 }
6843               else if (AOP_TYPE(left)==AOP_ACC)
6844                 {
6845                   if (!offset)
6846                     {
6847                       bool pushedB = pushB ();
6848                       emitcode("mov", "b,a");
6849                       MOVA (aopGet (right, offset, FALSE, FALSE));
6850                       emitcode("anl", "a,b");
6851                       popB (pushedB);
6852                     }
6853                   else
6854                     {
6855                       MOVA (aopGet (right, offset, FALSE, FALSE));
6856                       emitcode("anl", "a,b");
6857                     }
6858                 }
6859               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6860                 {
6861                   MOVB (aopGet (left, offset, FALSE, FALSE));
6862                   MOVA (aopGet (right, offset, FALSE, FALSE));
6863                   emitcode ("anl", "a,b");
6864                 }
6865               else if (aopGetUsesAcc (left, offset))
6866                 {
6867                   MOVA (aopGet (left, offset, FALSE, FALSE));
6868                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6869                     }
6870               else
6871                 {
6872                   MOVA (aopGet (right, offset, FALSE, FALSE));
6873                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6874                 }
6875
6876               emitcode ("jnz", "%05d$", tlbl->key + 100);
6877               offset++;
6878             }
6879           if (size)
6880             {
6881               CLRC;
6882               emitLabel (tlbl);
6883               outBitC (result);
6884             }
6885           else if (ifx)
6886             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6887           else
6888             emitLabel (tlbl);
6889         }
6890       else
6891         {
6892           for (; (size--); offset++)
6893             {
6894               // normal case
6895               // result = left & right
6896               if (AOP_TYPE (right) == AOP_LIT)
6897                 {
6898                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6899                   if (bytelit == 0x0FF)
6900                     {
6901                       aopPut (result,
6902                               aopGet (left, offset, FALSE, FALSE),
6903                               offset);
6904                       continue;
6905                     }
6906                   else if (bytelit == 0)
6907                     {
6908                       /* dummy read of volatile operand */
6909                       if (isOperandVolatile (left, FALSE))
6910                         MOVA (aopGet (left, offset, FALSE, FALSE));
6911                       aopPut (result, zero, offset);
6912                       continue;
6913                     }
6914                   else if (AOP_TYPE (left) == AOP_ACC)
6915                     {
6916                       if (!offset)
6917                         {
6918                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6919                           aopPut (result, "a", offset);
6920                           continue;
6921                         }
6922                       else
6923                         {
6924                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6925                           aopPut (result, "b", offset);
6926                           continue;
6927                         }
6928                     }
6929                 }
6930               // faster than result <- left, anl result,right
6931               // and better if result is SFR
6932               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6933                   && AOP_TYPE(left)==AOP_ACC)
6934                 {
6935                   if (offset)
6936                     emitcode("mov", "a,b");
6937                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6938                 }
6939               else if (AOP_TYPE(left)==AOP_ACC)
6940                 {
6941                   if (!offset)
6942                     {
6943                       bool pushedB = pushB ();
6944                       emitcode("mov", "b,a");
6945                       MOVA (aopGet (right, offset, FALSE, FALSE));
6946                       emitcode("anl", "a,b");
6947                       popB (pushedB);
6948                     }
6949                   else
6950                     {
6951                       MOVA (aopGet (right, offset, FALSE, FALSE));
6952                       emitcode("anl", "a,b");
6953                     }
6954                 }
6955               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6956                 {
6957                   MOVB (aopGet (left, offset, FALSE, FALSE));
6958                   MOVA (aopGet (right, offset, FALSE, FALSE));
6959                   emitcode ("anl", "a,b");
6960                 }
6961               else if (aopGetUsesAcc (left, offset))
6962                 {
6963                   MOVA (aopGet (left, offset, FALSE, FALSE));
6964                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6965                 }
6966               else
6967                 {
6968                   MOVA (aopGet (right, offset, FALSE, FALSE));
6969                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6970                 }
6971               aopPut (result, "a", offset);
6972             }
6973         }
6974     }
6975
6976 release:
6977   freeAsmop (result, NULL, ic, TRUE);
6978   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6979   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6980 }
6981
6982 /*-----------------------------------------------------------------*/
6983 /* genOr  - code for or                                            */
6984 /*-----------------------------------------------------------------*/
6985 static void
6986 genOr (iCode * ic, iCode * ifx)
6987 {
6988   operand *left, *right, *result;
6989   int size, offset = 0;
6990   unsigned long lit = 0L;
6991   int bytelit = 0;
6992
6993   D (emitcode (";", "genOr"));
6994
6995   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6996   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6997   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6998
6999 #ifdef DEBUG_TYPE
7000   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7001             AOP_TYPE (result),
7002             AOP_TYPE (left), AOP_TYPE (right));
7003   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7004             AOP_SIZE (result),
7005             AOP_SIZE (left), AOP_SIZE (right));
7006 #endif
7007
7008   /* if left is a literal & right is not then exchange them */
7009   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7010       AOP_NEEDSACC (left))
7011     {
7012       operand *tmp = right;
7013       right = left;
7014       left = tmp;
7015     }
7016
7017   /* if result = right then exchange them */
7018   if (sameRegs (AOP (result), AOP (right)))
7019     {
7020       operand *tmp = right;
7021       right = left;
7022       left = tmp;
7023     }
7024
7025   /* if right is bit then exchange them */
7026   if (AOP_TYPE (right) == AOP_CRY &&
7027       AOP_TYPE (left) != AOP_CRY)
7028     {
7029       operand *tmp = right;
7030       right = left;
7031       left = tmp;
7032     }
7033   if (AOP_TYPE (right) == AOP_LIT)
7034     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7035
7036   size = AOP_SIZE (result);
7037
7038   // if(bit | yy)
7039   // xx = bit | yy;
7040   if (AOP_TYPE (left) == AOP_CRY)
7041     {
7042       if (AOP_TYPE (right) == AOP_LIT)
7043         {
7044           // c = bit | literal;
7045           if (lit)
7046             {
7047               // lit != 0 => result = 1
7048               if (AOP_TYPE (result) == AOP_CRY)
7049                 {
7050                   if (size)
7051                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7052                   else if (ifx)
7053                     continueIfTrue (ifx);
7054                   goto release;
7055                 }
7056               emitcode ("setb", "c");
7057             }
7058           else
7059             {
7060               // lit == 0 => result = left
7061               if (size && sameRegs (AOP (result), AOP (left)))
7062                 goto release;
7063               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7064             }
7065         }
7066       else
7067         {
7068           if (AOP_TYPE (right) == AOP_CRY)
7069             {
7070               // c = bit | bit;
7071               if (IS_OP_ACCUSE (left))
7072                 {
7073                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7074                 }
7075               else
7076                 {
7077                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7078                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7079                 }
7080             }
7081           else
7082             {
7083               // c = bit | val;
7084               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7085                 {
7086                   symbol *tlbl = newiTempLabel (NULL);
7087                   emitcode ("jb", "%s,%05d$",
7088                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7089                   toBoolean (right);
7090                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7091                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7092                   goto release;
7093                 }
7094               else
7095                 {
7096                   toCarry (right);
7097                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7098                 }
7099             }
7100         }
7101       // bit = c
7102       // val = c
7103       if (size)
7104         outBitC (result);
7105       // if(bit | ...)
7106       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7107         genIfxJump (ifx, "c", left, right, result);
7108       goto release;
7109     }
7110
7111   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7112   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7113   if ((AOP_TYPE (right) == AOP_LIT) &&
7114       (AOP_TYPE (result) == AOP_CRY) &&
7115       (AOP_TYPE (left) != AOP_CRY))
7116     {
7117       if (lit)
7118         {
7119           // result = 1
7120           if (size)
7121             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7122           else
7123             continueIfTrue (ifx);
7124           goto release;
7125         }
7126       else
7127         {
7128           // lit = 0, result = boolean(left)
7129           if (size)
7130             emitcode ("setb", "c");
7131           toBoolean (right);
7132           if (size)
7133             {
7134               symbol *tlbl = newiTempLabel (NULL);
7135               emitcode ("jnz", "%05d$", tlbl->key + 100);
7136               CLRC;
7137               emitLabel (tlbl);
7138             }
7139           else
7140             {
7141               genIfxJump (ifx, "a", left, right, result);
7142               goto release;
7143             }
7144         }
7145       outBitC (result);
7146       goto release;
7147     }
7148
7149   /* if left is same as result */
7150   if (sameRegs (AOP (result), AOP (left)))
7151     {
7152       for (; size--; offset++)
7153         {
7154           if (AOP_TYPE (right) == AOP_LIT)
7155             {
7156               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7157               if (bytelit == 0)
7158                 {
7159                   /* dummy read of volatile operand */
7160                   if (isOperandVolatile (left, FALSE))
7161                     MOVA (aopGet (left, offset, FALSE, FALSE));
7162                   else
7163                     continue;
7164                 }
7165               else if (bytelit == 0x0FF)
7166                 {
7167                   aopPut (result, "#0xFF", offset);
7168                 }
7169               else if (IS_AOP_PREG (left))
7170                 {
7171                   MOVA (aopGet (left, offset, FALSE, TRUE));
7172                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7173                   aopPut (result, "a", offset);
7174                 }
7175               else
7176                 {
7177                   emitcode ("orl", "%s,%s",
7178                             aopGet (left, offset, FALSE, TRUE),
7179                             aopGet (right, offset, FALSE, FALSE));
7180                 }
7181             }
7182           else
7183             {
7184               if (AOP_TYPE (left) == AOP_ACC)
7185                 {
7186                   if (offset)
7187                     emitcode("mov", "a,b");
7188                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7189                 }
7190               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7191                 {
7192                   MOVB (aopGet (left, offset, FALSE, FALSE));
7193                   MOVA (aopGet (right, offset, FALSE, FALSE));
7194                   emitcode ("orl", "a,b");
7195                   aopPut (result, "a", offset);
7196                 }
7197               else if (aopGetUsesAcc (left, offset))
7198                 {
7199                   MOVA (aopGet (left, offset, FALSE, FALSE));
7200                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7201                   aopPut (result, "a", offset);
7202                 }
7203               else
7204                 {
7205                   MOVA (aopGet (right, offset, FALSE, FALSE));
7206                   if (IS_AOP_PREG (left))
7207                     {
7208                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7209                       aopPut (result, "a", offset);
7210                     }
7211                   else
7212                     {
7213                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7214                     }
7215                 }
7216             }
7217         }
7218     }
7219   else
7220     {
7221       // left & result in different registers
7222       if (AOP_TYPE (result) == AOP_CRY)
7223         {
7224           // result = bit
7225           // if(size), result in bit
7226           // if(!size && ifx), conditional oper: if(left | right)
7227           symbol *tlbl = newiTempLabel (NULL);
7228           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7229           if (size)
7230             emitcode ("setb", "c");
7231           while (sizer--)
7232             {
7233               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7234                   && AOP_TYPE(left)==AOP_ACC)
7235                 {
7236                   if (offset)
7237                     emitcode("mov", "a,b");
7238                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7239                 }
7240               else if (AOP_TYPE(left)==AOP_ACC)
7241                 {
7242                   if (!offset)
7243                     {
7244                       bool pushedB = pushB ();
7245                       emitcode("mov", "b,a");
7246                       MOVA (aopGet (right, offset, FALSE, FALSE));
7247                       emitcode("orl", "a,b");
7248                       popB (pushedB);
7249                     }
7250                   else
7251                     {
7252                       MOVA (aopGet (right, offset, FALSE, FALSE));
7253                       emitcode("orl", "a,b");
7254                     }
7255                 }
7256               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7257                 {
7258                   MOVB (aopGet (left, offset, FALSE, FALSE));
7259                   MOVA (aopGet (right, offset, FALSE, FALSE));
7260                   emitcode ("orl", "a,b");
7261                 }
7262               else if (aopGetUsesAcc (left, offset))
7263                 {
7264                   MOVA (aopGet (left, offset, FALSE, FALSE));
7265                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7266                 }
7267               else
7268                 {
7269                   MOVA (aopGet (right, offset, FALSE, FALSE));
7270                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7271               }
7272
7273               emitcode ("jnz", "%05d$", tlbl->key + 100);
7274               offset++;
7275             }
7276           if (size)
7277             {
7278               CLRC;
7279               emitLabel (tlbl);
7280               outBitC (result);
7281             }
7282           else if (ifx)
7283             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7284           else
7285             emitLabel (tlbl);
7286         }
7287       else
7288         {
7289           for (; (size--); offset++)
7290             {
7291               // normal case
7292               // result = left | right
7293               if (AOP_TYPE (right) == AOP_LIT)
7294                 {
7295                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7296                   if (bytelit == 0)
7297                     {
7298                       aopPut (result,
7299                               aopGet (left, offset, FALSE, FALSE),
7300                               offset);
7301                       continue;
7302                     }
7303                   else if (bytelit == 0x0FF)
7304                     {
7305                       /* dummy read of volatile operand */
7306                       if (isOperandVolatile (left, FALSE))
7307                         MOVA (aopGet (left, offset, FALSE, FALSE));
7308                       aopPut (result, "#0xFF", offset);
7309                       continue;
7310                     }
7311                 }
7312               // faster than result <- left, orl result,right
7313               // and better if result is SFR
7314               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7315                   && AOP_TYPE(left)==AOP_ACC)
7316                 {
7317                   if (offset)
7318                     emitcode("mov", "a,b");
7319                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7320                 }
7321               else if (AOP_TYPE(left)==AOP_ACC)
7322                 {
7323                   if (!offset)
7324                     {
7325                       bool pushedB = pushB ();
7326                       emitcode("mov", "b,a");
7327                       MOVA (aopGet (right, offset, FALSE, FALSE));
7328                       emitcode("orl", "a,b");
7329                       popB (pushedB);
7330                     }
7331                   else
7332                     {
7333                       MOVA (aopGet (right, offset, FALSE, FALSE));
7334                       emitcode("orl", "a,b");
7335                     }
7336                 }
7337               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7338                 {
7339                   MOVB (aopGet (left, offset, FALSE, FALSE));
7340                   MOVA (aopGet (right, offset, FALSE, FALSE));
7341                   emitcode ("orl", "a,b");
7342                 }
7343               else if (aopGetUsesAcc (left, offset))
7344                 {
7345                   MOVA (aopGet (left, offset, FALSE, FALSE));
7346                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7347                 }
7348               else
7349                 {
7350                   MOVA (aopGet (right, offset, FALSE, FALSE));
7351                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7352                 }
7353               aopPut (result, "a", offset);
7354             }
7355         }
7356     }
7357
7358 release:
7359   freeAsmop (result, NULL, ic, TRUE);
7360   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7361   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7362 }
7363
7364 /*-----------------------------------------------------------------*/
7365 /* genXor - code for xclusive or                                   */
7366 /*-----------------------------------------------------------------*/
7367 static void
7368 genXor (iCode * ic, iCode * ifx)
7369 {
7370   operand *left, *right, *result;
7371   int size, offset = 0;
7372   unsigned long lit = 0L;
7373   int bytelit = 0;
7374
7375   D (emitcode (";", "genXor"));
7376
7377   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7378   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7379   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7380
7381 #ifdef DEBUG_TYPE
7382   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7383             AOP_TYPE (result),
7384             AOP_TYPE (left), AOP_TYPE (right));
7385   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7386             AOP_SIZE (result),
7387             AOP_SIZE (left), AOP_SIZE (right));
7388 #endif
7389
7390   /* if left is a literal & right is not ||
7391      if left needs acc & right does not */
7392   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7393       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7394     {
7395       operand *tmp = right;
7396       right = left;
7397       left = tmp;
7398     }
7399
7400   /* if result = right then exchange them */
7401   if (sameRegs (AOP (result), AOP (right)))
7402     {
7403       operand *tmp = right;
7404       right = left;
7405       left = tmp;
7406     }
7407
7408   /* if right is bit then exchange them */
7409   if (AOP_TYPE (right) == AOP_CRY &&
7410       AOP_TYPE (left) != AOP_CRY)
7411     {
7412       operand *tmp = right;
7413       right = left;
7414       left = tmp;
7415     }
7416
7417   if (AOP_TYPE (right) == AOP_LIT)
7418     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7419
7420   size = AOP_SIZE (result);
7421
7422   // if(bit ^ yy)
7423   // xx = bit ^ yy;
7424   if (AOP_TYPE (left) == AOP_CRY)
7425     {
7426       if (AOP_TYPE (right) == AOP_LIT)
7427         {
7428           // c = bit & literal;
7429           if (lit >> 1)
7430             {
7431               // lit>>1  != 0 => result = 1
7432               if (AOP_TYPE (result) == AOP_CRY)
7433                 {
7434                   if (size)
7435                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7436                   else if (ifx)
7437                     continueIfTrue (ifx);
7438                   goto release;
7439                 }
7440               emitcode ("setb", "c");
7441             }
7442           else
7443             {
7444               // lit == (0 or 1)
7445               if (lit == 0)
7446                 {
7447                   // lit == 0, result = left
7448                   if (size && sameRegs (AOP (result), AOP (left)))
7449                     goto release;
7450                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7451                 }
7452               else
7453                 {
7454                   // lit == 1, result = not(left)
7455                   if (size && sameRegs (AOP (result), AOP (left)))
7456                     {
7457                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7458                       goto release;
7459                     }
7460                   else
7461                     {
7462                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7463                       emitcode ("cpl", "c");
7464                     }
7465                 }
7466             }
7467         }
7468       else
7469         {
7470           // right != literal
7471           symbol *tlbl = newiTempLabel (NULL);
7472           if (AOP_TYPE (right) == AOP_CRY)
7473             {
7474               // c = bit ^ bit;
7475               if (IS_OP_ACCUSE (left))
7476                 {// left already is in the carry
7477                   operand *tmp = right;
7478                   right = left;
7479                   left = tmp;
7480                 }
7481               else
7482                 {
7483                   toCarry (right);
7484                 }
7485             }
7486           else
7487             {
7488               // c = bit ^ val
7489               toCarry (right);
7490             }
7491           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7492           emitcode ("cpl", "c");
7493           emitLabel (tlbl);
7494         }
7495       // bit = c
7496       // val = c
7497       if (size)
7498         outBitC (result);
7499       // if(bit ^ ...)
7500       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7501         genIfxJump (ifx, "c", left, right, result);
7502       goto release;
7503     }
7504
7505   /* if left is same as result */
7506   if (sameRegs (AOP (result), AOP (left)))
7507     {
7508       for (; size--; offset++)
7509         {
7510           if (AOP_TYPE (right) == AOP_LIT)
7511             {
7512               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7513               if (bytelit == 0)
7514                 {
7515                   /* dummy read of volatile operand */
7516                   if (isOperandVolatile (left, FALSE))
7517                     MOVA (aopGet (left, offset, FALSE, FALSE));
7518                   else
7519                     continue;
7520                 }
7521               else if (IS_AOP_PREG (left))
7522                 {
7523                   MOVA (aopGet (left, offset, FALSE, TRUE));
7524                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7525                   aopPut (result, "a", offset);
7526                 }
7527               else
7528                 {
7529                   emitcode ("xrl", "%s,%s",
7530                             aopGet (left, offset, FALSE, TRUE),
7531                             aopGet (right, offset, FALSE, FALSE));
7532                 }
7533             }
7534           else
7535             {
7536               if (AOP_TYPE (left) == AOP_ACC)
7537                 {
7538                   if (offset)
7539                     emitcode("mov", "a,b");
7540                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7541                 }
7542               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7543                 {
7544                   MOVB (aopGet (left, offset, FALSE, FALSE));
7545                   MOVA (aopGet (right, offset, FALSE, FALSE));
7546                   emitcode ("xrl", "a,b");
7547                   aopPut (result, "a", offset);
7548                 }
7549               else if (aopGetUsesAcc (left, offset))
7550                 {
7551                   MOVA (aopGet (left, offset, FALSE, FALSE));
7552                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7553                   aopPut (result, "a", offset);
7554                 }
7555               else
7556                 {
7557                   MOVA (aopGet (right, offset, FALSE, FALSE));
7558                   if (IS_AOP_PREG (left))
7559                     {
7560                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7561                       aopPut (result, "a", offset);
7562                     }
7563                   else
7564                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7565                 }
7566             }
7567         }
7568     }
7569   else
7570     {
7571       // left & result in different registers
7572       if (AOP_TYPE (result) == AOP_CRY)
7573         {
7574           // result = bit
7575           // if(size), result in bit
7576           // if(!size && ifx), conditional oper: if(left ^ right)
7577           symbol *tlbl = newiTempLabel (NULL);
7578           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7579
7580           if (size)
7581             emitcode ("setb", "c");
7582           while (sizer--)
7583             {
7584               if ((AOP_TYPE (right) == AOP_LIT) &&
7585                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7586                 {
7587                   MOVA (aopGet (left, offset, FALSE, FALSE));
7588                 }
7589               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7590                   && AOP_TYPE(left)==AOP_ACC)
7591                 {
7592                   if (offset)
7593                     emitcode("mov", "a,b");
7594                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7595                 }
7596               else if (AOP_TYPE(left)==AOP_ACC)
7597                 {
7598                   if (!offset)
7599                     {
7600                       bool pushedB = pushB ();
7601                       emitcode("mov", "b,a");
7602                       MOVA (aopGet (right, offset, FALSE, FALSE));
7603                       emitcode("xrl", "a,b");
7604                       popB (pushedB);
7605                     }
7606                   else
7607                     {
7608                       MOVA (aopGet (right, offset, FALSE, FALSE));
7609                       emitcode("xrl", "a,b");
7610                     }
7611                 }
7612               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7613                 {
7614                   MOVB (aopGet (left, offset, FALSE, FALSE));
7615                   MOVA (aopGet (right, offset, FALSE, FALSE));
7616                   emitcode ("xrl", "a,b");
7617                 }
7618               else if (aopGetUsesAcc (left, offset))
7619                 {
7620                   MOVA (aopGet (left, offset, FALSE, FALSE));
7621                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7622                 }
7623               else
7624                 {
7625                   MOVA (aopGet (right, offset, FALSE, FALSE));
7626                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7627                 }
7628
7629               emitcode ("jnz", "%05d$", tlbl->key + 100);
7630               offset++;
7631             }
7632           if (size)
7633             {
7634               CLRC;
7635               emitLabel (tlbl);
7636               outBitC (result);
7637             }
7638           else if (ifx)
7639             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7640         }
7641       else
7642         {
7643           for (; (size--); offset++)
7644             {
7645               // normal case
7646               // result = left ^ right
7647               if (AOP_TYPE (right) == AOP_LIT)
7648                 {
7649                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7650                   if (bytelit == 0)
7651                     {
7652                       aopPut (result,
7653                               aopGet (left, offset, FALSE, FALSE),
7654                               offset);
7655                       continue;
7656                     }
7657                 }
7658               // faster than result <- left, xrl result,right
7659               // and better if result is SFR
7660               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7661                   && AOP_TYPE(left)==AOP_ACC)
7662                 {
7663                   if (offset)
7664                     emitcode("mov", "a,b");
7665                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7666                 }
7667               else if (AOP_TYPE(left)==AOP_ACC)
7668                 {
7669                   if (!offset)
7670                     {
7671                       bool pushedB = pushB ();
7672                       emitcode("mov", "b,a");
7673                       MOVA (aopGet (right, offset, FALSE, FALSE));
7674                       emitcode("xrl", "a,b");
7675                       popB (pushedB);
7676                     }
7677                   else
7678                     {
7679                       MOVA (aopGet (right, offset, FALSE, FALSE));
7680                       emitcode("xrl", "a,b");
7681                     }
7682                 }
7683               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7684                 {
7685                   MOVB (aopGet (left, offset, FALSE, FALSE));
7686                   MOVA (aopGet (right, offset, FALSE, FALSE));
7687                   emitcode ("xrl", "a,b");
7688                 }
7689               else if (aopGetUsesAcc (left, offset))
7690                 {
7691                   MOVA (aopGet (left, offset, FALSE, FALSE));
7692                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7693                 }
7694               else
7695                 {
7696                   MOVA (aopGet (right, offset, FALSE, FALSE));
7697                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7698                 }
7699               aopPut (result, "a", offset);
7700             }
7701         }
7702     }
7703
7704 release:
7705   freeAsmop (result, NULL, ic, TRUE);
7706   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7707   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7708 }
7709
7710 /*-----------------------------------------------------------------*/
7711 /* genInline - write the inline code out                           */
7712 /*-----------------------------------------------------------------*/
7713 static void
7714 genInline (iCode * ic)
7715 {
7716   char *buffer, *bp, *bp1;
7717   bool inComment = FALSE;
7718
7719   D (emitcode (";", "genInline"));
7720
7721   _G.inLine += (!options.asmpeep);
7722
7723   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7724
7725   /* emit each line as a code */
7726   while (*bp)
7727     {
7728       switch (*bp)
7729         {
7730         case ';':
7731           inComment = TRUE;
7732           ++bp;
7733           break;
7734
7735         case '\n':
7736           inComment = FALSE;
7737           *bp++ = '\0';
7738           emitcode (bp1, "");
7739           bp1 = bp;
7740           break;
7741
7742         default:
7743           /* Add \n for labels, not dirs such as c:\mydir */
7744           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7745             {
7746               ++bp;
7747               *bp = '\0';
7748               ++bp;
7749               emitcode (bp1, "");
7750               bp1 = bp;
7751             }
7752           else
7753             ++bp;
7754           break;
7755         }
7756     }
7757   if (bp1 != bp)
7758     emitcode (bp1, "");
7759
7760   Safe_free (buffer);
7761
7762   _G.inLine -= (!options.asmpeep);
7763 }
7764
7765 /*-----------------------------------------------------------------*/
7766 /* genRRC - rotate right with carry                                */
7767 /*-----------------------------------------------------------------*/
7768 static void
7769 genRRC (iCode * ic)
7770 {
7771   operand *left, *result;
7772   int size, offset;
7773   char *l;
7774
7775   D (emitcode (";", "genRRC"));
7776
7777   /* rotate right with carry */
7778   left = IC_LEFT (ic);
7779   result = IC_RESULT (ic);
7780   aopOp (left, ic, FALSE);
7781   aopOp (result, ic, FALSE);
7782
7783   /* move it to the result */
7784   size = AOP_SIZE (result);
7785   offset = size - 1;
7786   if (size == 1) { /* special case for 1 byte */
7787       l = aopGet (left, offset, FALSE, FALSE);
7788       MOVA (l);
7789       emitcode ("rr", "a");
7790       goto release;
7791   }
7792   /* no need to clear carry, bit7 will be written later */
7793   while (size--)
7794     {
7795       l = aopGet (left, offset, FALSE, FALSE);
7796       MOVA (l);
7797       emitcode ("rrc", "a");
7798       if (AOP_SIZE (result) > 1)
7799         aopPut (result, "a", offset--);
7800     }
7801   /* now we need to put the carry into the
7802      highest order byte of the result */
7803   if (AOP_SIZE (result) > 1)
7804     {
7805       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7806       MOVA (l);
7807     }
7808   emitcode ("mov", "acc.7,c");
7809  release:
7810   aopPut (result, "a", AOP_SIZE (result) - 1);
7811   freeAsmop (result, NULL, ic, TRUE);
7812   freeAsmop (left, NULL, ic, TRUE);
7813 }
7814
7815 /*-----------------------------------------------------------------*/
7816 /* genRLC - generate code for rotate left with carry               */
7817 /*-----------------------------------------------------------------*/
7818 static void
7819 genRLC (iCode * ic)
7820 {
7821   operand *left, *result;
7822   int size, offset;
7823   char *l;
7824
7825   D (emitcode (";", "genRLC"));
7826
7827   /* rotate right with carry */
7828   left = IC_LEFT (ic);
7829   result = IC_RESULT (ic);
7830   aopOp (left, ic, FALSE);
7831   aopOp (result, ic, FALSE);
7832
7833   /* move it to the result */
7834   size = AOP_SIZE (result);
7835   offset = 0;
7836   if (size--)
7837     {
7838       l = aopGet (left, offset, FALSE, FALSE);
7839       MOVA (l);
7840       if (size == 0) { /* special case for 1 byte */
7841               emitcode("rl","a");
7842               goto release;
7843       }
7844       emitcode("rlc","a"); /* bit0 will be written later */
7845       if (AOP_SIZE (result) > 1)
7846         {
7847           aopPut (result, "a", offset++);
7848         }
7849
7850       while (size--)
7851         {
7852           l = aopGet (left, offset, FALSE, FALSE);
7853           MOVA (l);
7854           emitcode ("rlc", "a");
7855           if (AOP_SIZE (result) > 1)
7856             aopPut (result, "a", offset++);
7857         }
7858     }
7859   /* now we need to put the carry into the
7860      highest order byte of the result */
7861   if (AOP_SIZE (result) > 1)
7862     {
7863       l = aopGet (result, 0, FALSE, FALSE);
7864       MOVA (l);
7865     }
7866   emitcode ("mov", "acc.0,c");
7867  release:
7868   aopPut (result, "a", 0);
7869   freeAsmop (result, NULL, ic, TRUE);
7870   freeAsmop (left, NULL, ic, TRUE);
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* genGetHbit - generates code get highest order bit               */
7875 /*-----------------------------------------------------------------*/
7876 static void
7877 genGetHbit (iCode * ic)
7878 {
7879   operand *left, *result;
7880
7881   D (emitcode (";", "genGetHbit"));
7882
7883   left = IC_LEFT (ic);
7884   result = IC_RESULT (ic);
7885   aopOp (left, ic, FALSE);
7886   aopOp (result, ic, FALSE);
7887
7888   /* get the highest order byte into a */
7889   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7890   if (AOP_TYPE (result) == AOP_CRY)
7891     {
7892       emitcode ("rlc", "a");
7893       outBitC (result);
7894     }
7895   else
7896     {
7897       emitcode ("rl", "a");
7898       emitcode ("anl", "a,#0x01");
7899       outAcc (result);
7900     }
7901
7902   freeAsmop (result, NULL, ic, TRUE);
7903   freeAsmop (left, NULL, ic, TRUE);
7904 }
7905
7906 /*-----------------------------------------------------------------*/
7907 /* genGetAbit - generates code get a single bit                    */
7908 /*-----------------------------------------------------------------*/
7909 static void
7910 genGetAbit (iCode * ic)
7911 {
7912   operand *left, *right, *result;
7913   int shCount;
7914
7915   D (emitcode (";", "genGetAbit"));
7916
7917   left = IC_LEFT (ic);
7918   right = IC_RIGHT (ic);
7919   result = IC_RESULT (ic);
7920   aopOp (left, ic, FALSE);
7921   aopOp (right, ic, FALSE);
7922   aopOp (result, ic, FALSE);
7923
7924   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7925
7926   /* get the needed byte into a */
7927   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7928   shCount %= 8;
7929   if (AOP_TYPE (result) == AOP_CRY)
7930     {
7931       if ((shCount) == 7)
7932           emitcode ("rlc", "a");
7933       else if ((shCount) == 0)
7934           emitcode ("rrc", "a");
7935       else
7936           emitcode ("mov", "c,acc[%d]", shCount);
7937       outBitC (result);
7938     }
7939   else
7940     {
7941       switch (shCount)
7942         {
7943         case 2:
7944           emitcode ("rr", "a");
7945           //fallthrough
7946         case 1:
7947           emitcode ("rr", "a");
7948           //fallthrough
7949         case 0:
7950           emitcode ("anl", "a,#0x01");
7951           break;
7952         case 3:
7953         case 5:
7954           emitcode ("mov", "c,acc[%d]", shCount);
7955           emitcode ("clr", "a");
7956           emitcode ("rlc", "a");
7957           break;
7958         case 4:
7959           emitcode ("swap", "a");
7960           emitcode ("anl", "a,#0x01");
7961           break;
7962         case 6:
7963           emitcode ("rl", "a");
7964           //fallthrough
7965         case 7:
7966           emitcode ("rl", "a");
7967           emitcode ("anl", "a,#0x01");
7968           break;
7969         }
7970       outAcc (result);
7971     }
7972
7973   freeAsmop (result, NULL, ic, TRUE);
7974   freeAsmop (right, NULL, ic, TRUE);
7975   freeAsmop (left, NULL, ic, TRUE);
7976 }
7977
7978 /*-----------------------------------------------------------------*/
7979 /* genGetByte - generates code get a single byte                   */
7980 /*-----------------------------------------------------------------*/
7981 static void
7982 genGetByte (iCode * ic)
7983 {
7984   operand *left, *right, *result;
7985   int offset;
7986
7987   D (emitcode (";", "genGetByte"));
7988
7989   left = IC_LEFT (ic);
7990   right = IC_RIGHT (ic);
7991   result = IC_RESULT (ic);
7992   aopOp (left, ic, FALSE);
7993   aopOp (right, ic, FALSE);
7994   aopOp (result, ic, FALSE);
7995
7996   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
7997   aopPut (result,
7998           aopGet (left, offset, FALSE, FALSE),
7999           0);
8000
8001   freeAsmop (result, NULL, ic, TRUE);
8002   freeAsmop (right, NULL, ic, TRUE);
8003   freeAsmop (left, NULL, ic, TRUE);
8004 }
8005
8006 /*-----------------------------------------------------------------*/
8007 /* genGetWord - generates code get two bytes                       */
8008 /*-----------------------------------------------------------------*/
8009 static void
8010 genGetWord (iCode * ic)
8011 {
8012   operand *left, *right, *result;
8013   int offset;
8014
8015   D (emitcode (";", "genGetWord"));
8016
8017   left = IC_LEFT (ic);
8018   right = IC_RIGHT (ic);
8019   result = IC_RESULT (ic);
8020   aopOp (left, ic, FALSE);
8021   aopOp (right, ic, FALSE);
8022   aopOp (result, ic, FALSE);
8023
8024   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8025   aopPut (result,
8026           aopGet (left, offset, FALSE, FALSE),
8027           0);
8028   aopPut (result,
8029           aopGet (left, offset+1, FALSE, FALSE),
8030           1);
8031
8032   freeAsmop (result, NULL, ic, TRUE);
8033   freeAsmop (right, NULL, ic, TRUE);
8034   freeAsmop (left, NULL, ic, TRUE);
8035 }
8036
8037 /*-----------------------------------------------------------------*/
8038 /* genSwap - generates code to swap nibbles or bytes               */
8039 /*-----------------------------------------------------------------*/
8040 static void
8041 genSwap (iCode * ic)
8042 {
8043   operand *left, *result;
8044
8045   D(emitcode (";", "genSwap"));
8046
8047   left = IC_LEFT (ic);
8048   result = IC_RESULT (ic);
8049   aopOp (left, ic, FALSE);
8050   aopOp (result, ic, FALSE);
8051
8052   switch (AOP_SIZE (left))
8053     {
8054     case 1: /* swap nibbles in byte */
8055       MOVA (aopGet (left, 0, FALSE, FALSE));
8056       emitcode ("swap", "a");
8057       aopPut (result, "a", 0);
8058       break;
8059     case 2: /* swap bytes in word */
8060       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8061         {
8062           MOVA (aopGet (left, 0, FALSE, FALSE));
8063           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8064           aopPut (result, "a", 1);
8065         }
8066       else if (operandsEqu (left, result))
8067         {
8068           char * reg = "a";
8069           bool pushedB = FALSE, leftInB = FALSE;
8070
8071           MOVA (aopGet (left, 0, FALSE, FALSE));
8072           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8073             {
8074               pushedB = pushB ();
8075               emitcode ("mov", "b,a");
8076               reg = "b";
8077               leftInB = TRUE;
8078             }
8079           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8080           aopPut (result, reg, 1);
8081
8082           if (leftInB)
8083             popB (pushedB);
8084         }
8085       else
8086         {
8087           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8088           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8089         }
8090       break;
8091     default:
8092       wassertl(FALSE, "unsupported SWAP operand size");
8093     }
8094
8095   freeAsmop (result, NULL, ic, TRUE);
8096   freeAsmop (left, NULL, ic, TRUE);
8097 }
8098
8099 /*-----------------------------------------------------------------*/
8100 /* AccRol - rotate left accumulator by known count                 */
8101 /*-----------------------------------------------------------------*/
8102 static void
8103 AccRol (int shCount)
8104 {
8105   shCount &= 0x0007;            // shCount : 0..7
8106
8107   switch (shCount)
8108     {
8109     case 0:
8110       break;
8111     case 1:
8112       emitcode ("rl", "a");
8113       break;
8114     case 2:
8115       emitcode ("rl", "a");
8116       emitcode ("rl", "a");
8117       break;
8118     case 3:
8119       emitcode ("swap", "a");
8120       emitcode ("rr", "a");
8121       break;
8122     case 4:
8123       emitcode ("swap", "a");
8124       break;
8125     case 5:
8126       emitcode ("swap", "a");
8127       emitcode ("rl", "a");
8128       break;
8129     case 6:
8130       emitcode ("rr", "a");
8131       emitcode ("rr", "a");
8132       break;
8133     case 7:
8134       emitcode ("rr", "a");
8135       break;
8136     }
8137 }
8138
8139 /*-----------------------------------------------------------------*/
8140 /* AccLsh - left shift accumulator by known count                  */
8141 /*-----------------------------------------------------------------*/
8142 static void
8143 AccLsh (int shCount)
8144 {
8145   if (shCount != 0)
8146     {
8147       if (shCount == 1)
8148         emitcode ("add", "a,acc");
8149       else if (shCount == 2)
8150         {
8151           emitcode ("add", "a,acc");
8152           emitcode ("add", "a,acc");
8153         }
8154       else
8155         {
8156           /* rotate left accumulator */
8157           AccRol (shCount);
8158           /* and kill the lower order bits */
8159           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8160         }
8161     }
8162 }
8163
8164 /*-----------------------------------------------------------------*/
8165 /* AccRsh - right shift accumulator by known count                 */
8166 /*-----------------------------------------------------------------*/
8167 static void
8168 AccRsh (int shCount)
8169 {
8170   if (shCount != 0)
8171     {
8172       if (shCount == 1)
8173         {
8174           CLRC;
8175           emitcode ("rrc", "a");
8176         }
8177       else
8178         {
8179           /* rotate right accumulator */
8180           AccRol (8 - shCount);
8181           /* and kill the higher order bits */
8182           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8183         }
8184     }
8185 }
8186
8187 /*-----------------------------------------------------------------*/
8188 /* AccSRsh - signed right shift accumulator by known count                 */
8189 /*-----------------------------------------------------------------*/
8190 static void
8191 AccSRsh (int shCount)
8192 {
8193   symbol *tlbl;
8194   if (shCount != 0)
8195     {
8196       if (shCount == 1)
8197         {
8198           emitcode ("mov", "c,acc.7");
8199           emitcode ("rrc", "a");
8200         }
8201       else if (shCount == 2)
8202         {
8203           emitcode ("mov", "c,acc.7");
8204           emitcode ("rrc", "a");
8205           emitcode ("mov", "c,acc.7");
8206           emitcode ("rrc", "a");
8207         }
8208       else
8209         {
8210           tlbl = newiTempLabel (NULL);
8211           /* rotate right accumulator */
8212           AccRol (8 - shCount);
8213           /* and kill the higher order bits */
8214           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8215           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8216           emitcode ("orl", "a,#0x%02x",
8217                     (unsigned char) ~SRMask[shCount]);
8218           emitLabel (tlbl);
8219         }
8220     }
8221 }
8222
8223 /*-----------------------------------------------------------------*/
8224 /* shiftR1Left2Result - shift right one byte from left to result   */
8225 /*-----------------------------------------------------------------*/
8226 static void
8227 shiftR1Left2Result (operand * left, int offl,
8228                     operand * result, int offr,
8229                     int shCount, int sign)
8230 {
8231   MOVA (aopGet (left, offl, FALSE, FALSE));
8232   /* shift right accumulator */
8233   if (sign)
8234     AccSRsh (shCount);
8235   else
8236     AccRsh (shCount);
8237   aopPut (result, "a", offr);
8238 }
8239
8240 /*-----------------------------------------------------------------*/
8241 /* shiftL1Left2Result - shift left one byte from left to result    */
8242 /*-----------------------------------------------------------------*/
8243 static void
8244 shiftL1Left2Result (operand * left, int offl,
8245                     operand * result, int offr, int shCount)
8246 {
8247   char *l;
8248   l = aopGet (left, offl, FALSE, FALSE);
8249   MOVA (l);
8250   /* shift left accumulator */
8251   AccLsh (shCount);
8252   aopPut (result, "a", offr);
8253 }
8254
8255 /*-----------------------------------------------------------------*/
8256 /* movLeft2Result - move byte from left to result                  */
8257 /*-----------------------------------------------------------------*/
8258 static void
8259 movLeft2Result (operand * left, int offl,
8260                 operand * result, int offr, int sign)
8261 {
8262   char *l;
8263   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8264     {
8265       l = aopGet (left, offl, FALSE, FALSE);
8266
8267       if (*l == '@' && (IS_AOP_PREG (result)))
8268         {
8269           emitcode ("mov", "a,%s", l);
8270           aopPut (result, "a", offr);
8271         }
8272       else
8273         {
8274           if (!sign)
8275             {
8276               aopPut (result, l, offr);
8277             }
8278           else
8279             {
8280               /* MSB sign in acc.7 ! */
8281               if (getDataSize (left) == offl + 1)
8282                 {
8283                   MOVA (l);
8284                   aopPut (result, "a", offr);
8285                 }
8286             }
8287         }
8288     }
8289 }
8290
8291 /*-----------------------------------------------------------------*/
8292 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8293 /*-----------------------------------------------------------------*/
8294 static void
8295 AccAXRrl1 (char *x)
8296 {
8297   emitcode ("rrc", "a");
8298   emitcode ("xch", "a,%s", x);
8299   emitcode ("rrc", "a");
8300   emitcode ("xch", "a,%s", x);
8301 }
8302
8303 /*-----------------------------------------------------------------*/
8304 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8305 /*-----------------------------------------------------------------*/
8306 static void
8307 AccAXLrl1 (char *x)
8308 {
8309   emitcode ("xch", "a,%s", x);
8310   emitcode ("rlc", "a");
8311   emitcode ("xch", "a,%s", x);
8312   emitcode ("rlc", "a");
8313 }
8314
8315 /*-----------------------------------------------------------------*/
8316 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8317 /*-----------------------------------------------------------------*/
8318 static void
8319 AccAXLsh1 (char *x)
8320 {
8321   emitcode ("xch", "a,%s", x);
8322   emitcode ("add", "a,acc");
8323   emitcode ("xch", "a,%s", x);
8324   emitcode ("rlc", "a");
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8329 /*-----------------------------------------------------------------*/
8330 static void
8331 AccAXLsh (char *x, int shCount)
8332 {
8333   switch (shCount)
8334     {
8335     case 0:
8336       break;
8337     case 1:
8338       AccAXLsh1 (x);
8339       break;
8340     case 2:
8341       AccAXLsh1 (x);
8342       AccAXLsh1 (x);
8343       break;
8344     case 3:
8345     case 4:
8346     case 5:                     // AAAAABBB:CCCCCDDD
8347
8348       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8349
8350       emitcode ("anl", "a,#0x%02x",
8351                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8352
8353       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8354
8355       AccRol (shCount);         // DDDCCCCC:BBB00000
8356
8357       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8358
8359       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8360
8361       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8362
8363       emitcode ("anl", "a,#0x%02x",
8364                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8365
8366       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8367
8368       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8369
8370       break;
8371     case 6:                     // AAAAAABB:CCCCCCDD
8372       emitcode ("anl", "a,#0x%02x",
8373                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8374       emitcode ("mov", "c,acc.0");      // c = B
8375       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8376 #if 0 // REMOVE ME
8377       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8378       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8379 #else
8380       emitcode("rrc","a");
8381       emitcode("xch","a,%s", x);
8382       emitcode("rrc","a");
8383       emitcode("mov","c,acc.0"); //<< get correct bit
8384       emitcode("xch","a,%s", x);
8385
8386       emitcode("rrc","a");
8387       emitcode("xch","a,%s", x);
8388       emitcode("rrc","a");
8389       emitcode("xch","a,%s", x);
8390 #endif
8391       break;
8392     case 7:                     // a:x <<= 7
8393
8394       emitcode ("anl", "a,#0x%02x",
8395                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8396
8397       emitcode ("mov", "c,acc.0");      // c = B
8398
8399       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8400
8401       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8402
8403       break;
8404     default:
8405       break;
8406     }
8407 }
8408
8409 /*-----------------------------------------------------------------*/
8410 /* AccAXRsh - right shift a:x known count (0..7)                   */
8411 /*-----------------------------------------------------------------*/
8412 static void
8413 AccAXRsh (char *x, int shCount)
8414 {
8415   switch (shCount)
8416     {
8417     case 0:
8418       break;
8419     case 1:
8420       CLRC;
8421       AccAXRrl1 (x);            // 0->a:x
8422
8423       break;
8424     case 2:
8425       CLRC;
8426       AccAXRrl1 (x);            // 0->a:x
8427
8428       CLRC;
8429       AccAXRrl1 (x);            // 0->a:x
8430
8431       break;
8432     case 3:
8433     case 4:
8434     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8435
8436       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8437
8438       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8439
8440       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8441
8442       emitcode ("anl", "a,#0x%02x",
8443                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8444
8445       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8446
8447       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8448
8449       emitcode ("anl", "a,#0x%02x",
8450                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8451
8452       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8453
8454       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8455
8456       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8457
8458       break;
8459     case 6:                     // AABBBBBB:CCDDDDDD
8460
8461       emitcode ("mov", "c,acc.7");
8462       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8463
8464       emitcode ("mov", "c,acc.7");
8465       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8466
8467       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8468
8469       emitcode ("anl", "a,#0x%02x",
8470                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8471
8472       break;
8473     case 7:                     // ABBBBBBB:CDDDDDDD
8474
8475       emitcode ("mov", "c,acc.7");      // c = A
8476
8477       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8478
8479       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8480
8481       emitcode ("anl", "a,#0x%02x",
8482                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8483
8484       break;
8485     default:
8486       break;
8487     }
8488 }
8489
8490 /*-----------------------------------------------------------------*/
8491 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8492 /*-----------------------------------------------------------------*/
8493 static void
8494 AccAXRshS (char *x, int shCount)
8495 {
8496   symbol *tlbl;
8497   switch (shCount)
8498     {
8499     case 0:
8500       break;
8501     case 1:
8502       emitcode ("mov", "c,acc.7");
8503       AccAXRrl1 (x);            // s->a:x
8504
8505       break;
8506     case 2:
8507       emitcode ("mov", "c,acc.7");
8508       AccAXRrl1 (x);            // s->a:x
8509
8510       emitcode ("mov", "c,acc.7");
8511       AccAXRrl1 (x);            // s->a:x
8512
8513       break;
8514     case 3:
8515     case 4:
8516     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8517
8518       tlbl = newiTempLabel (NULL);
8519       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8520
8521       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8522
8523       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8524
8525       emitcode ("anl", "a,#0x%02x",
8526                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8527
8528       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8529
8530       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8531
8532       emitcode ("anl", "a,#0x%02x",
8533                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8534
8535       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8536
8537       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8538
8539       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8540
8541       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8542       emitcode ("orl", "a,#0x%02x",
8543                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8544
8545       emitLabel (tlbl);
8546       break;                    // SSSSAAAA:BBBCCCCC
8547
8548     case 6:                     // AABBBBBB:CCDDDDDD
8549
8550       tlbl = newiTempLabel (NULL);
8551       emitcode ("mov", "c,acc.7");
8552       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8553
8554       emitcode ("mov", "c,acc.7");
8555       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8556
8557       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8558
8559       emitcode ("anl", "a,#0x%02x",
8560                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8561
8562       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8563       emitcode ("orl", "a,#0x%02x",
8564                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8565
8566       emitLabel (tlbl);
8567       break;
8568     case 7:                     // ABBBBBBB:CDDDDDDD
8569
8570       tlbl = newiTempLabel (NULL);
8571       emitcode ("mov", "c,acc.7");      // c = A
8572
8573       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8574
8575       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8576
8577       emitcode ("anl", "a,#0x%02x",
8578                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8579
8580       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8581       emitcode ("orl", "a,#0x%02x",
8582                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8583
8584       emitLabel (tlbl);
8585       break;
8586     default:
8587       break;
8588     }
8589 }
8590
8591 /*-----------------------------------------------------------------*/
8592 /* shiftL2Left2Result - shift left two bytes from left to result   */
8593 /*-----------------------------------------------------------------*/
8594 static void
8595 shiftL2Left2Result (operand * left, int offl,
8596                     operand * result, int offr, int shCount)
8597 {
8598   char * x;
8599   bool pushedB = FALSE;
8600   bool usedB = FALSE;
8601
8602   if (sameRegs (AOP (result), AOP (left)) &&
8603       ((offl + MSB16) == offr))
8604     {
8605       /* don't crash result[offr] */
8606       MOVA (aopGet (left, offl, FALSE, FALSE));
8607       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8608       usedB = !strncmp(x, "b", 1);
8609     }
8610   else if (aopGetUsesAcc (result, offr))
8611     {
8612       movLeft2Result (left, offl, result, offr, 0);
8613       pushedB = pushB ();
8614       usedB = TRUE;
8615       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8616       MOVA (aopGet (result, offr, FALSE, FALSE));
8617       emitcode ("xch", "a,b");
8618       x = "b";
8619     }
8620   else
8621     {
8622       movLeft2Result (left, offl, result, offr, 0);
8623       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8624       x = aopGet (result, offr, FALSE, FALSE);
8625     }
8626   /* ax << shCount (x = lsb(result)) */
8627   AccAXLsh (x, shCount);
8628   if (usedB)
8629     {
8630       emitcode ("xch", "a,b");
8631       aopPut (result, "a", offr);
8632       aopPut (result, "b", offr + MSB16);
8633       popB (pushedB);
8634     }
8635   else
8636     {
8637       aopPut (result, "a", offr + MSB16);
8638     }
8639 }
8640
8641
8642 /*-----------------------------------------------------------------*/
8643 /* shiftR2Left2Result - shift right two bytes from left to result  */
8644 /*-----------------------------------------------------------------*/
8645 static void
8646 shiftR2Left2Result (operand * left, int offl,
8647                     operand * result, int offr,
8648                     int shCount, int sign)
8649 {
8650   char * x;
8651   bool pushedB = FALSE;
8652   bool usedB = FALSE;
8653
8654   if (sameRegs (AOP (result), AOP (left)) &&
8655       ((offl + MSB16) == offr))
8656     {
8657       /* don't crash result[offr] */
8658       MOVA (aopGet (left, offl, FALSE, FALSE));
8659       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8660       usedB = !strncmp(x, "b", 1);
8661     }
8662   else if (aopGetUsesAcc (result, offr))
8663     {
8664       movLeft2Result (left, offl, result, offr, 0);
8665       pushedB = pushB ();
8666       usedB = TRUE;
8667       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8668       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8669       x = "b";
8670     }
8671   else
8672     {
8673       movLeft2Result (left, offl, result, offr, 0);
8674       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8675       x = aopGet (result, offr, FALSE, FALSE);
8676     }
8677   /* a:x >> shCount (x = lsb(result)) */
8678   if (sign)
8679     AccAXRshS (x, shCount);
8680   else
8681     AccAXRsh (x, shCount);
8682   if (usedB)
8683     {
8684       emitcode ("xch", "a,b");
8685       aopPut (result, "a", offr);
8686       emitcode ("xch", "a,b");
8687       popB (pushedB);
8688     }
8689   if (getDataSize (result) > 1)
8690     aopPut (result, "a", offr + MSB16);
8691 }
8692
8693 /*-----------------------------------------------------------------*/
8694 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8695 /*-----------------------------------------------------------------*/
8696 static void
8697 shiftLLeftOrResult (operand * left, int offl,
8698                     operand * result, int offr, int shCount)
8699 {
8700   MOVA (aopGet (left, offl, FALSE, FALSE));
8701   /* shift left accumulator */
8702   AccLsh (shCount);
8703   /* or with result */
8704   if (aopGetUsesAcc (result, offr))
8705     {
8706       emitcode ("xch", "a,b");
8707       MOVA (aopGet (result, offr, FALSE, FALSE));
8708       emitcode ("orl", "a,b");
8709     }
8710   else
8711     {
8712       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8713     }
8714   /* back to result */
8715   aopPut (result, "a", offr);
8716 }
8717
8718 /*-----------------------------------------------------------------*/
8719 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8720 /*-----------------------------------------------------------------*/
8721 static void
8722 shiftRLeftOrResult (operand * left, int offl,
8723                     operand * result, int offr, int shCount)
8724 {
8725   MOVA (aopGet (left, offl, FALSE, FALSE));
8726   /* shift right accumulator */
8727   AccRsh (shCount);
8728   /* or with result */
8729   if (aopGetUsesAcc(result, offr))
8730     {
8731       emitcode ("xch", "a,b");
8732       MOVA (aopGet (result, offr, FALSE, FALSE));
8733       emitcode ("orl", "a,b");
8734     }
8735   else
8736     {
8737       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8738     }
8739   /* back to result */
8740   aopPut (result, "a", offr);
8741 }
8742
8743 /*-----------------------------------------------------------------*/
8744 /* genlshOne - left shift a one byte quantity by known count       */
8745 /*-----------------------------------------------------------------*/
8746 static void
8747 genlshOne (operand * result, operand * left, int shCount)
8748 {
8749   D (emitcode (";", "genlshOne"));
8750
8751   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8752 }
8753
8754 /*-----------------------------------------------------------------*/
8755 /* genlshTwo - left shift two bytes by known amount != 0           */
8756 /*-----------------------------------------------------------------*/
8757 static void
8758 genlshTwo (operand * result, operand * left, int shCount)
8759 {
8760   int size;
8761
8762   D (emitcode (";", "genlshTwo"));
8763
8764   size = getDataSize (result);
8765
8766   /* if shCount >= 8 */
8767   if (shCount >= 8)
8768     {
8769       shCount -= 8;
8770
8771       if (size > 1)
8772         {
8773           if (shCount)
8774             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8775           else
8776             movLeft2Result (left, LSB, result, MSB16, 0);
8777         }
8778       aopPut (result, zero, LSB);
8779     }
8780
8781   /*  1 <= shCount <= 7 */
8782   else
8783     {
8784       if (size == 1)
8785         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8786       else
8787         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8788     }
8789 }
8790
8791 /*-----------------------------------------------------------------*/
8792 /* shiftLLong - shift left one long from left to result            */
8793 /* offl = LSB or MSB16                                             */
8794 /*-----------------------------------------------------------------*/
8795 static void
8796 shiftLLong (operand * left, operand * result, int offr)
8797 {
8798   char *l;
8799   int size = AOP_SIZE (result);
8800
8801   if (size >= LSB + offr)
8802     {
8803       l = aopGet (left, LSB, FALSE, FALSE);
8804       MOVA (l);
8805       emitcode ("add", "a,acc");
8806       if (sameRegs (AOP (left), AOP (result)) &&
8807           size >= MSB16 + offr && offr != LSB)
8808         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8809       else
8810         aopPut (result, "a", LSB + offr);
8811     }
8812
8813   if (size >= MSB16 + offr)
8814     {
8815       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8816         {
8817           l = aopGet (left, MSB16, FALSE, FALSE);
8818           MOVA (l);
8819         }
8820       emitcode ("rlc", "a");
8821       if (sameRegs (AOP (left), AOP (result)) &&
8822           size >= MSB24 + offr && offr != LSB)
8823         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8824       else
8825         aopPut (result, "a", MSB16 + offr);
8826     }
8827
8828   if (size >= MSB24 + offr)
8829     {
8830       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8831         {
8832           l = aopGet (left, MSB24, FALSE, FALSE);
8833           MOVA (l);
8834         }
8835       emitcode ("rlc", "a");
8836       if (sameRegs (AOP (left), AOP (result)) &&
8837           size >= MSB32 + offr && offr != LSB)
8838         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8839       else
8840         aopPut (result, "a", MSB24 + offr);
8841     }
8842
8843   if (size > MSB32 + offr)
8844     {
8845       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8846         {
8847           l = aopGet (left, MSB32, FALSE, FALSE);
8848           MOVA (l);
8849         }
8850       emitcode ("rlc", "a");
8851       aopPut (result, "a", MSB32 + offr);
8852     }
8853   if (offr != LSB)
8854     aopPut (result, zero, LSB);
8855 }
8856
8857 /*-----------------------------------------------------------------*/
8858 /* genlshFour - shift four byte by a known amount != 0             */
8859 /*-----------------------------------------------------------------*/
8860 static void
8861 genlshFour (operand * result, operand * left, int shCount)
8862 {
8863   int size;
8864
8865   D (emitcode (";", "genlshFour"));
8866
8867   size = AOP_SIZE (result);
8868
8869   /* if shifting more that 3 bytes */
8870   if (shCount >= 24)
8871     {
8872       shCount -= 24;
8873       if (shCount)
8874         /* lowest order of left goes to the highest
8875            order of the destination */
8876         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8877       else
8878         movLeft2Result (left, LSB, result, MSB32, 0);
8879       aopPut (result, zero, LSB);
8880       aopPut (result, zero, MSB16);
8881       aopPut (result, zero, MSB24);
8882       return;
8883     }
8884
8885   /* more than two bytes */
8886   else if (shCount >= 16)
8887     {
8888       /* lower order two bytes goes to higher order two bytes */
8889       shCount -= 16;
8890       /* if some more remaining */
8891       if (shCount)
8892         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8893       else
8894         {
8895           movLeft2Result (left, MSB16, result, MSB32, 0);
8896           movLeft2Result (left, LSB, result, MSB24, 0);
8897         }
8898       aopPut (result, zero, MSB16);
8899       aopPut (result, zero, LSB);
8900       return;
8901     }
8902
8903   /* if more than 1 byte */
8904   else if (shCount >= 8)
8905     {
8906       /* lower order three bytes goes to higher order  three bytes */
8907       shCount -= 8;
8908       if (size == 2)
8909         {
8910           if (shCount)
8911             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8912           else
8913             movLeft2Result (left, LSB, result, MSB16, 0);
8914         }
8915       else
8916         {                       /* size = 4 */
8917           if (shCount == 0)
8918             {
8919               movLeft2Result (left, MSB24, result, MSB32, 0);
8920               movLeft2Result (left, MSB16, result, MSB24, 0);
8921               movLeft2Result (left, LSB, result, MSB16, 0);
8922               aopPut (result, zero, LSB);
8923             }
8924           else if (shCount == 1)
8925             shiftLLong (left, result, MSB16);
8926           else
8927             {
8928               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8929               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8930               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8931               aopPut (result, zero, LSB);
8932             }
8933         }
8934     }
8935
8936   /* 1 <= shCount <= 7 */
8937   else if (shCount <= 2)
8938     {
8939       shiftLLong (left, result, LSB);
8940       if (shCount == 2)
8941         shiftLLong (result, result, LSB);
8942     }
8943   /* 3 <= shCount <= 7, optimize */
8944   else
8945     {
8946       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8947       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8948       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8949     }
8950 }
8951
8952 /*-----------------------------------------------------------------*/
8953 /* genLeftShiftLiteral - left shifting by known count              */
8954 /*-----------------------------------------------------------------*/
8955 static void
8956 genLeftShiftLiteral (operand * left,
8957                      operand * right,
8958                      operand * result,
8959                      iCode * ic)
8960 {
8961   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8962   int size;
8963
8964   D (emitcode (";", "genLeftShiftLiteral"));
8965
8966   freeAsmop (right, NULL, ic, TRUE);
8967
8968   aopOp (left, ic, FALSE);
8969   aopOp (result, ic, FALSE);
8970
8971   size = getSize (operandType (result));
8972
8973 #if VIEW_SIZE
8974   emitcode ("; shift left ", "result %d, left %d", size,
8975             AOP_SIZE (left));
8976 #endif
8977
8978   /* I suppose that the left size >= result size */
8979   if (shCount == 0)
8980     {
8981       while (size--)
8982         {
8983           movLeft2Result (left, size, result, size, 0);
8984         }
8985     }
8986   else if (shCount >= (size * 8))
8987     {
8988       while (size--)
8989         {
8990           aopPut (result, zero, size);
8991         }
8992     }
8993   else
8994     {
8995       switch (size)
8996         {
8997         case 1:
8998           genlshOne (result, left, shCount);
8999           break;
9000
9001         case 2:
9002           genlshTwo (result, left, shCount);
9003           break;
9004
9005         case 4:
9006           genlshFour (result, left, shCount);
9007           break;
9008         default:
9009           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9010                   "*** ack! mystery literal shift!\n");
9011           break;
9012         }
9013     }
9014   freeAsmop (result, NULL, ic, TRUE);
9015   freeAsmop (left, NULL, ic, TRUE);
9016 }
9017
9018 /*-----------------------------------------------------------------*/
9019 /* genLeftShift - generates code for left shifting                 */
9020 /*-----------------------------------------------------------------*/
9021 static void
9022 genLeftShift (iCode * ic)
9023 {
9024   operand *left, *right, *result;
9025   int size, offset;
9026   char *l;
9027   symbol *tlbl, *tlbl1;
9028   bool pushedB;
9029
9030   D (emitcode (";", "genLeftShift"));
9031
9032   right = IC_RIGHT (ic);
9033   left = IC_LEFT (ic);
9034   result = IC_RESULT (ic);
9035
9036   aopOp (right, ic, FALSE);
9037
9038   /* if the shift count is known then do it
9039      as efficiently as possible */
9040   if (AOP_TYPE (right) == AOP_LIT)
9041     {
9042       genLeftShiftLiteral (left, right, result, ic);
9043       return;
9044     }
9045
9046   /* shift count is unknown then we have to form
9047      a loop get the loop count in B : Note: we take
9048      only the lower order byte since shifting
9049      more that 32 bits make no sense anyway, ( the
9050      largest size of an object can be only 32 bits ) */
9051
9052   pushedB = pushB ();
9053   MOVB (aopGet (right, 0, FALSE, FALSE));
9054   emitcode ("inc", "b");
9055   freeAsmop (right, NULL, ic, TRUE);
9056   aopOp (left, ic, FALSE);
9057   aopOp (result, ic, FALSE);
9058
9059   /* now move the left to the result if they are not the same */
9060   if (!sameRegs (AOP (left), AOP (result)) &&
9061       AOP_SIZE (result) > 1)
9062     {
9063
9064       size = AOP_SIZE (result);
9065       offset = 0;
9066       while (size--)
9067         {
9068           l = aopGet (left, offset, FALSE, TRUE);
9069           if (*l == '@' && (IS_AOP_PREG (result)))
9070             {
9071
9072               emitcode ("mov", "a,%s", l);
9073               aopPut (result, "a", offset);
9074             }
9075           else
9076             aopPut (result, l, offset);
9077           offset++;
9078         }
9079     }
9080
9081   tlbl = newiTempLabel (NULL);
9082   size = AOP_SIZE (result);
9083   offset = 0;
9084   tlbl1 = newiTempLabel (NULL);
9085
9086   /* if it is only one byte then */
9087   if (size == 1)
9088     {
9089       symbol *tlbl1 = newiTempLabel (NULL);
9090
9091       l = aopGet (left, 0, FALSE, FALSE);
9092       MOVA (l);
9093       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9094       emitLabel (tlbl);
9095       emitcode ("add", "a,acc");
9096       emitLabel (tlbl1);
9097       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9098       popB (pushedB);
9099       aopPut (result, "a", 0);
9100       goto release;
9101     }
9102
9103   reAdjustPreg (AOP (result));
9104
9105   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9106   emitLabel (tlbl);
9107   l = aopGet (result, offset, FALSE, FALSE);
9108   MOVA (l);
9109   emitcode ("add", "a,acc");
9110   aopPut (result, "a", offset++);
9111   while (--size)
9112     {
9113       l = aopGet (result, offset, FALSE, FALSE);
9114       MOVA (l);
9115       emitcode ("rlc", "a");
9116       aopPut (result, "a", offset++);
9117     }
9118   reAdjustPreg (AOP (result));
9119
9120   emitLabel (tlbl1);
9121   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9122   popB (pushedB);
9123 release:
9124   freeAsmop (result, NULL, ic, TRUE);
9125   freeAsmop (left, NULL, ic, TRUE);
9126 }
9127
9128 /*-----------------------------------------------------------------*/
9129 /* genrshOne - right shift a one byte quantity by known count      */
9130 /*-----------------------------------------------------------------*/
9131 static void
9132 genrshOne (operand * result, operand * left,
9133            int shCount, int sign)
9134 {
9135   D (emitcode (";", "genrshOne"));
9136
9137   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9138 }
9139
9140 /*-----------------------------------------------------------------*/
9141 /* genrshTwo - right shift two bytes by known amount != 0          */
9142 /*-----------------------------------------------------------------*/
9143 static void
9144 genrshTwo (operand * result, operand * left,
9145            int shCount, int sign)
9146 {
9147   D (emitcode (";", "genrshTwo"));
9148
9149   /* if shCount >= 8 */
9150   if (shCount >= 8)
9151     {
9152       shCount -= 8;
9153       if (shCount)
9154         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9155       else
9156         movLeft2Result (left, MSB16, result, LSB, sign);
9157       addSign (result, MSB16, sign);
9158     }
9159
9160   /*  1 <= shCount <= 7 */
9161   else
9162     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9163 }
9164
9165 /*-----------------------------------------------------------------*/
9166 /* shiftRLong - shift right one long from left to result           */
9167 /* offl = LSB or MSB16                                             */
9168 /*-----------------------------------------------------------------*/
9169 static void
9170 shiftRLong (operand * left, int offl,
9171             operand * result, int sign)
9172 {
9173   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9174
9175   if (overlapping && offl>1)
9176     {
9177       // we are in big trouble, but this shouldn't happen
9178       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9179     }
9180
9181   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9182
9183   if (offl==MSB16)
9184     {
9185       // shift is > 8
9186       if (sign)
9187         {
9188           emitcode ("rlc", "a");
9189           emitcode ("subb", "a,acc");
9190           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9191             {
9192               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9193             }
9194           else
9195             {
9196               aopPut (result, "a", MSB32);
9197               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9198             }
9199         }
9200       else
9201         {
9202           if (aopPutUsesAcc (result, zero, MSB32))
9203             {
9204               emitcode("xch", "a,b");
9205               aopPut (result, zero, MSB32);
9206               emitcode("xch", "a,b");
9207             }
9208           else
9209             {
9210               aopPut (result, zero, MSB32);
9211             }
9212         }
9213     }
9214
9215   if (!sign)
9216     {
9217       emitcode ("clr", "c");
9218     }
9219   else
9220     {
9221       emitcode ("mov", "c,acc.7");
9222     }
9223
9224   emitcode ("rrc", "a");
9225
9226   if (overlapping && offl==MSB16 &&
9227       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9228     {
9229       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9230     }
9231   else
9232     {
9233       aopPut (result, "a", MSB32 - offl);
9234       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9235     }
9236
9237   emitcode ("rrc", "a");
9238   if (overlapping && offl==MSB16 &&
9239       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9240     {
9241       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9242     }
9243   else
9244     {
9245       aopPut (result, "a", MSB24 - offl);
9246       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9247     }
9248
9249   emitcode ("rrc", "a");
9250   if (offl != LSB)
9251     {
9252       aopPut (result, "a", MSB16 - offl);
9253     }
9254   else
9255     {
9256       if (overlapping &&
9257           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9258         {
9259           xch_a_aopGet (left, LSB, FALSE, FALSE);
9260         }
9261       else
9262         {
9263           aopPut (result, "a", MSB16 - offl);
9264           MOVA (aopGet (left, LSB, FALSE, FALSE));
9265         }
9266       emitcode ("rrc", "a");
9267       aopPut (result, "a", LSB);
9268     }
9269 }
9270
9271 /*-----------------------------------------------------------------*/
9272 /* genrshFour - shift four byte by a known amount != 0             */
9273 /*-----------------------------------------------------------------*/
9274 static void
9275 genrshFour (operand * result, operand * left,
9276             int shCount, int sign)
9277 {
9278   D (emitcode (";", "genrshFour"));
9279
9280   /* if shifting more that 3 bytes */
9281   if (shCount >= 24)
9282     {
9283       shCount -= 24;
9284       if (shCount)
9285         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9286       else
9287         movLeft2Result (left, MSB32, result, LSB, sign);
9288       addSign (result, MSB16, sign);
9289     }
9290   else if (shCount >= 16)
9291     {
9292       shCount -= 16;
9293       if (shCount)
9294         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9295       else
9296         {
9297           movLeft2Result (left, MSB24, result, LSB, 0);
9298           movLeft2Result (left, MSB32, result, MSB16, sign);
9299         }
9300       addSign (result, MSB24, sign);
9301     }
9302   else if (shCount >= 8)
9303     {
9304       shCount -= 8;
9305       if (shCount == 1)
9306         {
9307           shiftRLong (left, MSB16, result, sign);
9308         }
9309       else if (shCount == 0)
9310         {
9311           movLeft2Result (left, MSB16, result, LSB, 0);
9312           movLeft2Result (left, MSB24, result, MSB16, 0);
9313           movLeft2Result (left, MSB32, result, MSB24, sign);
9314           addSign (result, MSB32, sign);
9315         }
9316       else
9317         {
9318           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9319           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9320           /* the last shift is signed */
9321           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9322           addSign (result, MSB32, sign);
9323         }
9324     }
9325   else
9326     {
9327       /* 1 <= shCount <= 7 */
9328       if (shCount <= 2)
9329         {
9330           shiftRLong (left, LSB, result, sign);
9331           if (shCount == 2)
9332             shiftRLong (result, LSB, result, sign);
9333         }
9334       else
9335         {
9336           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9337           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9338           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9339         }
9340     }
9341 }
9342
9343 /*-----------------------------------------------------------------*/
9344 /* genRightShiftLiteral - right shifting by known count            */
9345 /*-----------------------------------------------------------------*/
9346 static void
9347 genRightShiftLiteral (operand * left,
9348                       operand * right,
9349                       operand * result,
9350                       iCode * ic,
9351                       int sign)
9352 {
9353   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9354   int size;
9355
9356   D (emitcode (";", "genRightShiftLiteral"));
9357
9358   freeAsmop (right, NULL, ic, TRUE);
9359
9360   aopOp (left, ic, FALSE);
9361   aopOp (result, ic, FALSE);
9362
9363 #if VIEW_SIZE
9364   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9365             AOP_SIZE (left));
9366 #endif
9367
9368   size = getDataSize (left);
9369   /* test the LEFT size !!! */
9370
9371   /* I suppose that the left size >= result size */
9372   if (shCount == 0)
9373     {
9374       size = getDataSize (result);
9375       while (size--)
9376         movLeft2Result (left, size, result, size, 0);
9377     }
9378
9379   else if (shCount >= (size * 8))
9380     {
9381       if (sign)
9382         {
9383           /* get sign in acc.7 */
9384           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9385         }
9386       addSign (result, LSB, sign);
9387     }
9388   else
9389     {
9390       switch (size)
9391         {
9392         case 1:
9393           genrshOne (result, left, shCount, sign);
9394           break;
9395
9396         case 2:
9397           genrshTwo (result, left, shCount, sign);
9398           break;
9399
9400         case 4:
9401           genrshFour (result, left, shCount, sign);
9402           break;
9403         default:
9404           break;
9405         }
9406     }
9407   freeAsmop (result, NULL, ic, TRUE);
9408   freeAsmop (left, NULL, ic, TRUE);
9409 }
9410
9411 /*-----------------------------------------------------------------*/
9412 /* genSignedRightShift - right shift of signed number              */
9413 /*-----------------------------------------------------------------*/
9414 static void
9415 genSignedRightShift (iCode * ic)
9416 {
9417   operand *right, *left, *result;
9418   int size, offset;
9419   char *l;
9420   symbol *tlbl, *tlbl1;
9421   bool pushedB;
9422
9423   D (emitcode (";", "genSignedRightShift"));
9424
9425   /* we do it the hard way put the shift count in b
9426      and loop thru preserving the sign */
9427
9428   right = IC_RIGHT (ic);
9429   left = IC_LEFT (ic);
9430   result = IC_RESULT (ic);
9431
9432   aopOp (right, ic, FALSE);
9433
9434
9435   if (AOP_TYPE (right) == AOP_LIT)
9436     {
9437       genRightShiftLiteral (left, right, result, ic, 1);
9438       return;
9439     }
9440   /* shift count is unknown then we have to form
9441      a loop get the loop count in B : Note: we take
9442      only the lower order byte since shifting
9443      more that 32 bits make no sense anyway, ( the
9444      largest size of an object can be only 32 bits ) */
9445
9446   pushedB = pushB ();
9447   MOVB (aopGet (right, 0, FALSE, FALSE));
9448   emitcode ("inc", "b");
9449   freeAsmop (right, NULL, ic, TRUE);
9450   aopOp (left, ic, FALSE);
9451   aopOp (result, ic, FALSE);
9452
9453   /* now move the left to the result if they are not the
9454      same */
9455   if (!sameRegs (AOP (left), AOP (result)) &&
9456       AOP_SIZE (result) > 1)
9457     {
9458
9459       size = AOP_SIZE (result);
9460       offset = 0;
9461       while (size--)
9462         {
9463           l = aopGet (left, offset, FALSE, TRUE);
9464           if (*l == '@' && IS_AOP_PREG (result))
9465             {
9466
9467               emitcode ("mov", "a,%s", l);
9468               aopPut (result, "a", offset);
9469             }
9470           else
9471             aopPut (result, l, offset);
9472           offset++;
9473         }
9474     }
9475
9476   /* mov the highest order bit to OVR */
9477   tlbl = newiTempLabel (NULL);
9478   tlbl1 = newiTempLabel (NULL);
9479
9480   size = AOP_SIZE (result);
9481   offset = size - 1;
9482   MOVA (aopGet (left, offset, FALSE, FALSE));
9483   emitcode ("rlc", "a");
9484   emitcode ("mov", "ov,c");
9485   /* if it is only one byte then */
9486   if (size == 1)
9487     {
9488       l = aopGet (left, 0, FALSE, FALSE);
9489       MOVA (l);
9490       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9491       emitLabel (tlbl);
9492       emitcode ("mov", "c,ov");
9493       emitcode ("rrc", "a");
9494       emitLabel (tlbl1);
9495       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9496       popB (pushedB);
9497       aopPut (result, "a", 0);
9498       goto release;
9499     }
9500
9501   reAdjustPreg (AOP (result));
9502   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9503   emitLabel (tlbl);
9504   emitcode ("mov", "c,ov");
9505   while (size--)
9506     {
9507       l = aopGet (result, offset, FALSE, FALSE);
9508       MOVA (l);
9509       emitcode ("rrc", "a");
9510       aopPut (result, "a", offset--);
9511     }
9512   reAdjustPreg (AOP (result));
9513   emitLabel (tlbl1);
9514   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9515   popB (pushedB);
9516
9517 release:
9518   freeAsmop (result, NULL, ic, TRUE);
9519   freeAsmop (left, NULL, ic, TRUE);
9520 }
9521
9522 /*-----------------------------------------------------------------*/
9523 /* genRightShift - generate code for right shifting                */
9524 /*-----------------------------------------------------------------*/
9525 static void
9526 genRightShift (iCode * ic)
9527 {
9528   operand *right, *left, *result;
9529   sym_link *letype;
9530   int size, offset;
9531   char *l;
9532   symbol *tlbl, *tlbl1;
9533   bool pushedB;
9534
9535   D (emitcode (";", "genRightShift"));
9536
9537   /* if signed then we do it the hard way preserve the
9538      sign bit moving it inwards */
9539   letype = getSpec (operandType (IC_LEFT (ic)));
9540
9541   if (!SPEC_USIGN (letype))
9542     {
9543       genSignedRightShift (ic);
9544       return;
9545     }
9546
9547   /* signed & unsigned types are treated the same : i.e. the
9548      signed is NOT propagated inwards : quoting from the
9549      ANSI - standard : "for E1 >> E2, is equivalent to division
9550      by 2**E2 if unsigned or if it has a non-negative value,
9551      otherwise the result is implementation defined ", MY definition
9552      is that the sign does not get propagated */
9553
9554   right = IC_RIGHT (ic);
9555   left = IC_LEFT (ic);
9556   result = IC_RESULT (ic);
9557
9558   aopOp (right, ic, FALSE);
9559
9560   /* if the shift count is known then do it
9561      as efficiently as possible */
9562   if (AOP_TYPE (right) == AOP_LIT)
9563     {
9564       genRightShiftLiteral (left, right, result, ic, 0);
9565       return;
9566     }
9567
9568   /* shift count is unknown then we have to form
9569      a loop get the loop count in B : Note: we take
9570      only the lower order byte since shifting
9571      more that 32 bits make no sense anyway, ( the
9572      largest size of an object can be only 32 bits ) */
9573
9574   pushedB = pushB ();
9575   MOVB (aopGet (right, 0, FALSE, FALSE));
9576   emitcode ("inc", "b");
9577   freeAsmop (right, NULL, ic, TRUE);
9578   aopOp (left, ic, FALSE);
9579   aopOp (result, ic, FALSE);
9580
9581   /* now move the left to the result if they are not the
9582      same */
9583   if (!sameRegs (AOP (left), AOP (result)) &&
9584       AOP_SIZE (result) > 1)
9585     {
9586       size = AOP_SIZE (result);
9587       offset = 0;
9588       while (size--)
9589         {
9590           l = aopGet (left, offset, FALSE, TRUE);
9591           if (*l == '@' && IS_AOP_PREG (result))
9592             {
9593
9594               emitcode ("mov", "a,%s", l);
9595               aopPut (result, "a", offset);
9596             }
9597           else
9598             aopPut (result, l, offset);
9599           offset++;
9600         }
9601     }
9602
9603   tlbl = newiTempLabel (NULL);
9604   tlbl1 = newiTempLabel (NULL);
9605   size = AOP_SIZE (result);
9606   offset = size - 1;
9607
9608   /* if it is only one byte then */
9609   if (size == 1)
9610     {
9611       l = aopGet (left, 0, FALSE, FALSE);
9612       MOVA (l);
9613       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9614       emitLabel (tlbl);
9615       CLRC;
9616       emitcode ("rrc", "a");
9617       emitLabel (tlbl1);
9618       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9619       popB (pushedB);
9620       aopPut (result, "a", 0);
9621       goto release;
9622     }
9623
9624   reAdjustPreg (AOP (result));
9625   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9626   emitLabel (tlbl);
9627   CLRC;
9628   while (size--)
9629     {
9630       l = aopGet (result, offset, FALSE, FALSE);
9631       MOVA (l);
9632       emitcode ("rrc", "a");
9633       aopPut (result, "a", offset--);
9634     }
9635   reAdjustPreg (AOP (result));
9636
9637   emitLabel (tlbl1);
9638   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9639   popB (pushedB);
9640
9641 release:
9642   freeAsmop (result, NULL, ic, TRUE);
9643   freeAsmop (left, NULL, ic, TRUE);
9644 }
9645
9646 /*-----------------------------------------------------------------*/
9647 /* emitPtrByteGet - emits code to get a byte into A through a      */
9648 /*                  pointer register (R0, R1, or DPTR). The        */
9649 /*                  original value of A can be preserved in B.     */
9650 /*-----------------------------------------------------------------*/
9651 static void
9652 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9653 {
9654   switch (p_type)
9655     {
9656     case IPOINTER:
9657     case POINTER:
9658       if (preserveAinB)
9659         emitcode ("mov", "b,a");
9660       emitcode ("mov", "a,@%s", rname);
9661       break;
9662
9663     case PPOINTER:
9664       if (preserveAinB)
9665         emitcode ("mov", "b,a");
9666       emitcode ("movx", "a,@%s", rname);
9667       break;
9668
9669     case FPOINTER:
9670       if (preserveAinB)
9671         emitcode ("mov", "b,a");
9672       emitcode ("movx", "a,@dptr");
9673       break;
9674
9675     case CPOINTER:
9676       if (preserveAinB)
9677         emitcode ("mov", "b,a");
9678       emitcode ("clr", "a");
9679       emitcode ("movc", "a,@a+dptr");
9680       break;
9681
9682     case GPOINTER:
9683       if (preserveAinB)
9684         {
9685           emitcode ("push", "b");
9686           emitcode ("push", "acc");
9687         }
9688       emitcode ("lcall", "__gptrget");
9689       if (preserveAinB)
9690         emitcode ("pop", "b");
9691       break;
9692     }
9693 }
9694
9695 /*-----------------------------------------------------------------*/
9696 /* emitPtrByteSet - emits code to set a byte from src through a    */
9697 /*                  pointer register (R0, R1, or DPTR).            */
9698 /*-----------------------------------------------------------------*/
9699 static void
9700 emitPtrByteSet (char *rname, int p_type, char *src)
9701 {
9702   switch (p_type)
9703     {
9704     case IPOINTER:
9705     case POINTER:
9706       if (*src=='@')
9707         {
9708           MOVA (src);
9709           emitcode ("mov", "@%s,a", rname);
9710         }
9711       else
9712         emitcode ("mov", "@%s,%s", rname, src);
9713       break;
9714
9715     case PPOINTER:
9716       MOVA (src);
9717       emitcode ("movx", "@%s,a", rname);
9718       break;
9719
9720     case FPOINTER:
9721       MOVA (src);
9722       emitcode ("movx", "@dptr,a");
9723       break;
9724
9725     case GPOINTER:
9726       MOVA (src);
9727       emitcode ("lcall", "__gptrput");
9728       break;
9729     }
9730 }
9731
9732 /*-----------------------------------------------------------------*/
9733 /* genUnpackBits - generates code for unpacking bits               */
9734 /*-----------------------------------------------------------------*/
9735 static void
9736 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9737 {
9738   int offset = 0;       /* result byte offset */
9739   int rsize;            /* result size */
9740   int rlen = 0;         /* remaining bitfield length */
9741   sym_link *etype;      /* bitfield type information */
9742   int blen;             /* bitfield length */
9743   int bstr;             /* bitfield starting bit within byte */
9744   char buffer[10];
9745
9746   D(emitcode (";", "genUnpackBits"));
9747
9748   etype = getSpec (operandType (result));
9749   rsize = getSize (operandType (result));
9750   blen = SPEC_BLEN (etype);
9751   bstr = SPEC_BSTR (etype);
9752
9753   if (ifx && blen <= 8)
9754     {
9755       emitPtrByteGet (rname, ptype, FALSE);
9756       if (blen == 1)
9757         {
9758           SNPRINTF (buffer, sizeof(buffer),
9759                     "acc.%d", bstr);
9760           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9761         }
9762       else
9763         {
9764           if (blen < 8)
9765             emitcode ("anl", "a,#0x%02x",
9766                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9767           genIfxJump (ifx, "a", NULL, NULL, NULL);
9768         }
9769       return;
9770     }
9771   wassert (!ifx);
9772
9773   /* If the bitfield length is less than a byte */
9774   if (blen < 8)
9775     {
9776       emitPtrByteGet (rname, ptype, FALSE);
9777       AccRol (8 - bstr);
9778       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9779       if (!SPEC_USIGN (etype))
9780         {
9781           /* signed bitfield */
9782           symbol *tlbl = newiTempLabel (NULL);
9783
9784           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9785           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9786           emitLabel (tlbl);
9787         }
9788       aopPut (result, "a", offset++);
9789       goto finish;
9790     }
9791
9792   /* Bit field did not fit in a byte. Copy all
9793      but the partial byte at the end.  */
9794   for (rlen=blen;rlen>=8;rlen-=8)
9795     {
9796       emitPtrByteGet (rname, ptype, FALSE);
9797       aopPut (result, "a", offset++);
9798       if (rlen>8)
9799         emitcode ("inc", "%s", rname);
9800     }
9801
9802   /* Handle the partial byte at the end */
9803   if (rlen)
9804     {
9805       emitPtrByteGet (rname, ptype, FALSE);
9806       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9807       if (!SPEC_USIGN (etype))
9808         {
9809           /* signed bitfield */
9810           symbol *tlbl = newiTempLabel (NULL);
9811
9812           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9813           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9814           emitLabel (tlbl);
9815         }
9816       aopPut (result, "a", offset++);
9817     }
9818
9819 finish:
9820   if (offset < rsize)
9821     {
9822       char *source;
9823
9824       if (SPEC_USIGN (etype))
9825         source = zero;
9826       else
9827         {
9828           /* signed bitfield: sign extension with 0x00 or 0xff */
9829           emitcode ("rlc", "a");
9830           emitcode ("subb", "a,acc");
9831
9832           source = "a";
9833         }
9834       rsize -= offset;
9835       while (rsize--)
9836         aopPut (result, source, offset++);
9837     }
9838 }
9839
9840
9841 /*-----------------------------------------------------------------*/
9842 /* genDataPointerGet - generates code when ptr offset is known     */
9843 /*-----------------------------------------------------------------*/
9844 static void
9845 genDataPointerGet (operand * left,
9846                    operand * result,
9847                    iCode * ic)
9848 {
9849   char *l;
9850   char buffer[256];
9851   int size, offset = 0;
9852
9853   D (emitcode (";", "genDataPointerGet"));
9854
9855   aopOp (result, ic, TRUE);
9856
9857   /* get the string representation of the name */
9858   l = aopGet (left, 0, FALSE, TRUE);
9859   l++; // remove #
9860   size = AOP_SIZE (result);
9861   while (size--)
9862     {
9863       if (offset)
9864         {
9865           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9866         }
9867       else
9868         {
9869           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9870         }
9871       aopPut (result, buffer, offset++);
9872     }
9873
9874   freeAsmop (result, NULL, ic, TRUE);
9875   freeAsmop (left, NULL, ic, TRUE);
9876 }
9877
9878 /*-----------------------------------------------------------------*/
9879 /* genNearPointerGet - emitcode for near pointer fetch             */
9880 /*-----------------------------------------------------------------*/
9881 static void
9882 genNearPointerGet (operand * left,
9883                    operand * result,
9884                    iCode * ic,
9885                    iCode * pi,
9886                    iCode * ifx)
9887 {
9888   asmop *aop = NULL;
9889   regs *preg = NULL;
9890   char *rname;
9891   sym_link *rtype, *retype;
9892   sym_link *ltype = operandType (left);
9893   char buffer[80];
9894
9895   D (emitcode (";", "genNearPointerGet"));
9896
9897   rtype = operandType (result);
9898   retype = getSpec (rtype);
9899
9900   aopOp (left, ic, FALSE);
9901
9902   /* if left is rematerialisable and
9903      result is not bitfield variable type and
9904      the left is pointer to data space i.e
9905      lower 128 bytes of space */
9906   if (AOP_TYPE (left) == AOP_IMMD &&
9907       !IS_BITFIELD (retype) &&
9908       DCL_TYPE (ltype) == POINTER)
9909     {
9910       genDataPointerGet (left, result, ic);
9911       return;
9912     }
9913
9914  /* if the value is already in a pointer register
9915      then don't need anything more */
9916   if (!AOP_INPREG (AOP (left)))
9917     {
9918       if (IS_AOP_PREG (left))
9919         {
9920           // Aha, it is a pointer, just in disguise.
9921           rname = aopGet (left, 0, FALSE, FALSE);
9922           if (*rname != '@')
9923             {
9924               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9925                       __FILE__, __LINE__);
9926             }
9927           else
9928             {
9929               // Expected case.
9930               emitcode ("mov", "a%s,%s", rname + 1, rname);
9931               rname++;  // skip the '@'.
9932             }
9933         }
9934       else
9935         {
9936           /* otherwise get a free pointer register */
9937           aop = newAsmop (0);
9938           preg = getFreePtr (ic, &aop, FALSE);
9939           emitcode ("mov", "%s,%s",
9940                     preg->name,
9941                     aopGet (left, 0, FALSE, TRUE));
9942           rname = preg->name;
9943         }
9944     }
9945   else
9946     rname = aopGet (left, 0, FALSE, FALSE);
9947
9948   //aopOp (result, ic, FALSE);
9949   aopOp (result, ic, result?TRUE:FALSE);
9950
9951   /* if bitfield then unpack the bits */
9952   if (IS_BITFIELD (retype))
9953     genUnpackBits (result, rname, POINTER, ifx);
9954   else
9955     {
9956       /* we have can just get the values */
9957       int size = AOP_SIZE (result);
9958       int offset = 0;
9959
9960       while (size--)
9961         {
9962           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9963             {
9964
9965               emitcode ("mov", "a,@%s", rname);
9966               if (!ifx)
9967                 aopPut (result, "a", offset);
9968             }
9969           else
9970             {
9971               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9972               aopPut (result, buffer, offset);
9973             }
9974           offset++;
9975           if (size || pi)
9976             emitcode ("inc", "%s", rname);
9977         }
9978     }
9979
9980   /* now some housekeeping stuff */
9981   if (aop)       /* we had to allocate for this iCode */
9982     {
9983       if (pi) { /* post increment present */
9984         aopPut (left, rname, 0);
9985       }
9986       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9987     }
9988   else
9989     {
9990       /* we did not allocate which means left
9991          already in a pointer register, then
9992          if size > 0 && this could be used again
9993          we have to point it back to where it
9994          belongs */
9995       if ((AOP_SIZE (result) > 1 &&
9996            !OP_SYMBOL (left)->remat &&
9997            (OP_SYMBOL (left)->liveTo > ic->seq ||
9998             ic->depth)) &&
9999           !pi)
10000         {
10001           int size = AOP_SIZE (result) - 1;
10002           while (size--)
10003             emitcode ("dec", "%s", rname);
10004         }
10005     }
10006
10007   if (ifx && !ifx->generated)
10008     {
10009       genIfxJump (ifx, "a", left, NULL, result);
10010     }
10011
10012   /* done */
10013   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10014   freeAsmop (left, NULL, ic, TRUE);
10015   if (pi) pi->generated = 1;
10016 }
10017
10018 /*-----------------------------------------------------------------*/
10019 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10020 /*-----------------------------------------------------------------*/
10021 static void
10022 genPagedPointerGet (operand * left,
10023                     operand * result,
10024                     iCode * ic,
10025                     iCode *pi,
10026                     iCode *ifx)
10027 {
10028   asmop *aop = NULL;
10029   regs *preg = NULL;
10030   char *rname;
10031   sym_link *rtype, *retype;
10032
10033   D (emitcode (";", "genPagedPointerGet"));
10034
10035   rtype = operandType (result);
10036   retype = getSpec (rtype);
10037
10038   aopOp (left, ic, FALSE);
10039
10040   /* if the value is already in a pointer register
10041      then don't need anything more */
10042   if (!AOP_INPREG (AOP (left)))
10043     {
10044       /* otherwise get a free pointer register */
10045       aop = newAsmop (0);
10046       preg = getFreePtr (ic, &aop, FALSE);
10047       emitcode ("mov", "%s,%s",
10048                 preg->name,
10049                 aopGet (left, 0, FALSE, TRUE));
10050       rname = preg->name;
10051     }
10052   else
10053     rname = aopGet (left, 0, FALSE, FALSE);
10054
10055   aopOp (result, ic, FALSE);
10056
10057   /* if bitfield then unpack the bits */
10058   if (IS_BITFIELD (retype))
10059     genUnpackBits (result, rname, PPOINTER, ifx);
10060   else
10061     {
10062       /* we have can just get the values */
10063       int size = AOP_SIZE (result);
10064       int offset = 0;
10065
10066       while (size--)
10067         {
10068
10069           emitcode ("movx", "a,@%s", rname);
10070           if (!ifx)
10071             aopPut (result, "a", offset);
10072
10073           offset++;
10074
10075           if (size || pi)
10076             emitcode ("inc", "%s", rname);
10077         }
10078     }
10079
10080   /* now some housekeeping stuff */
10081   if (aop) /* we had to allocate for this iCode */
10082     {
10083       if (pi)
10084         aopPut (left, rname, 0);
10085       freeAsmop (NULL, aop, ic, TRUE);
10086     }
10087   else
10088     {
10089       /* we did not allocate which means left
10090          already in a pointer register, then
10091          if size > 0 && this could be used again
10092          we have to point it back to where it
10093          belongs */
10094       if ((AOP_SIZE (result) > 1 &&
10095            !OP_SYMBOL (left)->remat &&
10096            (OP_SYMBOL (left)->liveTo > ic->seq ||
10097             ic->depth)) &&
10098           !pi)
10099         {
10100           int size = AOP_SIZE (result) - 1;
10101           while (size--)
10102             emitcode ("dec", "%s", rname);
10103         }
10104     }
10105
10106   if (ifx && !ifx->generated)
10107     {
10108       genIfxJump (ifx, "a", left, NULL, result);
10109     }
10110
10111   /* done */
10112   freeAsmop (result, NULL, ic, TRUE);
10113   freeAsmop (left, NULL, ic, TRUE);
10114   if (pi) pi->generated = 1;
10115 }
10116
10117 /*--------------------------------------------------------------------*/
10118 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10119 /*--------------------------------------------------------------------*/
10120 static void
10121 loadDptrFromOperand (operand *op, bool loadBToo)
10122 {
10123   if (AOP_TYPE (op) != AOP_STR)
10124     {
10125       /* if this is rematerializable */
10126       if (AOP_TYPE (op) == AOP_IMMD)
10127         {
10128           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10129           if (loadBToo)
10130             {
10131               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10132                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10133               else
10134                 {
10135                   wassertl(FALSE, "need pointerCode");
10136                   emitcode (";", "mov b,???");
10137                   /* genPointerGet and genPointerSet originally did different
10138                   ** things for this case. Both seem wrong.
10139                   ** from genPointerGet:
10140                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10141                   ** from genPointerSet:
10142                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10143                   */
10144                 }
10145             }
10146         }
10147       else if (AOP_TYPE (op) == AOP_DPTR)
10148         {
10149           if (loadBToo)
10150             {
10151               MOVA (aopGet (op, 0, FALSE, FALSE));
10152               emitcode ("push", "acc");
10153               MOVA (aopGet (op, 1, FALSE, FALSE));
10154               emitcode ("push", "acc");
10155               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10156               emitcode ("pop", "dph");
10157               emitcode ("pop", "dpl");
10158             }
10159           else
10160             {
10161               MOVA (aopGet (op, 0, FALSE, FALSE));
10162               emitcode ("push", "acc");
10163               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10164               emitcode ("pop", "dpl");
10165             }
10166         }
10167       else
10168         {                       /* we need to get it byte by byte */
10169           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10170           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10171           if (loadBToo)
10172             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10173         }
10174     }
10175 }
10176
10177 /*-----------------------------------------------------------------*/
10178 /* genFarPointerGet - get value from far space                     */
10179 /*-----------------------------------------------------------------*/
10180 static void
10181 genFarPointerGet (operand * left,
10182                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10183 {
10184   int size, offset;
10185   sym_link *retype = getSpec (operandType (result));
10186
10187   D (emitcode (";", "genFarPointerGet"));
10188
10189   aopOp (left, ic, FALSE);
10190   loadDptrFromOperand (left, FALSE);
10191
10192   /* so dptr now contains the address */
10193   aopOp (result, ic, FALSE);
10194
10195   /* if bit then unpack */
10196   if (IS_BITFIELD (retype))
10197     genUnpackBits (result, "dptr", FPOINTER, ifx);
10198   else
10199     {
10200       size = AOP_SIZE (result);
10201       offset = 0;
10202
10203       while (size--)
10204         {
10205           emitcode ("movx", "a,@dptr");
10206           if (!ifx)
10207             aopPut (result, "a", offset++);
10208           if (size || pi)
10209             emitcode ("inc", "dptr");
10210         }
10211     }
10212
10213   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10214     {
10215       aopPut (left, "dpl", 0);
10216       aopPut (left, "dph", 1);
10217       pi->generated = 1;
10218     }
10219
10220   if (ifx && !ifx->generated)
10221     {
10222       genIfxJump (ifx, "a", left, NULL, result);
10223     }
10224
10225   freeAsmop (result, NULL, ic, TRUE);
10226   freeAsmop (left, NULL, ic, TRUE);
10227 }
10228
10229 /*-----------------------------------------------------------------*/
10230 /* genCodePointerGet - get value from code space                   */
10231 /*-----------------------------------------------------------------*/
10232 static void
10233 genCodePointerGet (operand * left,
10234                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10235 {
10236   int size, offset;
10237   sym_link *retype = getSpec (operandType (result));
10238
10239   D (emitcode (";", "genCodePointerGet"));
10240
10241   aopOp (left, ic, FALSE);
10242   loadDptrFromOperand (left, FALSE);
10243
10244   /* so dptr now contains the address */
10245   aopOp (result, ic, FALSE);
10246
10247   /* if bit then unpack */
10248   if (IS_BITFIELD (retype))
10249     genUnpackBits (result, "dptr", CPOINTER, ifx);
10250   else
10251     {
10252       size = AOP_SIZE (result);
10253       offset = 0;
10254
10255       while (size--)
10256         {
10257           emitcode ("clr", "a");
10258           emitcode ("movc", "a,@a+dptr");
10259           if (!ifx)
10260             aopPut (result, "a", offset++);
10261           if (size || pi)
10262             emitcode ("inc", "dptr");
10263         }
10264     }
10265
10266   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10267     {
10268       aopPut (left, "dpl", 0);
10269       aopPut (left, "dph", 1);
10270       pi->generated = 1;
10271     }
10272
10273   if (ifx && !ifx->generated)
10274     {
10275       genIfxJump (ifx, "a", left, NULL, result);
10276     }
10277
10278   freeAsmop (result, NULL, ic, TRUE);
10279   freeAsmop (left, NULL, ic, TRUE);
10280 }
10281
10282 /*-----------------------------------------------------------------*/
10283 /* genGenPointerGet - get value from generic pointer space         */
10284 /*-----------------------------------------------------------------*/
10285 static void
10286 genGenPointerGet (operand * left,
10287                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10288 {
10289   int size, offset;
10290   sym_link *retype = getSpec (operandType (result));
10291
10292   D (emitcode (";", "genGenPointerGet"));
10293
10294   aopOp (left, ic, FALSE);
10295   loadDptrFromOperand (left, TRUE);
10296
10297   /* so dptr now contains the address */
10298   aopOp (result, ic, FALSE);
10299
10300   /* if bit then unpack */
10301   if (IS_BITFIELD (retype))
10302     {
10303       genUnpackBits (result, "dptr", GPOINTER, ifx);
10304     }
10305   else
10306     {
10307       size = AOP_SIZE (result);
10308       offset = 0;
10309
10310       while (size--)
10311         {
10312           emitcode ("lcall", "__gptrget");
10313           if (!ifx)
10314             aopPut (result, "a", offset++);
10315           if (size || pi)
10316             emitcode ("inc", "dptr");
10317         }
10318     }
10319
10320   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10321     {
10322       aopPut (left, "dpl", 0);
10323       aopPut (left, "dph", 1);
10324       pi->generated = 1;
10325     }
10326
10327   if (ifx && !ifx->generated)
10328     {
10329       genIfxJump (ifx, "a", left, NULL, result);
10330     }
10331
10332   freeAsmop (result, NULL, ic, TRUE);
10333   freeAsmop (left, NULL, ic, TRUE);
10334 }
10335
10336 /*-----------------------------------------------------------------*/
10337 /* genPointerGet - generate code for pointer get                   */
10338 /*-----------------------------------------------------------------*/
10339 static void
10340 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10341 {
10342   operand *left, *result;
10343   sym_link *type, *etype;
10344   int p_type;
10345
10346   D (emitcode (";", "genPointerGet"));
10347
10348   left = IC_LEFT (ic);
10349   result = IC_RESULT (ic);
10350
10351   if (getSize (operandType (result))>1)
10352     ifx = NULL;
10353
10354   /* depending on the type of pointer we need to
10355      move it to the correct pointer register */
10356   type = operandType (left);
10357   etype = getSpec (type);
10358   /* if left is of type of pointer then it is simple */
10359   if (IS_PTR (type) && !IS_FUNC (type->next))
10360     {
10361       p_type = DCL_TYPE (type);
10362     }
10363   else
10364     {
10365       /* we have to go by the storage class */
10366       p_type = PTR_TYPE (SPEC_OCLS (etype));
10367     }
10368
10369   /* special case when cast remat */
10370   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10371       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10372     {
10373       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10374       type = operandType (left);
10375       p_type = DCL_TYPE (type);
10376     }
10377   /* now that we have the pointer type we assign
10378      the pointer values */
10379   switch (p_type)
10380     {
10381
10382     case POINTER:
10383     case IPOINTER:
10384       genNearPointerGet (left, result, ic, pi, ifx);
10385       break;
10386
10387     case PPOINTER:
10388       genPagedPointerGet (left, result, ic, pi, ifx);
10389       break;
10390
10391     case FPOINTER:
10392       genFarPointerGet (left, result, ic, pi, ifx);
10393       break;
10394
10395     case CPOINTER:
10396       genCodePointerGet (left, result, ic, pi, ifx);
10397       break;
10398
10399     case GPOINTER:
10400       genGenPointerGet (left, result, ic, pi, ifx);
10401       break;
10402     }
10403 }
10404
10405
10406 /*-----------------------------------------------------------------*/
10407 /* genPackBits - generates code for packed bit storage             */
10408 /*-----------------------------------------------------------------*/
10409 static void
10410 genPackBits (sym_link * etype,
10411              operand * right,
10412              char *rname, int p_type)
10413 {
10414   int offset = 0;       /* source byte offset */
10415   int rlen = 0;         /* remaining bitfield length */
10416   int blen;             /* bitfield length */
10417   int bstr;             /* bitfield starting bit within byte */
10418   int litval;           /* source literal value (if AOP_LIT) */
10419   unsigned char mask;   /* bitmask within current byte */
10420
10421   D(emitcode (";", "genPackBits"));
10422
10423   blen = SPEC_BLEN (etype);
10424   bstr = SPEC_BSTR (etype);
10425
10426   /* If the bitfield length is less than a byte */
10427   if (blen < 8)
10428     {
10429       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10430               (unsigned char) (0xFF >> (8 - bstr)));
10431
10432       if (AOP_TYPE (right) == AOP_LIT)
10433         {
10434           /* Case with a bitfield length <8 and literal source
10435           */
10436           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10437           litval <<= bstr;
10438           litval &= (~mask) & 0xff;
10439           emitPtrByteGet (rname, p_type, FALSE);
10440           if ((mask|litval)!=0xff)
10441             emitcode ("anl","a,#0x%02x", mask);
10442           if (litval)
10443             emitcode ("orl","a,#0x%02x", litval);
10444         }
10445       else
10446         {
10447           if ((blen==1) && (p_type!=GPOINTER))
10448             {
10449               /* Case with a bitfield length == 1 and no generic pointer
10450               */
10451               if (AOP_TYPE (right) == AOP_CRY)
10452                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10453               else
10454                 {
10455                   MOVA (aopGet (right, 0, FALSE, FALSE));
10456                   emitcode ("rrc","a");
10457                 }
10458               emitPtrByteGet (rname, p_type, FALSE);
10459               emitcode ("mov","acc.%d,c",bstr);
10460             }
10461           else
10462             {
10463               bool pushedB;
10464               /* Case with a bitfield length < 8 and arbitrary source
10465               */
10466               MOVA (aopGet (right, 0, FALSE, FALSE));
10467               /* shift and mask source value */
10468               AccLsh (bstr);
10469               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10470
10471               pushedB = pushB ();
10472               /* transfer A to B and get next byte */
10473               emitPtrByteGet (rname, p_type, TRUE);
10474
10475               emitcode ("anl", "a,#0x%02x", mask);
10476               emitcode ("orl", "a,b");
10477               if (p_type == GPOINTER)
10478                 emitcode ("pop", "b");
10479
10480               popB (pushedB);
10481            }
10482         }
10483
10484       emitPtrByteSet (rname, p_type, "a");
10485       return;
10486     }
10487
10488   /* Bit length is greater than 7 bits. In this case, copy  */
10489   /* all except the partial byte at the end                 */
10490   for (rlen=blen;rlen>=8;rlen-=8)
10491     {
10492       emitPtrByteSet (rname, p_type,
10493                       aopGet (right, offset++, FALSE, TRUE) );
10494       if (rlen>8)
10495         emitcode ("inc", "%s", rname);
10496     }
10497
10498   /* If there was a partial byte at the end */
10499   if (rlen)
10500     {
10501       mask = (((unsigned char) -1 << rlen) & 0xff);
10502
10503       if (AOP_TYPE (right) == AOP_LIT)
10504         {
10505           /* Case with partial byte and literal source
10506           */
10507           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10508           litval >>= (blen-rlen);
10509           litval &= (~mask) & 0xff;
10510           emitPtrByteGet (rname, p_type, FALSE);
10511           if ((mask|litval)!=0xff)
10512             emitcode ("anl","a,#0x%02x", mask);
10513           if (litval)
10514             emitcode ("orl","a,#0x%02x", litval);
10515         }
10516       else
10517         {
10518           bool pushedB;
10519           /* Case with partial byte and arbitrary source
10520           */
10521           MOVA (aopGet (right, offset++, FALSE, FALSE));
10522           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10523
10524           pushedB = pushB ();
10525           /* transfer A to B and get next byte */
10526           emitPtrByteGet (rname, p_type, TRUE);
10527
10528           emitcode ("anl", "a,#0x%02x", mask);
10529           emitcode ("orl", "a,b");
10530           if (p_type == GPOINTER)
10531             emitcode ("pop", "b");
10532
10533           popB (pushedB);
10534         }
10535       emitPtrByteSet (rname, p_type, "a");
10536     }
10537 }
10538
10539
10540 /*-----------------------------------------------------------------*/
10541 /* genDataPointerSet - remat pointer to data space                 */
10542 /*-----------------------------------------------------------------*/
10543 static void
10544 genDataPointerSet (operand * right,
10545                    operand * result,
10546                    iCode * ic)
10547 {
10548   int size, offset = 0;
10549   char *l, buffer[256];
10550
10551   D (emitcode (";", "genDataPointerSet"));
10552
10553   aopOp (right, ic, FALSE);
10554
10555   l = aopGet (result, 0, FALSE, TRUE);
10556   l++; //remove #
10557   size = max (AOP_SIZE (right), AOP_SIZE (result));
10558   while (size--)
10559     {
10560       if (offset)
10561         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10562       else
10563         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10564       emitcode ("mov", "%s,%s", buffer,
10565                 aopGet (right, offset++, FALSE, FALSE));
10566     }
10567
10568   freeAsmop (right, NULL, ic, TRUE);
10569   freeAsmop (result, NULL, ic, TRUE);
10570 }
10571
10572 /*-----------------------------------------------------------------*/
10573 /* genNearPointerSet - emitcode for near pointer put               */
10574 /*-----------------------------------------------------------------*/
10575 static void
10576 genNearPointerSet (operand * right,
10577                    operand * result,
10578                    iCode * ic,
10579                    iCode * pi)
10580 {
10581   asmop *aop = NULL;
10582   regs *preg = NULL;
10583   char *rname, *l;
10584   sym_link *retype, *letype;
10585   sym_link *ptype = operandType (result);
10586
10587   D (emitcode (";", "genNearPointerSet"));
10588
10589   retype = getSpec (operandType (right));
10590   letype = getSpec (ptype);
10591
10592   aopOp (result, ic, FALSE);
10593
10594   /* if the result is rematerializable &
10595      in data space & not a bit variable */
10596   if (AOP_TYPE (result) == AOP_IMMD &&
10597       DCL_TYPE (ptype) == POINTER &&
10598       !IS_BITVAR (retype) &&
10599       !IS_BITVAR (letype))
10600     {
10601       genDataPointerSet (right, result, ic);
10602       return;
10603     }
10604
10605   /* if the value is already in a pointer register
10606      then don't need anything more */
10607   if (!AOP_INPREG (AOP (result)))
10608     {
10609         if (
10610             //AOP_TYPE (result) == AOP_STK
10611             IS_AOP_PREG(result)
10612             )
10613         {
10614             // Aha, it is a pointer, just in disguise.
10615             rname = aopGet (result, 0, FALSE, FALSE);
10616             if (*rname != '@')
10617             {
10618                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10619                         __FILE__, __LINE__);
10620             }
10621             else
10622             {
10623                 // Expected case.
10624                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10625                 rname++;  // skip the '@'.
10626             }
10627         }
10628         else
10629         {
10630             /* otherwise get a free pointer register */
10631             aop = newAsmop (0);
10632             preg = getFreePtr (ic, &aop, FALSE);
10633             emitcode ("mov", "%s,%s",
10634                       preg->name,
10635                       aopGet (result, 0, FALSE, TRUE));
10636             rname = preg->name;
10637         }
10638     }
10639     else
10640     {
10641         rname = aopGet (result, 0, FALSE, FALSE);
10642     }
10643
10644   aopOp (right, ic, FALSE);
10645
10646   /* if bitfield then unpack the bits */
10647   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10648     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10649   else
10650     {
10651       /* we can just get the values */
10652       int size = AOP_SIZE (right);
10653       int offset = 0;
10654
10655       while (size--)
10656         {
10657           l = aopGet (right, offset, FALSE, TRUE);
10658           if ((*l == '@') || (strcmp (l, "acc") == 0))
10659             {
10660               MOVA (l);
10661               emitcode ("mov", "@%s,a", rname);
10662             }
10663           else
10664             emitcode ("mov", "@%s,%s", rname, l);
10665           if (size || pi)
10666             emitcode ("inc", "%s", rname);
10667           offset++;
10668         }
10669     }
10670
10671   /* now some housekeeping stuff */
10672   if (aop) /* we had to allocate for this iCode */
10673     {
10674       if (pi)
10675         aopPut (result, rname, 0);
10676       freeAsmop (NULL, aop, ic, TRUE);
10677     }
10678   else
10679     {
10680       /* we did not allocate which means left
10681          already in a pointer register, then
10682          if size > 0 && this could be used again
10683          we have to point it back to where it
10684          belongs */
10685       if ((AOP_SIZE (right) > 1 &&
10686            !OP_SYMBOL (result)->remat &&
10687            (OP_SYMBOL (result)->liveTo > ic->seq ||
10688             ic->depth)) &&
10689           !pi)
10690         {
10691           int size = AOP_SIZE (right) - 1;
10692           while (size--)
10693             emitcode ("dec", "%s", rname);
10694         }
10695     }
10696
10697   /* done */
10698   if (pi)
10699     pi->generated = 1;
10700   freeAsmop (right, NULL, ic, TRUE);
10701   freeAsmop (result, NULL, ic, TRUE);
10702 }
10703
10704 /*-----------------------------------------------------------------*/
10705 /* genPagedPointerSet - emitcode for Paged pointer put             */
10706 /*-----------------------------------------------------------------*/
10707 static void
10708 genPagedPointerSet (operand * right,
10709                     operand * result,
10710                     iCode * ic,
10711                     iCode * pi)
10712 {
10713   asmop *aop = NULL;
10714   regs *preg = NULL;
10715   char *rname, *l;
10716   sym_link *retype, *letype;
10717
10718   D (emitcode (";", "genPagedPointerSet"));
10719
10720   retype = getSpec (operandType (right));
10721   letype = getSpec (operandType (result));
10722
10723   aopOp (result, ic, FALSE);
10724
10725   /* if the value is already in a pointer register
10726      then don't need anything more */
10727   if (!AOP_INPREG (AOP (result)))
10728     {
10729       /* otherwise get a free pointer register */
10730       aop = newAsmop (0);
10731       preg = getFreePtr (ic, &aop, FALSE);
10732       emitcode ("mov", "%s,%s",
10733                 preg->name,
10734                 aopGet (result, 0, FALSE, TRUE));
10735       rname = preg->name;
10736     }
10737   else
10738     rname = aopGet (result, 0, FALSE, FALSE);
10739
10740   aopOp (right, ic, FALSE);
10741
10742   /* if bitfield then unpack the bits */
10743   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10744     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10745   else
10746     {
10747       /* we have can just get the values */
10748       int size = AOP_SIZE (right);
10749       int offset = 0;
10750
10751       while (size--)
10752         {
10753           l = aopGet (right, offset, FALSE, TRUE);
10754           MOVA (l);
10755           emitcode ("movx", "@%s,a", rname);
10756
10757           if (size || pi)
10758             emitcode ("inc", "%s", rname);
10759
10760           offset++;
10761         }
10762     }
10763
10764   /* now some housekeeping stuff */
10765   if (aop) /* we had to allocate for this iCode */
10766     {
10767       if (pi)
10768         aopPut (result, rname, 0);
10769       freeAsmop (NULL, aop, ic, TRUE);
10770     }
10771   else
10772     {
10773       /* we did not allocate which means left
10774          already in a pointer register, then
10775          if size > 0 && this could be used again
10776          we have to point it back to where it
10777          belongs */
10778       if (AOP_SIZE (right) > 1 &&
10779           !OP_SYMBOL (result)->remat &&
10780           (OP_SYMBOL (result)->liveTo > ic->seq ||
10781            ic->depth))
10782         {
10783           int size = AOP_SIZE (right) - 1;
10784           while (size--)
10785             emitcode ("dec", "%s", rname);
10786         }
10787     }
10788
10789   /* done */
10790   if (pi) pi->generated = 1;
10791   freeAsmop (result, NULL, ic, TRUE);
10792   freeAsmop (right, NULL, ic, TRUE);
10793 }
10794
10795 /*-----------------------------------------------------------------*/
10796 /* genFarPointerSet - set value from far space                     */
10797 /*-----------------------------------------------------------------*/
10798 static void
10799 genFarPointerSet (operand * right,
10800                   operand * result, iCode * ic, iCode * pi)
10801 {
10802   int size, offset;
10803   sym_link *retype = getSpec (operandType (right));
10804   sym_link *letype = getSpec (operandType (result));
10805
10806   D(emitcode (";", "genFarPointerSet"));
10807
10808   aopOp (result, ic, FALSE);
10809   loadDptrFromOperand (result, FALSE);
10810
10811   /* so dptr now contains the address */
10812   aopOp (right, ic, FALSE);
10813
10814   /* if bit then unpack */
10815   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10816     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10817   else
10818     {
10819       size = AOP_SIZE (right);
10820       offset = 0;
10821
10822       while (size--)
10823         {
10824           char *l = aopGet (right, offset++, FALSE, FALSE);
10825           MOVA (l);
10826           emitcode ("movx", "@dptr,a");
10827           if (size || pi)
10828             emitcode ("inc", "dptr");
10829         }
10830     }
10831   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10832     aopPut (result, "dpl", 0);
10833     aopPut (result, "dph", 1);
10834     pi->generated=1;
10835   }
10836   freeAsmop (result, NULL, ic, TRUE);
10837   freeAsmop (right, NULL, ic, TRUE);
10838 }
10839
10840 /*-----------------------------------------------------------------*/
10841 /* genGenPointerSet - set value from generic pointer space         */
10842 /*-----------------------------------------------------------------*/
10843 static void
10844 genGenPointerSet (operand * right,
10845                   operand * result, iCode * ic, iCode * pi)
10846 {
10847   int size, offset;
10848   sym_link *retype = getSpec (operandType (right));
10849   sym_link *letype = getSpec (operandType (result));
10850
10851   D (emitcode (";", "genGenPointerSet"));
10852
10853   aopOp (result, ic, FALSE);
10854   loadDptrFromOperand (result, TRUE);
10855
10856   /* so dptr now contains the address */
10857   aopOp (right, ic, FALSE);
10858
10859   /* if bit then unpack */
10860   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10861     {
10862       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10863     }
10864   else
10865     {
10866       size = AOP_SIZE (right);
10867       offset = 0;
10868
10869       while (size--)
10870         {
10871           char *l = aopGet (right, offset++, FALSE, FALSE);
10872           MOVA (l);
10873           emitcode ("lcall", "__gptrput");
10874           if (size || pi)
10875             emitcode ("inc", "dptr");
10876         }
10877     }
10878
10879   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10880     aopPut (result, "dpl", 0);
10881     aopPut (result, "dph", 1);
10882     pi->generated=1;
10883   }
10884   freeAsmop (result, NULL, ic, TRUE);
10885   freeAsmop (right, NULL, ic, TRUE);
10886 }
10887
10888 /*-----------------------------------------------------------------*/
10889 /* genPointerSet - stores the value into a pointer location        */
10890 /*-----------------------------------------------------------------*/
10891 static void
10892 genPointerSet (iCode * ic, iCode *pi)
10893 {
10894   operand *right, *result;
10895   sym_link *type, *etype;
10896   int p_type;
10897
10898   D (emitcode (";", "genPointerSet"));
10899
10900   right = IC_RIGHT (ic);
10901   result = IC_RESULT (ic);
10902
10903   /* depending on the type of pointer we need to
10904      move it to the correct pointer register */
10905   type = operandType (result);
10906   etype = getSpec (type);
10907   /* if left is of type of pointer then it is simple */
10908   if (IS_PTR (type) && !IS_FUNC (type->next))
10909     {
10910       p_type = DCL_TYPE (type);
10911     }
10912   else
10913     {
10914       /* we have to go by the storage class */
10915       p_type = PTR_TYPE (SPEC_OCLS (etype));
10916     }
10917
10918   /* special case when cast remat */
10919   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10920       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10921           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10922           type = operandType (result);
10923           p_type = DCL_TYPE (type);
10924   }
10925
10926   /* now that we have the pointer type we assign
10927      the pointer values */
10928   switch (p_type)
10929     {
10930
10931     case POINTER:
10932     case IPOINTER:
10933       genNearPointerSet (right, result, ic, pi);
10934       break;
10935
10936     case PPOINTER:
10937       genPagedPointerSet (right, result, ic, pi);
10938       break;
10939
10940     case FPOINTER:
10941       genFarPointerSet (right, result, ic, pi);
10942       break;
10943
10944     case GPOINTER:
10945       genGenPointerSet (right, result, ic, pi);
10946       break;
10947
10948     default:
10949       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10950               "genPointerSet: illegal pointer type");
10951     }
10952 }
10953
10954 /*-----------------------------------------------------------------*/
10955 /* genIfx - generate code for Ifx statement                        */
10956 /*-----------------------------------------------------------------*/
10957 static void
10958 genIfx (iCode * ic, iCode * popIc)
10959 {
10960   operand *cond = IC_COND (ic);
10961   int isbit = 0;
10962   char *dup = NULL;
10963
10964   D (emitcode (";", "genIfx"));
10965
10966   aopOp (cond, ic, FALSE);
10967
10968   /* get the value into acc */
10969   if (AOP_TYPE (cond) != AOP_CRY)
10970     {
10971       toBoolean (cond);
10972     }
10973   else
10974     {
10975       isbit = 1;
10976       if (AOP(cond)->aopu.aop_dir)
10977         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10978     }
10979
10980   /* the result is now in the accumulator or a directly addressable bit */
10981   freeAsmop (cond, NULL, ic, TRUE);
10982
10983   /* if there was something to be popped then do it */
10984   if (popIc)
10985     genIpop (popIc);
10986
10987   /* if the condition is a bit variable */
10988   if (isbit && dup)
10989     genIfxJump(ic, dup, NULL, NULL, NULL);
10990   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10991     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10992   else if (isbit && !IS_ITEMP (cond))
10993     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10994   else
10995     genIfxJump (ic, "a", NULL, NULL, NULL);
10996
10997   ic->generated = 1;
10998 }
10999
11000 /*-----------------------------------------------------------------*/
11001 /* genAddrOf - generates code for address of                       */
11002 /*-----------------------------------------------------------------*/
11003 static void
11004 genAddrOf (iCode * ic)
11005 {
11006   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11007   int size, offset;
11008
11009   D (emitcode (";", "genAddrOf"));
11010
11011   aopOp (IC_RESULT (ic), ic, FALSE);
11012
11013   /* if the operand is on the stack then we
11014      need to get the stack offset of this
11015      variable */
11016   if (sym->onStack)
11017     {
11018       /* if it has an offset then we need to compute it */
11019       if (sym->stack)
11020         {
11021           int stack_offset = ((sym->stack < 0) ?
11022                               ((char) (sym->stack - _G.nRegsSaved)) :
11023                               ((char) sym->stack)) & 0xff;
11024           if ((abs(stack_offset) == 1) &&
11025               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11026               !isOperandVolatile (IC_RESULT (ic), FALSE))
11027             {
11028               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11029               if (stack_offset > 0)
11030                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11031               else
11032                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11033             }
11034           else
11035             {
11036               emitcode ("mov", "a,%s", SYM_BP (sym));
11037               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11038               aopPut (IC_RESULT (ic), "a", 0);
11039             }
11040         }
11041       else
11042         {
11043           /* we can just move _bp */
11044           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11045         }
11046       /* fill the result with zero */
11047       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11048
11049       offset = 1;
11050       while (size--)
11051         {
11052           aopPut (IC_RESULT (ic), zero, offset++);
11053         }
11054       goto release;
11055     }
11056
11057   /* object not on stack then we need the name */
11058   size = AOP_SIZE (IC_RESULT (ic));
11059   offset = 0;
11060
11061   while (size--)
11062     {
11063       char s[SDCC_NAME_MAX];
11064       if (offset)
11065         sprintf (s, "#(%s >> %d)",
11066                  sym->rname,
11067                  offset * 8);
11068       else
11069         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11070       aopPut (IC_RESULT (ic), s, offset++);
11071     }
11072
11073 release:
11074   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11075
11076 }
11077
11078 /*-----------------------------------------------------------------*/
11079 /* genFarFarAssign - assignment when both are in far space         */
11080 /*-----------------------------------------------------------------*/
11081 static void
11082 genFarFarAssign (operand * result, operand * right, iCode * ic)
11083 {
11084   int size = AOP_SIZE (right);
11085   int offset = 0;
11086   char *l;
11087
11088   D (emitcode (";", "genFarFarAssign"));
11089
11090   /* first push the right side on to the stack */
11091   while (size--)
11092     {
11093       l = aopGet (right, offset++, FALSE, FALSE);
11094       MOVA (l);
11095       emitcode ("push", "acc");
11096     }
11097
11098   freeAsmop (right, NULL, ic, FALSE);
11099   /* now assign DPTR to result */
11100   aopOp (result, ic, FALSE);
11101   size = AOP_SIZE (result);
11102   while (size--)
11103     {
11104       emitcode ("pop", "acc");
11105       aopPut (result, "a", --offset);
11106     }
11107   freeAsmop (result, NULL, ic, FALSE);
11108 }
11109
11110 /*-----------------------------------------------------------------*/
11111 /* genAssign - generate code for assignment                        */
11112 /*-----------------------------------------------------------------*/
11113 static void
11114 genAssign (iCode * ic)
11115 {
11116   operand *result, *right;
11117   int size, offset;
11118   unsigned long lit = 0L;
11119
11120   D (emitcode (";", "genAssign"));
11121
11122   result = IC_RESULT (ic);
11123   right = IC_RIGHT (ic);
11124
11125   /* if they are the same */
11126   if (operandsEqu (result, right) &&
11127       !isOperandVolatile (result, FALSE) &&
11128       !isOperandVolatile (right, FALSE))
11129     return;
11130
11131   aopOp (right, ic, FALSE);
11132
11133   /* special case both in far space */
11134   if (AOP_TYPE (right) == AOP_DPTR &&
11135       IS_TRUE_SYMOP (result) &&
11136       isOperandInFarSpace (result))
11137     {
11138       genFarFarAssign (result, right, ic);
11139       return;
11140     }
11141
11142   aopOp (result, ic, TRUE);
11143
11144   /* if they are the same registers */
11145   if (sameRegs (AOP (right), AOP (result)) &&
11146       !isOperandVolatile (result, FALSE) &&
11147       !isOperandVolatile (right, FALSE))
11148     goto release;
11149
11150   /* if the result is a bit */
11151   if (AOP_TYPE (result) == AOP_CRY)
11152     {
11153       assignBit (result, right);
11154       goto release;
11155     }
11156
11157   /* bit variables done */
11158   /* general case */
11159   size = AOP_SIZE (result);
11160   offset = 0;
11161   if (AOP_TYPE (right) == AOP_LIT)
11162     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11163
11164   if ((size > 1) &&
11165       (AOP_TYPE (result) != AOP_REG) &&
11166       (AOP_TYPE (right) == AOP_LIT) &&
11167       !IS_FLOAT (operandType (right)) &&
11168       (lit < 256L))
11169     {
11170       while ((size) && (lit))
11171         {
11172           aopPut (result,
11173                   aopGet (right, offset, FALSE, FALSE),
11174                   offset);
11175           lit >>= 8;
11176           offset++;
11177           size--;
11178         }
11179       /* And now fill the rest with zeros. */
11180       if (size)
11181         {
11182           emitcode ("clr", "a");
11183         }
11184       while (size--)
11185         {
11186           aopPut (result, "a", offset);
11187           offset++;
11188         }
11189     }
11190   else
11191     {
11192       while (size--)
11193         {
11194           aopPut (result,
11195                   aopGet (right, offset, FALSE, FALSE),
11196                   offset);
11197           offset++;
11198         }
11199     }
11200
11201 release:
11202   freeAsmop (result, NULL, ic, TRUE);
11203   freeAsmop (right, NULL, ic, TRUE);
11204 }
11205
11206 /*-----------------------------------------------------------------*/
11207 /* genJumpTab - generates code for jump table                      */
11208 /*-----------------------------------------------------------------*/
11209 static void
11210 genJumpTab (iCode * ic)
11211 {
11212   symbol *jtab,*jtablo,*jtabhi;
11213   char *l;
11214   unsigned int count;
11215
11216   D (emitcode (";", "genJumpTab"));
11217
11218   count = elementsInSet( IC_JTLABELS (ic) );
11219
11220   if( count <= 16 )
11221     {
11222       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11223          if the switch argument is in a register.
11224          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11225       /* Peephole may not convert ljmp to sjmp or ret
11226          labelIsReturnOnly & labelInRange must check
11227          currPl->ic->op != JUMPTABLE */
11228       aopOp (IC_JTCOND (ic), ic, FALSE);
11229       /* get the condition into accumulator */
11230       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11231       MOVA (l);
11232       /* multiply by three */
11233       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11234         {
11235           emitcode ("mov", "b,#3");
11236           emitcode ("mul", "ab");
11237         }
11238       else
11239         {
11240           emitcode ("add", "a,acc");
11241           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11242         }
11243       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11244
11245       jtab = newiTempLabel (NULL);
11246       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11247       emitcode ("jmp", "@a+dptr");
11248       emitLabel (jtab);
11249       /* now generate the jump labels */
11250       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11251            jtab = setNextItem (IC_JTLABELS (ic)))
11252         emitcode ("ljmp", "%05d$", jtab->key + 100);
11253     }
11254   else
11255     {
11256       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11257          if the switch argument is in a register.
11258          For n>6 this algorithm may be more compact */
11259       jtablo = newiTempLabel (NULL);
11260       jtabhi = newiTempLabel (NULL);
11261
11262       /* get the condition into accumulator.
11263          Using b as temporary storage, if register push/pop is needed */
11264       aopOp (IC_JTCOND (ic), ic, FALSE);
11265       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11266       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11267           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11268         {
11269           // (MB) what if B is in use???
11270           wassertl(!BINUSE, "B was in use");
11271           emitcode ("mov", "b,%s", l);
11272           l = "b";
11273         }
11274       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11275       MOVA (l);
11276       if( count <= 112 )
11277         {
11278           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11279           emitcode ("movc", "a,@a+pc");
11280           emitcode ("push", "acc");
11281
11282           MOVA (l);
11283           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11284           emitcode ("movc", "a,@a+pc");
11285           emitcode ("push", "acc");
11286         }
11287       else
11288         {
11289           /* this scales up to n<=255, but needs two more bytes
11290              and changes dptr */
11291           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11292           emitcode ("movc", "a,@a+dptr");
11293           emitcode ("push", "acc");
11294
11295           MOVA (l);
11296           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11297           emitcode ("movc", "a,@a+dptr");
11298           emitcode ("push", "acc");
11299         }
11300
11301       emitcode ("ret", "");
11302
11303       /* now generate jump table, LSB */
11304       emitLabel (jtablo);
11305       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11306            jtab = setNextItem (IC_JTLABELS (ic)))
11307         emitcode (".db", "%05d$", jtab->key + 100);
11308
11309       /* now generate jump table, MSB */
11310       emitLabel (jtabhi);
11311       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11312            jtab = setNextItem (IC_JTLABELS (ic)))
11313          emitcode (".db", "%05d$>>8", jtab->key + 100);
11314     }
11315 }
11316
11317 /*-----------------------------------------------------------------*/
11318 /* genCast - gen code for casting                                  */
11319 /*-----------------------------------------------------------------*/
11320 static void
11321 genCast (iCode * ic)
11322 {
11323   operand *result = IC_RESULT (ic);
11324   sym_link *ctype = operandType (IC_LEFT (ic));
11325   sym_link *rtype = operandType (IC_RIGHT (ic));
11326   operand *right = IC_RIGHT (ic);
11327   int size, offset;
11328
11329   D (emitcode (";", "genCast"));
11330
11331   /* if they are equivalent then do nothing */
11332   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11333     return;
11334
11335   aopOp (right, ic, FALSE);
11336   aopOp (result, ic, FALSE);
11337
11338   /* if the result is a bit (and not a bitfield) */
11339   if (IS_BIT (OP_SYMBOL (result)->type))
11340     {
11341       assignBit (result, right);
11342       goto release;
11343     }
11344
11345   /* if they are the same size : or less */
11346   if (AOP_SIZE (result) <= AOP_SIZE (right))
11347     {
11348
11349       /* if they are in the same place */
11350       if (sameRegs (AOP (right), AOP (result)))
11351         goto release;
11352
11353       /* if they in different places then copy */
11354       size = AOP_SIZE (result);
11355       offset = 0;
11356       while (size--)
11357         {
11358           aopPut (result,
11359                   aopGet (right, offset, FALSE, FALSE),
11360                   offset);
11361           offset++;
11362         }
11363       goto release;
11364     }
11365
11366   /* if the result is of type pointer */
11367   if (IS_PTR (ctype))
11368     {
11369
11370       int p_type;
11371       sym_link *type = operandType (right);
11372       sym_link *etype = getSpec (type);
11373
11374       /* pointer to generic pointer */
11375       if (IS_GENPTR (ctype))
11376         {
11377           if (IS_PTR (type))
11378             {
11379               p_type = DCL_TYPE (type);
11380             }
11381           else
11382             {
11383               if (SPEC_SCLS(etype)==S_REGISTER) {
11384                 // let's assume it is a generic pointer
11385                 p_type=GPOINTER;
11386               } else {
11387                 /* we have to go by the storage class */
11388                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11389               }
11390             }
11391
11392           /* the first two bytes are known */
11393           size = GPTRSIZE - 1;
11394           offset = 0;
11395           while (size--)
11396             {
11397               aopPut (result,
11398                       aopGet (right, offset, FALSE, FALSE),
11399                       offset);
11400               offset++;
11401             }
11402           /* the last byte depending on type */
11403             {
11404                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11405                 char gpValStr[10];
11406
11407                 if (gpVal == -1)
11408                 {
11409                     // pointerTypeToGPByte will have bitched.
11410                     exit(1);
11411                 }
11412
11413                 sprintf(gpValStr, "#0x%x", gpVal);
11414                 aopPut (result, gpValStr, GPTRSIZE - 1);
11415             }
11416           goto release;
11417         }
11418
11419       /* just copy the pointers */
11420       size = AOP_SIZE (result);
11421       offset = 0;
11422       while (size--)
11423         {
11424           aopPut (result,
11425                   aopGet (right, offset, FALSE, FALSE),
11426                   offset);
11427           offset++;
11428         }
11429       goto release;
11430     }
11431
11432   /* so we now know that the size of destination is greater
11433      than the size of the source */
11434   /* we move to result for the size of source */
11435   size = AOP_SIZE (right);
11436   offset = 0;
11437   while (size--)
11438     {
11439       aopPut (result,
11440               aopGet (right, offset, FALSE, FALSE),
11441               offset);
11442       offset++;
11443     }
11444
11445   /* now depending on the sign of the source && destination */
11446   size = AOP_SIZE (result) - AOP_SIZE (right);
11447   /* if unsigned or not an integral type */
11448   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11449     {
11450       while (size--)
11451         aopPut (result, zero, offset++);
11452     }
11453   else
11454     {
11455       /* we need to extend the sign :{ */
11456       char *l = aopGet (right, AOP_SIZE (right) - 1,
11457                         FALSE, FALSE);
11458       MOVA (l);
11459       emitcode ("rlc", "a");
11460       emitcode ("subb", "a,acc");
11461       while (size--)
11462         aopPut (result, "a", offset++);
11463     }
11464
11465   /* we are done hurray !!!! */
11466
11467 release:
11468   freeAsmop (result, NULL, ic, TRUE);
11469   freeAsmop (right, NULL, ic, TRUE);
11470 }
11471
11472 /*-----------------------------------------------------------------*/
11473 /* genDjnz - generate decrement & jump if not zero instrucion      */
11474 /*-----------------------------------------------------------------*/
11475 static int
11476 genDjnz (iCode * ic, iCode * ifx)
11477 {
11478   symbol *lbl, *lbl1;
11479   if (!ifx)
11480     return 0;
11481
11482   /* if the if condition has a false label
11483      then we cannot save */
11484   if (IC_FALSE (ifx))
11485     return 0;
11486
11487   /* if the minus is not of the form a = a - 1 */
11488   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11489       !IS_OP_LITERAL (IC_RIGHT (ic)))
11490     return 0;
11491
11492   if (operandLitValue (IC_RIGHT (ic)) != 1)
11493     return 0;
11494
11495   /* if the size of this greater than one then no
11496      saving */
11497   if (getSize (operandType (IC_RESULT (ic))) > 1)
11498     return 0;
11499
11500   /* otherwise we can save BIG */
11501
11502   D (emitcode (";", "genDjnz"));
11503
11504   lbl = newiTempLabel (NULL);
11505   lbl1 = newiTempLabel (NULL);
11506
11507   aopOp (IC_RESULT (ic), ic, FALSE);
11508
11509   if (AOP_NEEDSACC(IC_RESULT(ic)))
11510   {
11511       /* If the result is accessed indirectly via
11512        * the accumulator, we must explicitly write
11513        * it back after the decrement.
11514        */
11515       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11516
11517       if (strcmp(rByte, "a"))
11518       {
11519            /* Something is hopelessly wrong */
11520            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11521                    __FILE__, __LINE__);
11522            /* We can just give up; the generated code will be inefficient,
11523             * but what the hey.
11524             */
11525            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11526            return 0;
11527       }
11528       emitcode ("dec", "%s", rByte);
11529       aopPut (IC_RESULT (ic), rByte, 0);
11530       emitcode ("jnz", "%05d$", lbl->key + 100);
11531   }
11532   else if (IS_AOP_PREG (IC_RESULT (ic)))
11533     {
11534       emitcode ("dec", "%s",
11535                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11536       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11537       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11538       ifx->generated = 1;
11539       emitcode ("jnz", "%05d$", lbl->key + 100);
11540     }
11541   else
11542     {
11543       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11544                 lbl->key + 100);
11545     }
11546   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11547   emitLabel (lbl);
11548   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11549   emitLabel (lbl1);
11550
11551   if (!ifx->generated)
11552       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11553   ifx->generated = 1;
11554   return 1;
11555 }
11556
11557 /*-----------------------------------------------------------------*/
11558 /* genReceive - generate code for a receive iCode                  */
11559 /*-----------------------------------------------------------------*/
11560 static void
11561 genReceive (iCode * ic)
11562 {
11563   int size = getSize (operandType (IC_RESULT (ic)));
11564   int offset = 0;
11565
11566   D (emitcode (";", "genReceive"));
11567
11568   if (ic->argreg == 1)
11569     { /* first parameter */
11570       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11571            isOperandInPagedSpace (IC_RESULT (ic))) &&
11572           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11573            IS_TRUE_SYMOP (IC_RESULT (ic))))
11574         {
11575           regs *tempRegs[4];
11576           int receivingA = 0;
11577           int roffset = 0;
11578
11579           for (offset = 0; offset<size; offset++)
11580             if (!strcmp (fReturn[offset], "a"))
11581               receivingA = 1;
11582
11583           if (!receivingA)
11584             {
11585               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11586                 {
11587                   for (offset = size-1; offset>0; offset--)
11588                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11589                   emitcode("mov","a,%s", fReturn[0]);
11590                   _G.accInUse++;
11591                   aopOp (IC_RESULT (ic), ic, FALSE);
11592                   _G.accInUse--;
11593                   aopPut (IC_RESULT (ic), "a", offset);
11594                   for (offset = 1; offset<size; offset++)
11595                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11596                   goto release;
11597                 }
11598             }
11599           else
11600             {
11601               if (getTempRegs(tempRegs, size, ic))
11602                 {
11603                   for (offset = 0; offset<size; offset++)
11604                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11605                   aopOp (IC_RESULT (ic), ic, FALSE);
11606                   for (offset = 0; offset<size; offset++)
11607                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11608                   goto release;
11609                 }
11610             }
11611
11612           offset = fReturnSizeMCS51 - size;
11613           while (size--)
11614             {
11615               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11616                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11617               offset++;
11618             }
11619           aopOp (IC_RESULT (ic), ic, FALSE);
11620           size = AOP_SIZE (IC_RESULT (ic));
11621           offset = 0;
11622           while (size--)
11623             {
11624               emitcode ("pop", "acc");
11625               aopPut (IC_RESULT (ic), "a", offset++);
11626             }
11627         }
11628       else
11629         {
11630           _G.accInUse++;
11631           aopOp (IC_RESULT (ic), ic, FALSE);
11632           _G.accInUse--;
11633           assignResultValue (IC_RESULT (ic), NULL);
11634         }
11635     }
11636   else if (ic->argreg > 12)
11637     { /* bit parameters */
11638       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11639
11640       BitBankUsed = 1;
11641       if (!reg || reg->rIdx != ic->argreg-5)
11642         {
11643           aopOp (IC_RESULT (ic), ic, FALSE);
11644           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11645           outBitC(IC_RESULT (ic));
11646         }
11647     }
11648   else
11649     { /* other parameters */
11650       int rb1off ;
11651       aopOp (IC_RESULT (ic), ic, FALSE);
11652       rb1off = ic->argreg;
11653       while (size--)
11654         {
11655           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11656         }
11657     }
11658
11659 release:
11660   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11661 }
11662
11663 /*-----------------------------------------------------------------*/
11664 /* genDummyRead - generate code for dummy read of volatiles        */
11665 /*-----------------------------------------------------------------*/
11666 static void
11667 genDummyRead (iCode * ic)
11668 {
11669   operand *op;
11670   int size, offset;
11671
11672   D (emitcode(";", "genDummyRead"));
11673
11674   op = IC_RIGHT (ic);
11675   if (op && IS_SYMOP (op))
11676     {
11677       aopOp (op, ic, FALSE);
11678
11679       /* if the result is a bit */
11680       if (AOP_TYPE (op) == AOP_CRY)
11681         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11682       else
11683         {
11684           /* bit variables done */
11685           /* general case */
11686           size = AOP_SIZE (op);
11687           offset = 0;
11688           while (size--)
11689           {
11690             MOVA (aopGet (op, offset, FALSE, FALSE));
11691             offset++;
11692           }
11693         }
11694
11695       freeAsmop (op, NULL, ic, TRUE);
11696     }
11697
11698   op = IC_LEFT (ic);
11699   if (op && IS_SYMOP (op))
11700     {
11701       aopOp (op, ic, FALSE);
11702
11703       /* if the result is a bit */
11704       if (AOP_TYPE (op) == AOP_CRY)
11705         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11706       else
11707         {
11708           /* bit variables done */
11709           /* general case */
11710           size = AOP_SIZE (op);
11711           offset = 0;
11712           while (size--)
11713           {
11714             MOVA (aopGet (op, offset, FALSE, FALSE));
11715             offset++;
11716           }
11717         }
11718
11719       freeAsmop (op, NULL, ic, TRUE);
11720     }
11721 }
11722
11723 /*-----------------------------------------------------------------*/
11724 /* genCritical - generate code for start of a critical sequence    */
11725 /*-----------------------------------------------------------------*/
11726 static void
11727 genCritical (iCode *ic)
11728 {
11729   symbol *tlbl = newiTempLabel (NULL);
11730
11731   D (emitcode(";", "genCritical"));
11732
11733   if (IC_RESULT (ic))
11734     {
11735       aopOp (IC_RESULT (ic), ic, TRUE);
11736       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11737       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11738       aopPut (IC_RESULT (ic), zero, 0);
11739       emitLabel (tlbl);
11740       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11741     }
11742   else
11743     {
11744       emitcode ("setb", "c");
11745       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11746       emitcode ("clr", "c");
11747       emitLabel (tlbl);
11748       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11749     }
11750 }
11751
11752 /*-----------------------------------------------------------------*/
11753 /* genEndCritical - generate code for end of a critical sequence   */
11754 /*-----------------------------------------------------------------*/
11755 static void
11756 genEndCritical (iCode *ic)
11757 {
11758   D(emitcode(";", "genEndCritical"));
11759
11760   if (IC_RIGHT (ic))
11761     {
11762       aopOp (IC_RIGHT (ic), ic, FALSE);
11763       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11764         {
11765           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11766           emitcode ("mov", "ea,c");
11767         }
11768       else
11769         {
11770           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11771             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11772           emitcode ("rrc", "a");
11773           emitcode ("mov", "ea,c");
11774         }
11775       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11776     }
11777   else
11778     {
11779       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11780       emitcode ("mov", "ea,c");
11781     }
11782 }
11783
11784 /*-----------------------------------------------------------------*/
11785 /* gen51Code - generate code for 8051 based controllers            */
11786 /*-----------------------------------------------------------------*/
11787 void
11788 gen51Code (iCode * lic)
11789 {
11790   iCode *ic;
11791   int cln = 0;
11792   /* int cseq = 0; */
11793
11794   _G.currentFunc = NULL;
11795   lineHead = lineCurr = NULL;
11796
11797   /* print the allocation information */
11798   if (allocInfo && currFunc)
11799     printAllocInfo (currFunc, codeOutBuf);
11800   /* if debug information required */
11801   if (options.debug && currFunc)
11802     {
11803       debugFile->writeFunction (currFunc, lic);
11804     }
11805   /* stack pointer name */
11806   if (options.useXstack)
11807     spname = "_spx";
11808   else
11809     spname = "sp";
11810
11811
11812   for (ic = lic; ic; ic = ic->next)
11813     {
11814       _G.current_iCode = ic;
11815
11816       if (ic->lineno && cln != ic->lineno)
11817         {
11818           if (options.debug)
11819             {
11820               debugFile->writeCLine (ic);
11821             }
11822           if (!options.noCcodeInAsm) {
11823             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11824                       printCLine(ic->filename, ic->lineno));
11825           }
11826           cln = ic->lineno;
11827         }
11828       #if 0
11829       if (ic->seqPoint && ic->seqPoint != cseq)
11830         {
11831           emitcode (";", "sequence point %d", ic->seqPoint);
11832           cseq = ic->seqPoint;
11833         }
11834       #endif
11835       if (options.iCodeInAsm) {
11836         char regsInUse[80];
11837         int i;
11838         char *iLine;
11839
11840         #if 0
11841         for (i=0; i<8; i++) {
11842           sprintf (&regsInUse[i],
11843                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11844         regsInUse[i]=0;
11845         #else
11846         strcpy (regsInUse, "--------");
11847         for (i=0; i < 8; i++) {
11848           if (bitVectBitValue (ic->rMask, i))
11849             {
11850               int offset = regs8051[i].offset;
11851               regsInUse[offset] = offset + '0'; /* show rMask */
11852             }
11853         #endif
11854         }
11855         iLine = printILine(ic);
11856         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11857         dbuf_free(iLine);
11858       }
11859       /* if the result is marked as
11860          spilt and rematerializable or code for
11861          this has already been generated then
11862          do nothing */
11863       if (resultRemat (ic) || ic->generated)
11864         continue;
11865
11866       /* depending on the operation */
11867       switch (ic->op)
11868         {
11869         case '!':
11870           genNot (ic);
11871           break;
11872
11873         case '~':
11874           genCpl (ic);
11875           break;
11876
11877         case UNARYMINUS:
11878           genUminus (ic);
11879           break;
11880
11881         case IPUSH:
11882           genIpush (ic);
11883           break;
11884
11885         case IPOP:
11886           /* IPOP happens only when trying to restore a
11887              spilt live range, if there is an ifx statement
11888              following this pop then the if statement might
11889              be using some of the registers being popped which
11890              would destory the contents of the register so
11891              we need to check for this condition and handle it */
11892           if (ic->next &&
11893               ic->next->op == IFX &&
11894               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11895             genIfx (ic->next, ic);
11896           else
11897             genIpop (ic);
11898           break;
11899
11900         case CALL:
11901           genCall (ic);
11902           break;
11903
11904         case PCALL:
11905           genPcall (ic);
11906           break;
11907
11908         case FUNCTION:
11909           genFunction (ic);
11910           break;
11911
11912         case ENDFUNCTION:
11913           genEndFunction (ic);
11914           break;
11915
11916         case RETURN:
11917           genRet (ic);
11918           break;
11919
11920         case LABEL:
11921           genLabel (ic);
11922           break;
11923
11924         case GOTO:
11925           genGoto (ic);
11926           break;
11927
11928         case '+':
11929           genPlus (ic);
11930           break;
11931
11932         case '-':
11933           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11934             genMinus (ic);
11935           break;
11936
11937         case '*':
11938           genMult (ic);
11939           break;
11940
11941         case '/':
11942           genDiv (ic);
11943           break;
11944
11945         case '%':
11946           genMod (ic);
11947           break;
11948
11949         case '>':
11950           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11951           break;
11952
11953         case '<':
11954           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11955           break;
11956
11957         case LE_OP:
11958         case GE_OP:
11959         case NE_OP:
11960
11961           /* note these two are xlated by algebraic equivalence
11962              in decorateType() in SDCCast.c */
11963           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11964                   "got '>=' or '<=' shouldn't have come here");
11965           break;
11966
11967         case EQ_OP:
11968           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11969           break;
11970
11971         case AND_OP:
11972           genAndOp (ic);
11973           break;
11974
11975         case OR_OP:
11976           genOrOp (ic);
11977           break;
11978
11979         case '^':
11980           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11981           break;
11982
11983         case '|':
11984           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11985           break;
11986
11987         case BITWISEAND:
11988           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11989           break;
11990
11991         case INLINEASM:
11992           genInline (ic);
11993           break;
11994
11995         case RRC:
11996           genRRC (ic);
11997           break;
11998
11999         case RLC:
12000           genRLC (ic);
12001           break;
12002
12003         case GETHBIT:
12004           genGetHbit (ic);
12005           break;
12006
12007         case GETABIT:
12008           genGetAbit (ic);
12009           break;
12010
12011         case GETBYTE:
12012           genGetByte (ic);
12013           break;
12014
12015         case GETWORD:
12016           genGetWord (ic);
12017           break;
12018
12019         case LEFT_OP:
12020           genLeftShift (ic);
12021           break;
12022
12023         case RIGHT_OP:
12024           genRightShift (ic);
12025           break;
12026
12027         case GET_VALUE_AT_ADDRESS:
12028           genPointerGet (ic,
12029                          hasInc (IC_LEFT (ic), ic,
12030                                  getSize (operandType (IC_RESULT (ic)))),
12031                          ifxForOp (IC_RESULT (ic), ic) );
12032           break;
12033
12034         case '=':
12035           if (POINTER_SET (ic))
12036             genPointerSet (ic,
12037                            hasInc (IC_RESULT (ic), ic,
12038                                    getSize (operandType (IC_RIGHT (ic)))));
12039           else
12040             genAssign (ic);
12041           break;
12042
12043         case IFX:
12044           genIfx (ic, NULL);
12045           break;
12046
12047         case ADDRESS_OF:
12048           genAddrOf (ic);
12049           break;
12050
12051         case JUMPTABLE:
12052           genJumpTab (ic);
12053           break;
12054
12055         case CAST:
12056           genCast (ic);
12057           break;
12058
12059         case RECEIVE:
12060           genReceive (ic);
12061           break;
12062
12063         case SEND:
12064           addSet (&_G.sendSet, ic);
12065           break;
12066
12067         case DUMMY_READ_VOLATILE:
12068           genDummyRead (ic);
12069           break;
12070
12071         case CRITICAL:
12072           genCritical (ic);
12073           break;
12074
12075         case ENDCRITICAL:
12076           genEndCritical (ic);
12077           break;
12078
12079         case SWAP:
12080           genSwap (ic);
12081           break;
12082
12083         default:
12084           ic = ic;
12085         }
12086     }
12087
12088   _G.current_iCode = NULL;
12089
12090   /* now we are ready to call the
12091      peep hole optimizer */
12092   if (!options.nopeep)
12093     peepHole (&lineHead);
12094
12095   /* now do the actual printing */
12096   printLine (lineHead, codeOutBuf);
12097   return;
12098 }