* src/mcs51/gen.c (saveRegisters, unsaveRegisters): free some bitVects,
[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.noGenComments) {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 && *lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191     }
192
193   lineCurr->isInline = _G.inLine;
194   lineCurr->isDebug = _G.debugLine;
195   lineCurr->ic = _G.current_iCode;
196   lineCurr->isComment = (*lbp==';');
197   va_end (ap);
198
199   dbuf_destroy(&dbuf);
200 }
201
202 static void
203 emitLabel (symbol *tlbl)
204 {
205   emitcode ("", "%05d$:", tlbl->key + 100);
206   lineCurr->isLabel = 1;
207 }
208
209 /*-----------------------------------------------------------------*/
210 /* mcs51_emitDebuggerSymbol - associate the current code location  */
211 /*   with a debugger symbol                                        */
212 /*-----------------------------------------------------------------*/
213 void
214 mcs51_emitDebuggerSymbol (char * debugSym)
215 {
216   _G.debugLine = 1;
217   emitcode ("", "%s ==.", debugSym);
218   _G.debugLine = 0;
219 }
220
221 /*-----------------------------------------------------------------*/
222 /* mova - moves specified value into accumulator                   */
223 /*-----------------------------------------------------------------*/
224 static void
225 mova (const char *x)
226 {
227   /* do some early peephole optimization */
228   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
229     return;
230
231   /* if it is a literal mov try to get it cheaper */
232   if (*x == '#' &&
233       rtrackMoveALit(x))
234     return;
235
236   emitcode("mov", "a,%s", x);
237 }
238
239 /*-----------------------------------------------------------------*/
240 /* movb - moves specified value into register b                    */
241 /*-----------------------------------------------------------------*/
242 static void
243 movb (const char *x)
244 {
245   /* do some early peephole optimization */
246   if (!strncmp(x, "b", 2))
247     return;
248
249   /* if it is a literal mov try to get it cheaper */
250   if (*x == '#')
251     {
252       emitcode("mov","b,%s", rtrackGetLit(x));
253       return;
254     }
255
256   emitcode("mov","b,%s", x);
257 }
258
259 /*-----------------------------------------------------------------*/
260 /* pushB - saves register B if necessary                           */
261 /*-----------------------------------------------------------------*/
262 static bool
263 pushB (void)
264 {
265   bool pushedB = FALSE;
266
267   if (BINUSE)
268     {
269       emitcode ("push", "b");
270 //    printf("B was in use !\n");
271       pushedB = TRUE;
272     }
273   else
274     {
275       OPINB++;
276     }
277   return pushedB;
278 }
279
280 /*-----------------------------------------------------------------*/
281 /* popB - restores value of register B if necessary                */
282 /*-----------------------------------------------------------------*/
283 static void
284 popB (bool pushedB)
285 {
286   if (pushedB)
287     {
288       emitcode ("pop", "b");
289     }
290   else
291     {
292       OPINB--;
293     }
294 }
295
296 /*-----------------------------------------------------------------*/
297 /* pushReg - saves register                                        */
298 /*-----------------------------------------------------------------*/
299 static bool
300 pushReg (int index, bool bits_pushed)
301 {
302   regs * reg = REG_WITH_INDEX (index);
303   if (reg->type == REG_BIT)
304     {
305       if (!bits_pushed)
306         emitcode ("push", "%s", reg->base);
307       return TRUE;
308     }
309   else
310     emitcode ("push", "%s", reg->dname);
311   return bits_pushed;
312 }
313
314 /*-----------------------------------------------------------------*/
315 /* popReg - restores register                                      */
316 /*-----------------------------------------------------------------*/
317 static bool
318 popReg (int index, bool bits_popped)
319 {
320   regs * reg = REG_WITH_INDEX (index);
321   if (reg->type == REG_BIT)
322     {
323       if (!bits_popped)
324         emitcode ("pop", "%s", reg->base);
325       return TRUE;
326     }
327   else
328     emitcode ("pop", "%s", reg->dname);
329   return bits_popped;
330 }
331
332 /*-----------------------------------------------------------------*/
333 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
334 /*-----------------------------------------------------------------*/
335 static regs *
336 getFreePtr (iCode * ic, asmop ** aopp, bool result)
337 {
338   bool r0iu, r1iu;
339   bool r0ou, r1ou;
340
341   /* the logic: if r0 & r1 used in the instruction
342      then we are in trouble otherwise */
343
344   /* first check if r0 & r1 are used by this
345      instruction, in which case we are in trouble */
346   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
347   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
348   if (r0iu && r1iu) {
349       goto endOfWorld;
350     }
351
352   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
353   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
354
355   /* if no usage of r0 then return it */
356   if (!r0iu && !r0ou)
357     {
358       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
359       (*aopp)->type = AOP_R0;
360
361       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
362     }
363
364   /* if no usage of r1 then return it */
365   if (!r1iu && !r1ou)
366     {
367       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
368       (*aopp)->type = AOP_R1;
369
370       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
371     }
372
373   /* now we know they both have usage */
374   /* if r0 not used in this instruction */
375   if (!r0iu)
376     {
377       /* push it if not already pushed */
378       if (ic->op == IPUSH)
379         {
380           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
381           R0INB++;
382         }
383       else if (!_G.r0Pushed)
384         {
385           emitcode ("push", "%s",
386                     REG_WITH_INDEX (R0_IDX)->dname);
387           _G.r0Pushed++;
388         }
389
390       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
391       (*aopp)->type = AOP_R0;
392
393       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
394     }
395
396   /* if r1 not used then */
397
398   if (!r1iu)
399     {
400       /* push it if not already pushed */
401       if (ic->op == IPUSH)
402         {
403           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
404           R1INB++;
405         }
406       else if (!_G.r1Pushed)
407         {
408           emitcode ("push", "%s",
409                     REG_WITH_INDEX (R1_IDX)->dname);
410           _G.r1Pushed++;
411         }
412
413       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
414       (*aopp)->type = AOP_R1;
415       return REG_WITH_INDEX (R1_IDX);
416     }
417
418 endOfWorld:
419   /* I said end of world, but not quite end of world yet */
420   /* if this is a result then we can push it on the stack */
421   if (result)
422     {
423       (*aopp)->type = AOP_STK;
424       return NULL;
425     }
426   /* in the case that result AND left AND right needs a pointer reg
427      we can safely use the result's */
428   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
429     {
430       (*aopp)->type = AOP_R0;
431       return REG_WITH_INDEX (R0_IDX);
432     }
433   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
434     {
435       (*aopp)->type = AOP_R1;
436       return REG_WITH_INDEX (R1_IDX);
437     }
438
439   /* now this is REALLY the end of the world */
440   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
441           "getFreePtr should never reach here");
442   exit (1);
443 }
444
445
446 /*-----------------------------------------------------------------*/
447 /* getTempRegs - initialize an array of pointers to GPR registers */
448 /*               that are not in use. Returns 1 if the requested   */
449 /*               number of registers were available, 0 otherwise.  */
450 /*-----------------------------------------------------------------*/
451 int
452 getTempRegs(regs **tempRegs, int size, iCode *ic)
453 {
454   bitVect * freeRegs;
455   int i;
456   int offset;
457
458   if (!ic)
459     ic = _G.current_iCode;
460   if (!ic)
461     return 0;
462   if (!_G.currentFunc)
463     return 0;
464
465   freeRegs = newBitVect(8);
466   bitVectSetBit (freeRegs, R2_IDX);
467   bitVectSetBit (freeRegs, R3_IDX);
468   bitVectSetBit (freeRegs, R4_IDX);
469   bitVectSetBit (freeRegs, R5_IDX);
470   bitVectSetBit (freeRegs, R6_IDX);
471   bitVectSetBit (freeRegs, R7_IDX);
472
473   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
474     {
475       bitVect * newfreeRegs;
476       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
477       freeBitVect(freeRegs);
478       freeRegs = newfreeRegs;
479     }
480   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
481
482   offset = 0;
483   for (i=0; i<freeRegs->size; i++)
484     {
485       if (bitVectBitValue(freeRegs,i))
486         tempRegs[offset++] = REG_WITH_INDEX(i);
487       if (offset>=size)
488         {
489           freeBitVect(freeRegs);
490           return 1;
491         }
492     }
493
494   freeBitVect(freeRegs);
495   return 0;
496 }
497
498
499 /*-----------------------------------------------------------------*/
500 /* newAsmop - creates a new asmOp                                  */
501 /*-----------------------------------------------------------------*/
502 static asmop *
503 newAsmop (short type)
504 {
505   asmop *aop;
506
507   aop = Safe_calloc (1, sizeof (asmop));
508   aop->type = type;
509   aop->allocated = 1;
510   return aop;
511 }
512
513 /*-----------------------------------------------------------------*/
514 /* pointerCode - returns the code for a pointer type               */
515 /*-----------------------------------------------------------------*/
516 static int
517 pointerCode (sym_link * etype)
518 {
519
520   return PTR_TYPE (SPEC_OCLS (etype));
521
522 }
523
524 /*-----------------------------------------------------------------*/
525 /* leftRightUseAcc - returns size of accumulator use by operands   */
526 /*-----------------------------------------------------------------*/
527 static int
528 leftRightUseAcc(iCode *ic)
529 {
530   operand *op;
531   int size;
532   int accuseSize = 0;
533   int accuse = 0;
534
535   if (!ic)
536     {
537       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
538               "null iCode pointer");
539       return 0;
540     }
541
542   if (ic->op == IFX)
543     {
544       op = IC_COND (ic);
545       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
546         {
547           accuse = 1;
548           size = getSize (OP_SYMBOL (op)->type);
549           if (size>accuseSize)
550             accuseSize = size;
551         }
552     }
553   else if (ic->op == JUMPTABLE)
554     {
555       op = IC_JTCOND (ic);
556       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
557         {
558           accuse = 1;
559           size = getSize (OP_SYMBOL (op)->type);
560           if (size>accuseSize)
561             accuseSize = size;
562         }
563     }
564   else
565     {
566       op = IC_LEFT (ic);
567       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
568         {
569           accuse = 1;
570           size = getSize (OP_SYMBOL (op)->type);
571           if (size>accuseSize)
572             accuseSize = size;
573         }
574       op = IC_RIGHT (ic);
575       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
576         {
577           accuse = 1;
578           size = getSize (OP_SYMBOL (op)->type);
579           if (size>accuseSize)
580             accuseSize = size;
581         }
582     }
583
584   if (accuseSize)
585     return accuseSize;
586   else
587     return accuse;
588 }
589
590 /*-----------------------------------------------------------------*/
591 /* aopForSym - for a true symbol                                   */
592 /*-----------------------------------------------------------------*/
593 static asmop *
594 aopForSym (iCode * ic, symbol * sym, bool result)
595 {
596   asmop *aop;
597   memmap *space;
598   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
599
600   wassertl (ic != NULL, "Got a null iCode");
601   wassertl (sym != NULL, "Got a null symbol");
602
603   space = SPEC_OCLS (sym->etype);
604
605   /* if already has one */
606   if (sym->aop)
607     {
608       sym->aop->allocated++;
609       return sym->aop;
610     }
611
612   /* assign depending on the storage class */
613   /* if it is on the stack or indirectly addressable */
614   /* space we need to assign either r0 or r1 to it   */
615   if (sym->onStack || sym->iaccess)
616     {
617       sym->aop = aop = newAsmop (0);
618       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
619       aop->size = getSize (sym->type);
620
621       /* now assign the address of the variable to
622          the pointer register */
623       if (aop->type != AOP_STK)
624         {
625           if (sym->onStack)
626             {
627               signed char offset = ((sym->stack < 0) ?
628                          ((signed char) (sym->stack - _G.nRegsSaved)) :
629                          ((signed char) sym->stack)) & 0xff;
630
631               if ((abs(offset) <= 3) ||
632                   (accuse && (abs(offset) <= 7)))
633                 {
634                   emitcode ("mov", "%s,%s",
635                             aop->aopu.aop_ptr->name, SYM_BP (sym));
636                   while (offset < 0)
637                     {
638                       emitcode ("dec", aop->aopu.aop_ptr->name);
639                       offset++;
640                     }
641                   while (offset > 0)
642                     {
643                       emitcode ("inc", aop->aopu.aop_ptr->name);
644                       offset--;
645                     }
646                 }
647               else
648                 {
649                   if (accuse)
650                     emitcode ("push", "acc");
651                   emitcode ("mov", "a,%s", SYM_BP (sym));
652                   emitcode ("add", "a,#0x%02x", offset & 0xff);
653                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
654                   if (accuse)
655                     emitcode ("pop", "acc");
656                 }
657             }
658           else
659             {
660               emitcode ("mov", "%s,#%s",
661                         aop->aopu.aop_ptr->name,
662                         sym->rname);
663             }
664           aop->paged = space->paged;
665         }
666       else
667         aop->aopu.aop_stk = sym->stack;
668       return aop;
669     }
670
671   /* if in bit space */
672   if (IN_BITSPACE (space))
673     {
674       sym->aop = aop = newAsmop (AOP_CRY);
675       aop->aopu.aop_dir = sym->rname;
676       aop->size = getSize (sym->type);
677       return aop;
678     }
679   /* if it is in direct space */
680   if (IN_DIRSPACE (space))
681     {
682       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
683       //printTypeChainRaw(sym->type, NULL);
684       //printf("space = %s\n", space ? space->sname : "NULL");
685       sym->aop = aop = newAsmop (AOP_DIR);
686       aop->aopu.aop_dir = sym->rname;
687       aop->size = getSize (sym->type);
688       return aop;
689     }
690
691   /* special case for a function */
692   if (IS_FUNC (sym->type))
693     {
694       sym->aop = aop = newAsmop (AOP_IMMD);
695       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
696       aop->size = getSize (sym->type);
697       return aop;
698     }
699
700   /* only remaining is far space */
701   /* in which case DPTR gets the address */
702   sym->aop = aop = newAsmop (AOP_DPTR);
703   emitcode ("mov", "dptr,#%s", sym->rname);
704   aop->size = getSize (sym->type);
705
706   /* if it is in code space */
707   if (IN_CODESPACE (space))
708     aop->code = 1;
709
710   return aop;
711 }
712
713 /*-----------------------------------------------------------------*/
714 /* aopForRemat - rematerialzes an object                           */
715 /*-----------------------------------------------------------------*/
716 static asmop *
717 aopForRemat (symbol * sym)
718 {
719   iCode *ic = sym->rematiCode;
720   asmop *aop = newAsmop (AOP_IMMD);
721   int ptr_type = 0;
722   int val = 0;
723
724   for (;;)
725     {
726       if (ic->op == '+')
727         val += (int) operandLitValue (IC_RIGHT (ic));
728       else if (ic->op == '-')
729         val -= (int) operandLitValue (IC_RIGHT (ic));
730       else if (IS_CAST_ICODE(ic)) {
731               sym_link *from_type = operandType(IC_RIGHT(ic));
732               aop->aopu.aop_immd.from_cast_remat = 1;
733               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
734               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
735               continue;
736       } else break;
737
738       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
739     }
740
741   if (val)
742     {
743       SNPRINTF (buffer, sizeof(buffer),
744                 "(%s %c 0x%04x)",
745                 OP_SYMBOL (IC_LEFT (ic))->rname,
746                 val >= 0 ? '+' : '-',
747                 abs (val) & 0xffff);
748     }
749   else
750     {
751       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
752     }
753
754   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
755   /* set immd2 field if required */
756   if (aop->aopu.aop_immd.from_cast_remat)
757     {
758       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
759       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
760     }
761
762   return aop;
763 }
764
765 /*-----------------------------------------------------------------*/
766 /* regsInCommon - two operands have some registers in common       */
767 /*-----------------------------------------------------------------*/
768 static bool
769 regsInCommon (operand * op1, operand * op2)
770 {
771   symbol *sym1, *sym2;
772   int i;
773
774   /* if they have registers in common */
775   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
776     return FALSE;
777
778   sym1 = OP_SYMBOL (op1);
779   sym2 = OP_SYMBOL (op2);
780
781   if (sym1->nRegs == 0 || sym2->nRegs == 0)
782     return FALSE;
783
784   for (i = 0; i < sym1->nRegs; i++)
785     {
786       int j;
787       if (!sym1->regs[i])
788         continue;
789
790       for (j = 0; j < sym2->nRegs; j++)
791         {
792           if (!sym2->regs[j])
793             continue;
794
795           if (sym2->regs[j] == sym1->regs[i])
796             return TRUE;
797         }
798     }
799
800   return FALSE;
801 }
802
803 /*-----------------------------------------------------------------*/
804 /* operandsEqu - equivalent                                        */
805 /*-----------------------------------------------------------------*/
806 static bool
807 operandsEqu (operand * op1, operand * op2)
808 {
809   symbol *sym1, *sym2;
810
811   /* if they're not symbols */
812   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
813     return FALSE;
814
815   sym1 = OP_SYMBOL (op1);
816   sym2 = OP_SYMBOL (op2);
817
818   /* if both are itemps & one is spilt
819      and the other is not then false */
820   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
821       sym1->isspilt != sym2->isspilt)
822     return FALSE;
823
824   /* if they are the same */
825   if (sym1 == sym2)
826     return TRUE;
827
828   /* if they have the same rname */
829   if (sym1->rname[0] && sym2->rname[0] &&
830       strcmp (sym1->rname, sym2->rname) == 0 &&
831       !(IS_PARM (op2) && IS_ITEMP (op1)))
832     return TRUE;
833
834   /* if left is a tmp & right is not */
835   if (IS_ITEMP (op1) &&
836       !IS_ITEMP (op2) &&
837       sym1->isspilt &&
838       (sym1->usl.spillLoc == sym2))
839     return TRUE;
840
841   if (IS_ITEMP (op2) &&
842       !IS_ITEMP (op1) &&
843       sym2->isspilt &&
844       sym1->level > 0 &&
845       (sym2->usl.spillLoc == sym1))
846     return TRUE;
847
848   return FALSE;
849 }
850
851 /*-----------------------------------------------------------------*/
852 /* sameByte - two asmops have the same address at given offsets    */
853 /*-----------------------------------------------------------------*/
854 static bool
855 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
856 {
857   if (aop1 == aop2 && off1 == off2)
858     return TRUE;
859
860   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
861     return FALSE;
862
863   if (aop1->type != aop2->type)
864     return FALSE;
865
866   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
867     return FALSE;
868
869   return TRUE;
870 }
871
872 /*-----------------------------------------------------------------*/
873 /* sameRegs - two asmops have the same registers                   */
874 /*-----------------------------------------------------------------*/
875 static bool
876 sameRegs (asmop * aop1, asmop * aop2)
877 {
878   int i;
879
880   if (aop1 == aop2)
881     return TRUE;
882
883   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
884     return FALSE;
885
886   if (aop1->type != aop2->type)
887     return FALSE;
888
889   if (aop1->size != aop2->size)
890     return FALSE;
891
892   for (i = 0; i < aop1->size; i++)
893     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
894       return FALSE;
895
896   return TRUE;
897 }
898
899 /*-----------------------------------------------------------------*/
900 /* aopOp - allocates an asmop for an operand  :                    */
901 /*-----------------------------------------------------------------*/
902 static void
903 aopOp (operand * op, iCode * ic, bool result)
904 {
905   asmop *aop;
906   symbol *sym;
907   int i;
908
909   if (!op)
910     return;
911
912   /* if this a literal */
913   if (IS_OP_LITERAL (op))
914     {
915       op->aop = aop = newAsmop (AOP_LIT);
916       aop->aopu.aop_lit = op->operand.valOperand;
917       aop->size = getSize (operandType (op));
918       return;
919     }
920
921   /* if already has a asmop then continue */
922   if (op->aop)
923     {
924       op->aop->allocated++;
925       return;
926     }
927
928   /* if the underlying symbol has a aop */
929   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
930     {
931       op->aop = OP_SYMBOL (op)->aop;
932       op->aop->allocated++;
933       return;
934     }
935
936   /* if this is a true symbol */
937   if (IS_TRUE_SYMOP (op))
938     {
939       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
940       return;
941     }
942
943   /* this is a temporary : this has
944      only five choices :
945      a) register
946      b) spillocation
947      c) rematerialize
948      d) conditional
949      e) can be a return use only */
950
951   sym = OP_SYMBOL (op);
952
953   /* if the type is a conditional */
954   if (sym->regType == REG_CND)
955     {
956       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
957       aop->size = 0;
958       return;
959     }
960
961   /* if it is spilt then two situations
962      a) is rematerialize
963      b) has a spill location */
964   if (sym->isspilt || sym->nRegs == 0)
965     {
966
967       /* rematerialize it NOW */
968       if (sym->remat)
969         {
970           sym->aop = op->aop = aop = aopForRemat (sym);
971           aop->size = getSize (sym->type);
972           return;
973         }
974
975       if (sym->accuse)
976         {
977           int i;
978           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
979           aop->size = getSize (sym->type);
980           for (i = 0; i < 2; i++)
981             aop->aopu.aop_str[i] = accUse[i];
982           return;
983         }
984
985       if (sym->ruonly)
986         {
987           unsigned i;
988
989           aop = op->aop = sym->aop = newAsmop (AOP_STR);
990           aop->size = getSize (sym->type);
991           for (i = 0; i < fReturnSizeMCS51; i++)
992             aop->aopu.aop_str[i] = fReturn[i];
993           return;
994         }
995
996       if (sym->usl.spillLoc)
997         {
998           asmop *oldAsmOp = NULL;
999
1000           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1001             {
1002               /* force a new aop if sizes differ */
1003               oldAsmOp = sym->usl.spillLoc->aop;
1004               sym->usl.spillLoc->aop = NULL;
1005             }
1006           sym->aop = op->aop = aop =
1007                      aopForSym (ic, sym->usl.spillLoc, result);
1008           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1009             {
1010               /* Don't reuse the new aop, go with the last one */
1011               sym->usl.spillLoc->aop = oldAsmOp;
1012             }
1013           aop->size = getSize (sym->type);
1014           return;
1015         }
1016
1017       /* else must be a dummy iTemp */
1018       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1019       aop->size = getSize (sym->type);
1020       return;
1021     }
1022
1023   /* if the type is a bit register */
1024   if (sym->regType == REG_BIT)
1025     {
1026       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1027       aop->size = sym->nRegs;//1???
1028       aop->aopu.aop_reg[0] = sym->regs[0];
1029       aop->aopu.aop_dir = sym->regs[0]->name;
1030       return;
1031     }
1032
1033   /* must be in a register */
1034   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1035   aop->size = sym->nRegs;
1036   for (i = 0; i < sym->nRegs; i++)
1037     aop->aopu.aop_reg[i] = sym->regs[i];
1038 }
1039
1040 /*-----------------------------------------------------------------*/
1041 /* freeAsmop - free up the asmop given to an operand               */
1042 /*----------------------------------------------------------------*/
1043 static void
1044 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1045 {
1046   asmop *aop;
1047
1048   if (!op)
1049     aop = aaop;
1050   else
1051     aop = op->aop;
1052
1053   if (!aop)
1054     return;
1055
1056   aop->allocated--;
1057
1058   if (aop->allocated)
1059     goto dealloc;
1060
1061   /* depending on the asmop type only three cases need work
1062      AOP_R0, AOP_R1 & AOP_STK */
1063   switch (aop->type)
1064     {
1065     case AOP_R0:
1066       if (R0INB)
1067         {
1068           emitcode ("mov", "r0,b");
1069           R0INB--;
1070         }
1071       else if (_G.r0Pushed)
1072         {
1073           if (pop)
1074             {
1075               emitcode ("pop", "ar0");
1076               _G.r0Pushed--;
1077             }
1078         }
1079       bitVectUnSetBit (ic->rUsed, R0_IDX);
1080       break;
1081
1082     case AOP_R1:
1083       if (R1INB)
1084         {
1085           emitcode ("mov", "r1,b");
1086           R1INB--;
1087         }
1088       else if (_G.r1Pushed)
1089         {
1090           if (pop)
1091             {
1092               emitcode ("pop", "ar1");
1093               _G.r1Pushed--;
1094             }
1095         }
1096       bitVectUnSetBit (ic->rUsed, R1_IDX);
1097       break;
1098
1099     case AOP_STK:
1100       {
1101         int sz = aop->size;
1102         int stk = aop->aopu.aop_stk + aop->size - 1;
1103         bitVectUnSetBit (ic->rUsed, R0_IDX);
1104         bitVectUnSetBit (ic->rUsed, R1_IDX);
1105
1106         getFreePtr (ic, &aop, FALSE);
1107
1108         if (stk)
1109           {
1110             emitcode ("mov", "a,_bp");
1111             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1112             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1113           }
1114         else
1115           {
1116             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1117           }
1118
1119         while (sz--)
1120           {
1121             emitcode ("pop", "acc");
1122             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1123             if (!sz)
1124               break;
1125             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1126           }
1127         op->aop = aop;
1128         freeAsmop (op, NULL, ic, TRUE);
1129         if (_G.r1Pushed)
1130           {
1131             emitcode ("pop", "ar1");
1132             _G.r1Pushed--;
1133           }
1134         if (_G.r0Pushed)
1135           {
1136             emitcode ("pop", "ar0");
1137             _G.r0Pushed--;
1138           }
1139       }
1140       break;
1141     }
1142
1143 dealloc:
1144   /* all other cases just dealloc */
1145   if (op)
1146     {
1147       op->aop = NULL;
1148       if (IS_SYMOP (op))
1149         {
1150           OP_SYMBOL (op)->aop = NULL;
1151           /* if the symbol has a spill */
1152           if (SPIL_LOC (op))
1153             SPIL_LOC (op)->aop = NULL;
1154         }
1155     }
1156 }
1157
1158 /*------------------------------------------------------------------*/
1159 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1160 /*                      pop r0 or r1 off stack if pushed            */
1161 /*------------------------------------------------------------------*/
1162 static void
1163 freeForBranchAsmop (operand * op)
1164 {
1165   asmop *aop;
1166
1167   if (!op)
1168     return;
1169
1170   aop = op->aop;
1171
1172   if (!aop)
1173     return;
1174
1175   if (!aop->allocated)
1176     return;
1177
1178   switch (aop->type)
1179     {
1180     case AOP_R0:
1181       if (R0INB)
1182         {
1183           emitcode ("mov", "r0,b");
1184         }
1185       else if (_G.r0Pushed)
1186         {
1187           emitcode ("pop", "ar0");
1188         }
1189       break;
1190
1191     case AOP_R1:
1192       if (R1INB)
1193         {
1194           emitcode ("mov", "r1,b");
1195         }
1196       else if (_G.r1Pushed)
1197         {
1198           emitcode ("pop", "ar1");
1199         }
1200       break;
1201
1202     case AOP_STK:
1203       {
1204         int sz = aop->size;
1205         int stk = aop->aopu.aop_stk + aop->size - 1;
1206
1207         emitcode ("mov", "b,r0");
1208         if (stk)
1209           {
1210             emitcode ("mov", "a,_bp");
1211             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1212             emitcode ("mov", "r0,a");
1213           }
1214         else
1215           {
1216             emitcode ("mov", "r0,_bp");
1217           }
1218
1219         while (sz--)
1220           {
1221             emitcode ("pop", "acc");
1222             emitcode ("mov", "@r0,a");
1223             if (!sz)
1224               break;
1225             emitcode ("dec", "r0");
1226           }
1227         emitcode ("mov", "r0,b");
1228       }
1229     }
1230
1231 }
1232
1233 /*-----------------------------------------------------------------*/
1234 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1235 /*                 clobber the accumulator                         */
1236 /*-----------------------------------------------------------------*/
1237 static bool
1238 aopGetUsesAcc (operand * oper, int offset)
1239 {
1240   asmop * aop = AOP (oper);
1241
1242   if (offset > (aop->size - 1))
1243     return FALSE;
1244
1245   switch (aop->type)
1246     {
1247
1248     case AOP_R0:
1249     case AOP_R1:
1250       if (aop->paged)
1251         return TRUE;
1252       return FALSE;
1253     case AOP_DPTR:
1254       return TRUE;
1255     case AOP_IMMD:
1256       return FALSE;
1257     case AOP_DIR:
1258       return FALSE;
1259     case AOP_REG:
1260       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1261       return FALSE;
1262     case AOP_CRY:
1263       return TRUE;
1264     case AOP_ACC:
1265       if (offset)
1266         return FALSE;
1267       return TRUE;
1268     case AOP_LIT:
1269       return FALSE;
1270     case AOP_STR:
1271       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1272         return TRUE;
1273       return FALSE;
1274     case AOP_DUMMY:
1275       return FALSE;
1276     default:
1277       /* Error case --- will have been caught already */
1278       wassert(0);
1279       return FALSE;
1280     }
1281 }
1282
1283 /*-------------------------------------------------------------------*/
1284 /* aopGet - for fetching value of the aop                            */
1285 /*-------------------------------------------------------------------*/
1286 static char *
1287 aopGet (operand * oper, int offset, bool bit16, bool dname)
1288 {
1289   asmop * aop = AOP (oper);
1290
1291   /* offset is greater than
1292      size then zero */
1293   if (offset > (aop->size - 1) &&
1294       aop->type != AOP_LIT)
1295     return zero;
1296
1297   /* depending on type */
1298   switch (aop->type)
1299     {
1300     case AOP_DUMMY:
1301       return zero;
1302
1303     case AOP_R0:
1304     case AOP_R1:
1305       /* if we need to increment it */
1306       while (offset > aop->coff)
1307         {
1308           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1309           aop->coff++;
1310         }
1311
1312       while (offset < aop->coff)
1313         {
1314           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1315           aop->coff--;
1316         }
1317
1318       aop->coff = offset;
1319       if (aop->paged)
1320         {
1321           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1322           return (dname ? "acc" : "a");
1323         }
1324       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1325       return Safe_strdup(buffer);
1326
1327     case AOP_DPTR:
1328       if (aop->code && aop->coff==0 && offset>=1) {
1329         emitcode ("mov", "a,#0x%02x", offset);
1330         emitcode ("movc", "a,@a+dptr");
1331         return (dname ? "acc" : "a");
1332       }
1333
1334       while (offset > aop->coff)
1335         {
1336           emitcode ("inc", "dptr");
1337           aop->coff++;
1338         }
1339
1340       while (offset < aop->coff)
1341         {
1342           emitcode ("lcall", "__decdptr");
1343           aop->coff--;
1344         }
1345
1346       aop->coff = offset;
1347       if (aop->code)
1348         {
1349           emitcode ("clr", "a");
1350           emitcode ("movc", "a,@a+dptr");
1351         }
1352       else
1353         {
1354           emitcode ("movx", "a,@dptr");
1355         }
1356       return (dname ? "acc" : "a");
1357
1358     case AOP_IMMD:
1359       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1360         {
1361           SNPRINTF(buffer, sizeof(buffer),
1362                    "%s",aop->aopu.aop_immd.aop_immd2);
1363         }
1364       else if (bit16)
1365         {
1366           SNPRINTF(buffer, sizeof(buffer),
1367                    "#%s", aop->aopu.aop_immd.aop_immd1);
1368         }
1369       else if (offset)
1370         {
1371           SNPRINTF (buffer, sizeof(buffer),
1372                     "#(%s >> %d)",
1373                     aop->aopu.aop_immd.aop_immd1,
1374                     offset * 8);
1375         }
1376       else
1377         {
1378           SNPRINTF (buffer, sizeof(buffer),
1379                     "#%s",
1380                     aop->aopu.aop_immd.aop_immd1);
1381         }
1382       return Safe_strdup(buffer);
1383
1384     case AOP_DIR:
1385       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1386         {
1387           SNPRINTF (buffer, sizeof(buffer),
1388                     "(%s >> %d)",
1389                     aop->aopu.aop_dir, offset * 8);
1390         }
1391       else if (offset)
1392         {
1393           SNPRINTF (buffer, sizeof(buffer),
1394                     "(%s + %d)",
1395                     aop->aopu.aop_dir,
1396                     offset);
1397         }
1398       else
1399         {
1400           SNPRINTF (buffer, sizeof(buffer),
1401                     "%s",
1402                     aop->aopu.aop_dir);
1403         }
1404
1405       return Safe_strdup(buffer);
1406
1407     case AOP_REG:
1408       if (dname)
1409         return aop->aopu.aop_reg[offset]->dname;
1410       else
1411         return aop->aopu.aop_reg[offset]->name;
1412
1413     case AOP_CRY:
1414       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1415       emitcode ("clr", "a");
1416       emitcode ("rlc", "a");
1417       return (dname ? "acc" : "a");
1418
1419     case AOP_ACC:
1420       if (!offset && dname)
1421         return "acc";
1422       return aop->aopu.aop_str[offset];
1423
1424     case AOP_LIT:
1425       return aopLiteral (aop->aopu.aop_lit, offset);
1426
1427     case AOP_STR:
1428       aop->coff = offset;
1429       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1430           dname)
1431         return "acc";
1432
1433       return aop->aopu.aop_str[offset];
1434
1435     }
1436
1437   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1438           "aopget got unsupported aop->type");
1439   exit (1);
1440 }
1441
1442 /*-----------------------------------------------------------------*/
1443 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1444 /*                 clobber the accumulator                         */
1445 /*-----------------------------------------------------------------*/
1446 static bool
1447 aopPutUsesAcc (operand * oper, const char *s, int offset)
1448 {
1449   asmop * aop = AOP (oper);
1450
1451   if (offset > (aop->size - 1))
1452     return FALSE;
1453
1454   switch (aop->type)
1455     {
1456     case AOP_DUMMY:
1457       return TRUE;
1458     case AOP_DIR:
1459       return FALSE;
1460     case AOP_REG:
1461       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1462       return FALSE;
1463     case AOP_DPTR:
1464       return TRUE;
1465     case AOP_R0:
1466     case AOP_R1:
1467       return ((aop->paged) || (*s == '@'));
1468     case AOP_STK:
1469       return (*s == '@');
1470     case AOP_CRY:
1471       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1472     case AOP_STR:
1473       return FALSE;
1474     case AOP_IMMD:
1475       return FALSE;
1476     case AOP_ACC:
1477       return FALSE;
1478     default:
1479       /* Error case --- will have been caught already */
1480       wassert(0);
1481       return FALSE;
1482     }
1483 }
1484
1485 /*-----------------------------------------------------------------*/
1486 /* aopPut - puts a string for a aop and indicates if acc is in use */
1487 /*-----------------------------------------------------------------*/
1488 static bool
1489 aopPut (operand * result, const char *s, int offset)
1490 {
1491   bool bvolatile = isOperandVolatile (result, FALSE);
1492   bool accuse = FALSE;
1493   asmop * aop = AOP (result);
1494
1495   if (aop->size && offset > (aop->size - 1))
1496     {
1497       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1498               "aopPut got offset > aop->size");
1499       exit (1);
1500     }
1501
1502   /* will assign value to value */
1503   /* depending on where it is ofcourse */
1504   switch (aop->type)
1505     {
1506     case AOP_DUMMY:
1507       MOVA (s);         /* read s in case it was volatile */
1508       accuse = TRUE;
1509       break;
1510
1511     case AOP_DIR:
1512       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1513         {
1514           SNPRINTF (buffer, sizeof(buffer),
1515                     "(%s >> %d)",
1516                     aop->aopu.aop_dir, offset * 8);
1517         }
1518       else if (offset)
1519         {
1520           SNPRINTF (buffer, sizeof(buffer),
1521                     "(%s + %d)",
1522                     aop->aopu.aop_dir, offset);
1523         }
1524       else
1525         {
1526           SNPRINTF (buffer, sizeof(buffer),
1527                     "%s",
1528                     aop->aopu.aop_dir);
1529         }
1530
1531       if (strcmp (buffer, s) || bvolatile)
1532         {
1533           emitcode ("mov", "%s,%s", buffer, s);
1534         }
1535       if (!strcmp (buffer, "acc"))
1536         {
1537           accuse = TRUE;
1538         }
1539       break;
1540
1541     case AOP_REG:
1542       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1543           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1544         {
1545           if (*s == '@' ||
1546               strcmp (s, "r0") == 0 ||
1547               strcmp (s, "r1") == 0 ||
1548               strcmp (s, "r2") == 0 ||
1549               strcmp (s, "r3") == 0 ||
1550               strcmp (s, "r4") == 0 ||
1551               strcmp (s, "r5") == 0 ||
1552               strcmp (s, "r6") == 0 ||
1553               strcmp (s, "r7") == 0)
1554             {
1555               emitcode ("mov", "%s,%s",
1556                         aop->aopu.aop_reg[offset]->dname, s);
1557             }
1558           else
1559             {
1560               emitcode ("mov", "%s,%s",
1561                         aop->aopu.aop_reg[offset]->name, s);
1562             }
1563         }
1564       break;
1565
1566     case AOP_DPTR:
1567       if (aop->code)
1568         {
1569           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1570                   "aopPut writing to code space");
1571           exit (1);
1572         }
1573
1574       while (offset > aop->coff)
1575         {
1576           aop->coff++;
1577           emitcode ("inc", "dptr");
1578         }
1579
1580       while (offset < aop->coff)
1581         {
1582           aop->coff--;
1583           emitcode ("lcall", "__decdptr");
1584         }
1585
1586       aop->coff = offset;
1587
1588       /* if not in accumulator */
1589       MOVA (s);
1590
1591       emitcode ("movx", "@dptr,a");
1592       break;
1593
1594     case AOP_R0:
1595     case AOP_R1:
1596       while (offset > aop->coff)
1597         {
1598           aop->coff++;
1599           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1600         }
1601       while (offset < aop->coff)
1602         {
1603           aop->coff--;
1604           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1605         }
1606       aop->coff = offset;
1607
1608       if (aop->paged)
1609         {
1610           MOVA (s);
1611           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1612         }
1613       else if (*s == '@')
1614         {
1615           MOVA (s);
1616           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1617         }
1618       else if (strcmp (s, "r0") == 0 ||
1619                strcmp (s, "r1") == 0 ||
1620                strcmp (s, "r2") == 0 ||
1621                strcmp (s, "r3") == 0 ||
1622                strcmp (s, "r4") == 0 ||
1623                strcmp (s, "r5") == 0 ||
1624                strcmp (s, "r6") == 0 ||
1625                strcmp (s, "r7") == 0)
1626         {
1627           char buffer[10];
1628           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1629           emitcode ("mov", "@%s,%s",
1630                     aop->aopu.aop_ptr->name, buffer);
1631         }
1632       else
1633         {
1634           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1635         }
1636       break;
1637
1638     case AOP_STK:
1639       if (strcmp (s, "a") == 0)
1640         {
1641           emitcode ("push", "acc");
1642         }
1643       else if (*s=='@')
1644         {
1645           MOVA(s);
1646           emitcode ("push", "acc");
1647         }
1648       else if (strcmp (s, "r0") == 0 ||
1649                strcmp (s, "r1") == 0 ||
1650                strcmp (s, "r2") == 0 ||
1651                strcmp (s, "r3") == 0 ||
1652                strcmp (s, "r4") == 0 ||
1653                strcmp (s, "r5") == 0 ||
1654                strcmp (s, "r6") == 0 ||
1655                strcmp (s, "r7") == 0)
1656         {
1657           char buffer[10];
1658           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1659           emitcode ("push", buffer);
1660         }
1661       else
1662         {
1663           emitcode ("push", s);
1664         }
1665
1666       break;
1667
1668     case AOP_CRY:
1669       /* if result no bit variable */
1670       if (!aop->aopu.aop_dir)
1671         {
1672           assert (!strcmp (s, "c"));
1673           /* inefficient: move carry into A and use jz/jnz */
1674           emitcode ("clr", "a");
1675           emitcode ("rlc", "a");
1676           accuse = TRUE;
1677         }
1678       else if (s == zero)
1679           emitcode ("clr", "%s", aop->aopu.aop_dir);
1680       else if (s == one)
1681           emitcode ("setb", "%s", aop->aopu.aop_dir);
1682       else if (!strcmp (s, "c"))
1683           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1684       else if (strcmp (s, aop->aopu.aop_dir))
1685         {
1686           MOVA (s);
1687           /* set C, if a >= 1 */
1688           emitcode ("add", "a,#0xff");
1689           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1690         }
1691       break;
1692
1693     case AOP_STR:
1694       aop->coff = offset;
1695       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1696         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1697       break;
1698
1699     case AOP_ACC:
1700       accuse = TRUE;
1701       aop->coff = offset;
1702       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1703         break;
1704
1705       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1706         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1707       break;
1708
1709     default:
1710       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1711               "aopPut got unsupported aop->type");
1712       exit (1);
1713     }
1714
1715     return accuse;
1716 }
1717
1718
1719 #if 0
1720 /*-----------------------------------------------------------------*/
1721 /* pointToEnd :- points to the last byte of the operand            */
1722 /*-----------------------------------------------------------------*/
1723 static void
1724 pointToEnd (asmop * aop)
1725 {
1726   int count;
1727   if (!aop)
1728     return;
1729
1730   aop->coff = count = (aop->size - 1);
1731   switch (aop->type)
1732     {
1733     case AOP_R0:
1734     case AOP_R1:
1735       while (count--)
1736         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1737       break;
1738     case AOP_DPTR:
1739       while (count--)
1740         emitcode ("inc", "dptr");
1741       break;
1742     }
1743
1744 }
1745 #endif
1746
1747 /*-----------------------------------------------------------------*/
1748 /* reAdjustPreg - points a register back to where it should        */
1749 /*-----------------------------------------------------------------*/
1750 static void
1751 reAdjustPreg (asmop * aop)
1752 {
1753   if ((aop->coff==0) || (aop->size <= 1))
1754     return;
1755
1756   switch (aop->type)
1757     {
1758     case AOP_R0:
1759     case AOP_R1:
1760       while (aop->coff--)
1761         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1762       break;
1763     case AOP_DPTR:
1764       while (aop->coff--)
1765         {
1766           emitcode ("lcall", "__decdptr");
1767         }
1768       break;
1769     }
1770   aop->coff = 0;
1771 }
1772
1773 /*-----------------------------------------------------------------*/
1774 /* opIsGptr: returns non-zero if the passed operand is       */
1775 /* a generic pointer type.             */
1776 /*-----------------------------------------------------------------*/
1777 static int
1778 opIsGptr (operand * op)
1779 {
1780   sym_link *type = operandType (op);
1781
1782   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1783     {
1784       return 1;
1785     }
1786   return 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* getDataSize - get the operand data size                         */
1791 /*-----------------------------------------------------------------*/
1792 static int
1793 getDataSize (operand * op)
1794 {
1795   int size;
1796   size = AOP_SIZE (op);
1797   if (size == GPTRSIZE)
1798     {
1799       sym_link *type = operandType (op);
1800       if (IS_GENPTR (type))
1801         {
1802           /* generic pointer; arithmetic operations
1803            * should ignore the high byte (pointer type).
1804            */
1805           size--;
1806         }
1807     }
1808   return size;
1809 }
1810
1811 /*-----------------------------------------------------------------*/
1812 /* outAcc - output Acc                                             */
1813 /*-----------------------------------------------------------------*/
1814 static void
1815 outAcc (operand * result)
1816 {
1817   int size, offset;
1818   size = getDataSize (result);
1819   if (size)
1820     {
1821       aopPut (result, "a", 0);
1822       size--;
1823       offset = 1;
1824       /* unsigned or positive */
1825       while (size--)
1826         {
1827           aopPut (result, zero, offset++);
1828         }
1829     }
1830 }
1831
1832 /*-----------------------------------------------------------------*/
1833 /* outBitC - output a bit C                                        */
1834 /*-----------------------------------------------------------------*/
1835 static void
1836 outBitC (operand * result)
1837 {
1838   /* if the result is bit */
1839   if (AOP_TYPE (result) == AOP_CRY)
1840     {
1841       aopPut (result, "c", 0);
1842     }
1843   else
1844     {
1845       emitcode ("clr", "a");
1846       emitcode ("rlc", "a");
1847       outAcc (result);
1848     }
1849 }
1850
1851 /*-----------------------------------------------------------------*/
1852 /* toBoolean - emit code for orl a,operator(sizeop)                */
1853 /*-----------------------------------------------------------------*/
1854 static void
1855 toBoolean (operand * oper)
1856 {
1857   int size = AOP_SIZE (oper) - 1;
1858   int offset = 1;
1859   bool AccUsed = FALSE;
1860   bool pushedB;
1861
1862   while (!AccUsed && size--)
1863     {
1864       AccUsed |= aopGetUsesAcc(oper, offset++);
1865     }
1866
1867   size = AOP_SIZE (oper) - 1;
1868   offset = 1;
1869   MOVA (aopGet (oper, 0, FALSE, FALSE));
1870   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1871     {
1872       pushedB = pushB ();
1873       emitcode("mov", "b,a");
1874       while (--size)
1875         {
1876           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1877           emitcode ("orl", "b,a");
1878         }
1879       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1880       emitcode ("orl", "a,b");
1881       popB (pushedB);
1882     }
1883   else
1884     {
1885       while (size--)
1886         {
1887           emitcode ("orl", "a,%s",
1888                     aopGet (oper, offset++, FALSE, FALSE));
1889         }
1890     }
1891 }
1892
1893 /*-----------------------------------------------------------------*/
1894 /* toCarry - make boolean and move into carry                      */
1895 /*-----------------------------------------------------------------*/
1896 static void
1897 toCarry (operand * oper)
1898 {
1899   /* if the operand is a literal then
1900      we know what the value is */
1901   if (AOP_TYPE (oper) == AOP_LIT)
1902     {
1903       if ((int) operandLitValue (oper))
1904         SETC;
1905       else
1906         CLRC;
1907     }
1908   else if (AOP_TYPE (oper) == AOP_CRY)
1909     {
1910       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1911     }
1912   else
1913     {
1914       /* or the operand into a */
1915       toBoolean (oper);
1916       /* set C, if a >= 1 */
1917       emitcode ("add", "a,#0xff");
1918     }
1919 }
1920
1921 /*-----------------------------------------------------------------*/
1922 /* assignBit - assign operand to bit operand                       */
1923 /*-----------------------------------------------------------------*/
1924 static void
1925 assignBit (operand * result, operand * right)
1926 {
1927   /* if the right side is a literal then
1928      we know what the value is */
1929   if (AOP_TYPE (right) == AOP_LIT)
1930     {
1931       if ((int) operandLitValue (right))
1932         aopPut (result, one, 0);
1933       else
1934         aopPut (result, zero, 0);
1935     }
1936   else
1937     {
1938       toCarry (right);
1939       aopPut (result, "c", 0);
1940     }
1941 }
1942
1943
1944 /*-------------------------------------------------------------------*/
1945 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1946 /*-------------------------------------------------------------------*/
1947 static char *
1948 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1949 {
1950   char * l;
1951
1952   if (aopGetUsesAcc (oper, offset))
1953     {
1954       emitcode("mov", "b,a");
1955       MOVA (aopGet (oper, offset, bit16, dname));
1956       emitcode("xch", "a,b");
1957       aopPut (oper, "a", offset);
1958       emitcode("xch", "a,b");
1959       l = "b";
1960     }
1961   else
1962     {
1963       l = aopGet (oper, offset, bit16, dname);
1964       emitcode("xch", "a,%s", l);
1965     }
1966   return l;
1967 }
1968
1969
1970 /*-----------------------------------------------------------------*/
1971 /* genNot - generate code for ! operation                          */
1972 /*-----------------------------------------------------------------*/
1973 static void
1974 genNot (iCode * ic)
1975 {
1976   symbol *tlbl;
1977
1978   D (emitcode (";", "genNot"));
1979
1980   /* assign asmOps to operand & result */
1981   aopOp (IC_LEFT (ic), ic, FALSE);
1982   aopOp (IC_RESULT (ic), ic, TRUE);
1983
1984   /* if in bit space then a special case */
1985   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1986     {
1987       /* if left==result then cpl bit */
1988       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1989         {
1990           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1991         }
1992       else
1993         {
1994           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1995           emitcode ("cpl", "c");
1996           outBitC (IC_RESULT (ic));
1997         }
1998       goto release;
1999     }
2000
2001   toBoolean (IC_LEFT (ic));
2002
2003   /* set C, if a == 0 */
2004   tlbl = newiTempLabel (NULL);
2005   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2006   emitLabel (tlbl);
2007   outBitC (IC_RESULT (ic));
2008
2009 release:
2010   /* release the aops */
2011   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2012   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2013 }
2014
2015
2016 /*-----------------------------------------------------------------*/
2017 /* genCpl - generate code for complement                           */
2018 /*-----------------------------------------------------------------*/
2019 static void
2020 genCpl (iCode * ic)
2021 {
2022   int offset = 0;
2023   int size;
2024   symbol *tlbl;
2025   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2026
2027   D(emitcode (";", "genCpl"));
2028
2029   /* assign asmOps to operand & result */
2030   aopOp (IC_LEFT (ic), ic, FALSE);
2031   aopOp (IC_RESULT (ic), ic, TRUE);
2032
2033   /* special case if in bit space */
2034   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2035     {
2036       char *l;
2037
2038       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2039           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2040         {
2041           /* promotion rules are responsible for this strange result:
2042              bit -> int -> ~int -> bit
2043              uchar -> int -> ~int -> bit
2044           */
2045           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2046           goto release;
2047         }
2048
2049       tlbl=newiTempLabel(NULL);
2050       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2051       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2052           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2053           IS_AOP_PREG (IC_LEFT (ic)))
2054         {
2055           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2056         }
2057       else
2058         {
2059           MOVA (l);
2060           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2061         }
2062       emitLabel (tlbl);
2063       outBitC (IC_RESULT(ic));
2064       goto release;
2065     }
2066
2067   size = AOP_SIZE (IC_RESULT (ic));
2068   while (size--)
2069     {
2070       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2071       MOVA (l);
2072       emitcode ("cpl", "a");
2073       aopPut (IC_RESULT (ic), "a", offset++);
2074     }
2075
2076
2077 release:
2078   /* release the aops */
2079   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2080   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2081 }
2082
2083 /*-----------------------------------------------------------------*/
2084 /* genUminusFloat - unary minus for floating points                */
2085 /*-----------------------------------------------------------------*/
2086 static void
2087 genUminusFloat (operand * op, operand * result)
2088 {
2089   int size, offset = 0;
2090   char *l;
2091
2092   D (emitcode (";", "genUminusFloat"));
2093
2094   /* for this we just copy and then flip the bit */
2095
2096   size = AOP_SIZE (op) - 1;
2097
2098   while (size--)
2099     {
2100       aopPut (result,
2101               aopGet (op, offset, FALSE, FALSE),
2102               offset);
2103       offset++;
2104     }
2105
2106   l = aopGet (op, offset, FALSE, FALSE);
2107   MOVA (l);
2108
2109   emitcode ("cpl", "acc.7");
2110   aopPut (result, "a", offset);
2111 }
2112
2113 /*-----------------------------------------------------------------*/
2114 /* genUminus - unary minus code generation                         */
2115 /*-----------------------------------------------------------------*/
2116 static void
2117 genUminus (iCode * ic)
2118 {
2119   int offset, size;
2120   sym_link *optype;
2121
2122   D (emitcode (";", "genUminus"));
2123
2124   /* assign asmops */
2125   aopOp (IC_LEFT (ic), ic, FALSE);
2126   aopOp (IC_RESULT (ic), ic, TRUE);
2127
2128   /* if both in bit space then special
2129      case */
2130   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2131       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2132     {
2133
2134       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2135       emitcode ("cpl", "c");
2136       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2137       goto release;
2138     }
2139
2140   optype = operandType (IC_LEFT (ic));
2141
2142   /* if float then do float stuff */
2143   if (IS_FLOAT (optype))
2144     {
2145       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2146       goto release;
2147     }
2148
2149   /* otherwise subtract from zero */
2150   size = AOP_SIZE (IC_LEFT (ic));
2151   offset = 0;
2152   while (size--)
2153     {
2154       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2155       if (!strcmp (l, "a"))
2156         {
2157           if (offset == 0)
2158             SETC;
2159           emitcode ("cpl", "a");
2160           emitcode ("addc", "a,#0");
2161         }
2162       else
2163         {
2164           if (offset == 0)
2165             CLRC;
2166           emitcode ("clr", "a");
2167           emitcode ("subb", "a,%s", l);
2168         }
2169       aopPut (IC_RESULT (ic), "a", offset++);
2170     }
2171
2172   /* if any remaining bytes in the result */
2173   /* we just need to propagate the sign   */
2174   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2175     {
2176       emitcode ("rlc", "a");
2177       emitcode ("subb", "a,acc");
2178       while (size--)
2179         aopPut (IC_RESULT (ic), "a", offset++);
2180     }
2181
2182 release:
2183   /* release the aops */
2184   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2185   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2186 }
2187
2188 /*-----------------------------------------------------------------*/
2189 /* saveRegisters - will look for a call and save the registers     */
2190 /*-----------------------------------------------------------------*/
2191 static void
2192 saveRegisters (iCode * lic)
2193 {
2194   int i;
2195   iCode *ic;
2196   bitVect *rsave;
2197
2198   /* look for call */
2199   for (ic = lic; ic; ic = ic->next)
2200     if (ic->op == CALL || ic->op == PCALL)
2201       break;
2202
2203   if (!ic)
2204     {
2205       fprintf (stderr, "found parameter push with no function call\n");
2206       return;
2207     }
2208
2209   /* if the registers have been saved already or don't need to be then
2210      do nothing */
2211   if (ic->regsSaved)
2212     return;
2213   if (IS_SYMOP(IC_LEFT(ic)) &&
2214       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2215        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2216     return;
2217
2218   /* save the registers in use at this time but skip the
2219      ones for the result */
2220   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2221                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2222
2223   ic->regsSaved = 1;
2224   if (options.useXstack)
2225     {
2226       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2227       int nBits = bitVectnBitsOn (rsavebits);
2228       int count = bitVectnBitsOn (rsave);
2229
2230       if (nBits != 0)
2231         {
2232           count = count - nBits + 1;
2233           /* remove all but the first bits as they are pushed all at once */
2234           rsave = bitVectCplAnd (rsave, rsavebits);
2235           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2236         }
2237       freeBitVect (rsavebits);
2238
2239       if (count == 1)
2240         {
2241           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2242           if (reg->type == REG_BIT)
2243             {
2244               emitcode ("mov", "a,%s", reg->base);
2245             }
2246           else
2247             {
2248               emitcode ("mov", "a,%s", reg->name);
2249             }
2250           emitcode ("mov", "r0,%s", spname);
2251           emitcode ("inc", "%s", spname);// allocate before use
2252           emitcode ("movx", "@r0,a");
2253           if (bitVectBitValue (rsave, R0_IDX))
2254             emitcode ("mov", "r0,a");
2255         }
2256       else if (count != 0)
2257         {
2258           if (bitVectBitValue (rsave, R0_IDX))
2259             {
2260               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2261             }
2262           emitcode ("mov", "r0,%s", spname);
2263           MOVA ("r0");
2264           emitcode ("add", "a,#%d", count);
2265           emitcode ("mov", "%s,a", spname);
2266           for (i = 0; i < mcs51_nRegs; i++)
2267             {
2268               if (bitVectBitValue (rsave, i))
2269                 {
2270                   regs * reg = REG_WITH_INDEX (i);
2271                   if (i == R0_IDX)
2272                     {
2273                       emitcode ("pop", "acc");
2274                       emitcode ("push", "acc");
2275                     }
2276                   else if (reg->type == REG_BIT)
2277                     {
2278                       emitcode ("mov", "a,%s", reg->base);
2279                     }
2280                   else
2281                     {
2282                       emitcode ("mov", "a,%s", reg->name);
2283                     }
2284                   emitcode ("movx", "@r0,a");
2285                   if (--count)
2286                     {
2287                       emitcode ("inc", "r0");
2288                     }
2289                 }
2290             }
2291           if (bitVectBitValue (rsave, R0_IDX))
2292             {
2293               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2294             }
2295         }
2296     }
2297   else
2298     {
2299       bool bits_pushed = FALSE;
2300       for (i = 0; i < mcs51_nRegs; i++)
2301         {
2302           if (bitVectBitValue (rsave, i))
2303             {
2304               bits_pushed = pushReg (i, bits_pushed);
2305             }
2306         }
2307     }
2308   freeBitVect (rsave);
2309 }
2310
2311 /*-----------------------------------------------------------------*/
2312 /* unsaveRegisters - pop the pushed registers                      */
2313 /*-----------------------------------------------------------------*/
2314 static void
2315 unsaveRegisters (iCode * ic)
2316 {
2317   int i;
2318   bitVect *rsave;
2319
2320   /* restore the registers in use at this time but skip the
2321      ones for the result */
2322   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2323                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2324
2325   if (options.useXstack)
2326     {
2327       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2328       int nBits = bitVectnBitsOn (rsavebits);
2329       int count = bitVectnBitsOn (rsave);
2330
2331       if (nBits != 0)
2332         {
2333           count = count - nBits + 1;
2334           /* remove all but the first bits as they are popped all at once */
2335           rsave = bitVectCplAnd (rsave, rsavebits);
2336           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2337         }
2338       freeBitVect (rsavebits);
2339
2340       if (count == 1)
2341         {
2342           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2343           emitcode ("mov", "r0,%s", spname);
2344           emitcode ("dec", "r0");
2345           emitcode ("movx", "a,@r0");
2346           if (reg->type == REG_BIT)
2347             {
2348               emitcode ("mov", "%s,a", reg->base);
2349             }
2350           else
2351             {
2352               emitcode ("mov", "%s,a", reg->name);
2353             }
2354           emitcode ("dec", "%s", spname);
2355         }
2356       else if (count != 0)
2357         {
2358           emitcode ("mov", "r0,%s", spname);
2359           for (i = mcs51_nRegs; i >= 0; i--)
2360             {
2361               if (bitVectBitValue (rsave, i))
2362                 {
2363                   regs * reg = REG_WITH_INDEX (i);
2364                   emitcode ("dec", "r0");
2365                   emitcode ("movx", "a,@r0");
2366                   if (i == R0_IDX)
2367                     {
2368                       emitcode ("push", "acc");
2369                     }
2370                   else if (reg->type == REG_BIT)
2371                     {
2372                       emitcode ("mov", "%s,a", reg->base);
2373                     }
2374                   else
2375                     {
2376                       emitcode ("mov", "%s,a", reg->name);
2377                     }
2378                 }
2379             }
2380           emitcode ("mov", "%s,r0", spname);
2381           if (bitVectBitValue (rsave, R0_IDX))
2382             {
2383               emitcode ("pop", "ar0");
2384             }
2385         }
2386     }
2387   else
2388     {
2389       bool bits_popped = FALSE;
2390       for (i = mcs51_nRegs; i >= 0; i--)
2391         {
2392           if (bitVectBitValue (rsave, i))
2393             {
2394               bits_popped = popReg (i, bits_popped);
2395             }
2396         }
2397     }
2398   freeBitVect (rsave);
2399 }
2400
2401
2402 /*-----------------------------------------------------------------*/
2403 /* pushSide -                                                      */
2404 /*-----------------------------------------------------------------*/
2405 static void
2406 pushSide (operand * oper, int size)
2407 {
2408   int offset = 0;
2409   while (size--)
2410     {
2411       char *l = aopGet (oper, offset++, FALSE, TRUE);
2412       if (AOP_TYPE (oper) != AOP_REG &&
2413           AOP_TYPE (oper) != AOP_DIR &&
2414           strcmp (l, "a"))
2415         {
2416           MOVA (l);
2417           emitcode ("push", "acc");
2418         }
2419       else
2420         {
2421           emitcode ("push", "%s", l);
2422         }
2423     }
2424 }
2425
2426 /*-----------------------------------------------------------------*/
2427 /* assignResultValue - also indicates if acc is in use afterwards  */
2428 /*-----------------------------------------------------------------*/
2429 static bool
2430 assignResultValue (operand * oper, operand * func)
2431 {
2432   int offset = 0;
2433   int size = AOP_SIZE (oper);
2434   bool accuse = FALSE;
2435   bool pushedA = FALSE;
2436
2437   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2438     {
2439       outBitC (oper);
2440       return FALSE;
2441     }
2442
2443   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2444     {
2445       emitcode ("push", "acc");
2446       pushedA = TRUE;
2447     }
2448   while (size--)
2449     {
2450       if ((offset == 3) && pushedA)
2451         emitcode ("pop", "acc");
2452       accuse |= aopPut (oper, fReturn[offset], offset);
2453       offset++;
2454     }
2455   return accuse;
2456 }
2457
2458
2459 /*-----------------------------------------------------------------*/
2460 /* genXpush - pushes onto the external stack                       */
2461 /*-----------------------------------------------------------------*/
2462 static void
2463 genXpush (iCode * ic)
2464 {
2465   asmop *aop = newAsmop (0);
2466   regs *r;
2467   int size, offset = 0;
2468
2469   D (emitcode (";", "genXpush"));
2470
2471   aopOp (IC_LEFT (ic), ic, FALSE);
2472   r = getFreePtr (ic, &aop, FALSE);
2473
2474   size = AOP_SIZE (IC_LEFT (ic));
2475
2476   if (size == 1)
2477     {
2478       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2479       emitcode ("mov", "%s,%s", r->name, spname);
2480       emitcode ("inc", "%s", spname); // allocate space first
2481       emitcode ("movx", "@%s,a", r->name);
2482     }
2483   else
2484     {
2485       // allocate space first
2486       emitcode ("mov", "%s,%s", r->name, spname);
2487       MOVA (r->name);
2488       emitcode ("add", "a,#%d", size);
2489       emitcode ("mov", "%s,a", spname);
2490
2491       while (size--)
2492         {
2493           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2494           emitcode ("movx", "@%s,a", r->name);
2495           emitcode ("inc", "%s", r->name);
2496         }
2497     }
2498
2499   freeAsmop (NULL, aop, ic, TRUE);
2500   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2501 }
2502
2503 /*-----------------------------------------------------------------*/
2504 /* genIpush - generate code for pushing this gets a little complex */
2505 /*-----------------------------------------------------------------*/
2506 static void
2507 genIpush (iCode * ic)
2508 {
2509   int size, offset = 0;
2510   char *l;
2511   char *prev = "";
2512
2513   D (emitcode (";", "genIpush"));
2514
2515   /* if this is not a parm push : ie. it is spill push
2516      and spill push is always done on the local stack */
2517   if (!ic->parmPush)
2518     {
2519
2520       /* and the item is spilt then do nothing */
2521       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2522         return;
2523
2524       aopOp (IC_LEFT (ic), ic, FALSE);
2525       size = AOP_SIZE (IC_LEFT (ic));
2526       /* push it on the stack */
2527       while (size--)
2528         {
2529           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2530           if (*l == '#')
2531             {
2532               MOVA (l);
2533               l = "acc";
2534             }
2535           emitcode ("push", "%s", l);
2536         }
2537       return;
2538     }
2539
2540   /* this is a parameter push: in this case we call
2541      the routine to find the call and save those
2542      registers that need to be saved */
2543   saveRegisters (ic);
2544
2545   /* if use external stack then call the external
2546      stack pushing routine */
2547   if (options.useXstack)
2548     {
2549       genXpush (ic);
2550       return;
2551     }
2552
2553   /* then do the push */
2554   aopOp (IC_LEFT (ic), ic, FALSE);
2555
2556   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2557   size = AOP_SIZE (IC_LEFT (ic));
2558
2559   while (size--)
2560     {
2561       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2562       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2563           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2564         {
2565           if (strcmp (l, prev) || *l == '@')
2566             MOVA (l);
2567           emitcode ("push", "acc");
2568         }
2569       else
2570         {
2571           emitcode ("push", "%s", l);
2572         }
2573       prev = l;
2574     }
2575
2576   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2577 }
2578
2579 /*-----------------------------------------------------------------*/
2580 /* genIpop - recover the registers: can happen only for spilling   */
2581 /*-----------------------------------------------------------------*/
2582 static void
2583 genIpop (iCode * ic)
2584 {
2585   int size, offset;
2586
2587   D (emitcode (";", "genIpop"));
2588
2589   /* if the temp was not pushed then */
2590   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2591     return;
2592
2593   aopOp (IC_LEFT (ic), ic, FALSE);
2594   size = AOP_SIZE (IC_LEFT (ic));
2595   offset = (size - 1);
2596   while (size--)
2597     {
2598       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2599                                      FALSE, TRUE));
2600     }
2601
2602   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2603 }
2604
2605 /*-----------------------------------------------------------------*/
2606 /* saveRBank - saves an entire register bank on the stack          */
2607 /*-----------------------------------------------------------------*/
2608 static void
2609 saveRBank (int bank, iCode * ic, bool pushPsw)
2610 {
2611   int i;
2612   int count = 8 + (pushPsw ? 1 : 0);
2613   asmop *aop = NULL;
2614   regs *r = NULL;
2615
2616   if (options.useXstack)
2617     {
2618       if (!ic)
2619         {
2620           /* Assume r0 is available for use. */
2621           r = REG_WITH_INDEX (R0_IDX);
2622         }
2623       else
2624         {
2625           aop = newAsmop (0);
2626           r = getFreePtr (ic, &aop, FALSE);
2627         }
2628       // allocate space first
2629       emitcode ("mov", "%s,%s", r->name, spname);
2630       MOVA (r->name);
2631       emitcode ("add", "a,#%d", count);
2632       emitcode ("mov", "%s,a", spname);
2633     }
2634
2635   for (i = 0; i < 8; i++)
2636     {
2637       if (options.useXstack)
2638         {
2639           emitcode ("mov", "a,(%s+%d)",
2640                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2641           emitcode ("movx", "@%s,a", r->name);
2642           if (--count)
2643             emitcode ("inc", "%s", r->name);
2644         }
2645       else
2646         emitcode ("push", "(%s+%d)",
2647                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2648     }
2649
2650   if (pushPsw)
2651     {
2652       if (options.useXstack)
2653         {
2654           emitcode ("mov", "a,psw");
2655           emitcode ("movx", "@%s,a", r->name);
2656         }
2657       else
2658         {
2659           emitcode ("push", "psw");
2660         }
2661
2662       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2663     }
2664
2665   if (aop)
2666     {
2667       freeAsmop (NULL, aop, ic, TRUE);
2668     }
2669
2670   if (ic)
2671   {
2672     ic->bankSaved = 1;
2673   }
2674 }
2675
2676 /*-----------------------------------------------------------------*/
2677 /* unsaveRBank - restores the register bank from stack             */
2678 /*-----------------------------------------------------------------*/
2679 static void
2680 unsaveRBank (int bank, iCode * ic, bool popPsw)
2681 {
2682   int i;
2683   asmop *aop = NULL;
2684   regs *r = NULL;
2685
2686   if (options.useXstack)
2687     {
2688       if (!ic)
2689         {
2690           /* Assume r0 is available for use. */
2691           r = REG_WITH_INDEX (R0_IDX);;
2692         }
2693       else
2694         {
2695           aop = newAsmop (0);
2696           r = getFreePtr (ic, &aop, FALSE);
2697         }
2698       emitcode ("mov", "%s,%s", r->name, spname);
2699     }
2700
2701   if (popPsw)
2702     {
2703       if (options.useXstack)
2704         {
2705           emitcode ("dec", "%s", r->name);
2706           emitcode ("movx", "a,@%s", r->name);
2707           emitcode ("mov", "psw,a");
2708         }
2709       else
2710         {
2711           emitcode ("pop", "psw");
2712         }
2713     }
2714
2715   for (i = 7; i >= 0; i--)
2716     {
2717       if (options.useXstack)
2718         {
2719           emitcode ("dec", "%s", r->name);
2720           emitcode ("movx", "a,@%s", r->name);
2721           emitcode ("mov", "(%s+%d),a",
2722                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2723         }
2724       else
2725         {
2726           emitcode ("pop", "(%s+%d)",
2727                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2728         }
2729     }
2730
2731   if (options.useXstack)
2732     {
2733       emitcode ("mov", "%s,%s", spname, r->name);
2734     }
2735
2736   if (aop)
2737     {
2738       freeAsmop (NULL, aop, ic, TRUE);
2739     }
2740 }
2741
2742 /*-----------------------------------------------------------------*/
2743 /* genSend - gen code for SEND                                     */
2744 /*-----------------------------------------------------------------*/
2745 static void genSend(set *sendSet)
2746 {
2747   iCode *sic;
2748   int bit_count = 0;
2749
2750   /* first we do all bit parameters */
2751   for (sic = setFirstItem (sendSet); sic;
2752        sic = setNextItem (sendSet))
2753     {
2754       if (sic->argreg > 12)
2755         {
2756           int bit = sic->argreg-13;
2757
2758           aopOp (IC_LEFT (sic), sic, FALSE);
2759
2760           /* if left is a literal then
2761              we know what the value is */
2762           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2763             {
2764               if (((int) operandLitValue (IC_LEFT (sic))))
2765                   emitcode ("setb", "b[%d]", bit);
2766               else
2767                   emitcode ("clr", "b[%d]", bit);
2768             }
2769           else
2770             {
2771               /* we need to or */
2772               toCarry (IC_LEFT (sic));
2773               emitcode ("mov", "b[%d],c", bit);
2774             }
2775           bit_count++;
2776           BitBankUsed = 1;
2777
2778           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2779         }
2780     }
2781
2782   if (bit_count)
2783     {
2784       saveRegisters (setFirstItem (sendSet));
2785       emitcode ("mov", "bits,b");
2786     }
2787
2788   /* then we do all other parameters */
2789   for (sic = setFirstItem (sendSet); sic;
2790        sic = setNextItem (sendSet))
2791     {
2792       if (sic->argreg <= 12)
2793         {
2794           int size, offset = 0;
2795           aopOp (IC_LEFT (sic), sic, FALSE);
2796           size = AOP_SIZE (IC_LEFT (sic));
2797
2798           if (sic->argreg == 1)
2799             {
2800               while (size--)
2801                 {
2802                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2803                   if (strcmp (l, fReturn[offset]))
2804                     {
2805                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2806                     }
2807                   offset++;
2808                 }
2809             }
2810           else
2811             {
2812               while (size--)
2813                 {
2814                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2815                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2816                   offset++;
2817                 }
2818             }
2819           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2820         }
2821     }
2822 }
2823
2824 /*-----------------------------------------------------------------*/
2825 /* selectRegBank - emit code to select the register bank           */
2826 /*-----------------------------------------------------------------*/
2827 static void
2828 selectRegBank (short bank, bool keepFlags)
2829 {
2830   /* if f.e. result is in carry */
2831   if (keepFlags)
2832     {
2833       emitcode ("anl", "psw,#0xE7");
2834       if (bank)
2835         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2836     }
2837   else
2838     {
2839       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2840     }
2841 }
2842
2843 /*-----------------------------------------------------------------*/
2844 /* genCall - generates a call statement                            */
2845 /*-----------------------------------------------------------------*/
2846 static void
2847 genCall (iCode * ic)
2848 {
2849   sym_link *dtype;
2850   sym_link *etype;
2851 //  bool restoreBank = FALSE;
2852   bool swapBanks = FALSE;
2853   bool accuse = FALSE;
2854   bool accPushed = FALSE;
2855   bool resultInF0 = FALSE;
2856   bool assignResultGenerated = FALSE;
2857
2858   D (emitcode (";", "genCall"));
2859
2860   dtype = operandType (IC_LEFT (ic));
2861   etype = getSpec(dtype);
2862   /* if send set is not empty then assign */
2863   if (_G.sendSet)
2864     {
2865         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2866             genSend(reverseSet(_G.sendSet));
2867         } else {
2868             genSend(_G.sendSet);
2869         }
2870       _G.sendSet = NULL;
2871     }
2872
2873   /* if we are calling a not _naked function that is not using
2874      the same register bank then we need to save the
2875      destination registers on the stack */
2876   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2877       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2878        !IFFUNC_ISISR (dtype))
2879     {
2880       swapBanks = TRUE;
2881     }
2882
2883   /* if caller saves & we have not saved then */
2884   if (!ic->regsSaved)
2885       saveRegisters (ic);
2886
2887   if (swapBanks)
2888     {
2889         emitcode ("mov", "psw,#0x%02x",
2890            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2891     }
2892
2893   /* make the call */
2894   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2895     {
2896       if (IFFUNC_CALLEESAVES(dtype))
2897         {
2898           werror (E_BANKED_WITH_CALLEESAVES);
2899         }
2900       else
2901         {
2902           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2903                      OP_SYMBOL (IC_LEFT (ic))->rname :
2904                      OP_SYMBOL (IC_LEFT (ic))->name);
2905
2906           emitcode ("mov", "r0,#%s", l);
2907           emitcode ("mov", "r1,#(%s >> 8)", l);
2908           emitcode ("mov", "r2,#(%s >> 16)", l);
2909           emitcode ("lcall", "__sdcc_banked_call");
2910         }
2911     }
2912   else
2913     {
2914       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2915                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2916                                 OP_SYMBOL (IC_LEFT (ic))->name));
2917     }
2918
2919   if (swapBanks)
2920     {
2921       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2922     }
2923
2924   /* if we need assign a result value */
2925   if ((IS_ITEMP (IC_RESULT (ic)) &&
2926        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2927        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2928         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2929         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2930       IS_TRUE_SYMOP (IC_RESULT (ic)))
2931     {
2932
2933       _G.accInUse++;
2934       aopOp (IC_RESULT (ic), ic, FALSE);
2935       _G.accInUse--;
2936
2937       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2938       assignResultGenerated = TRUE;
2939
2940       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2941     }
2942
2943   /* adjust the stack for parameters if required */
2944   if (ic->parmBytes)
2945     {
2946       int i;
2947       if (ic->parmBytes > 3)
2948         {
2949           if (accuse)
2950             {
2951               emitcode ("push", "acc");
2952               accPushed = TRUE;
2953             }
2954           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2955               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2956               !assignResultGenerated)
2957             {
2958               emitcode ("mov", "F0,c");
2959               resultInF0 = TRUE;
2960             }
2961
2962           emitcode ("mov", "a,%s", spname);
2963           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2964           emitcode ("mov", "%s,a", spname);
2965
2966           /* unsaveRegisters from xstack needs acc, but */
2967           /* unsaveRegisters from stack needs this popped */
2968           if (accPushed && !options.useXstack)
2969             {
2970               emitcode ("pop", "acc");
2971               accPushed = FALSE;
2972             }
2973         }
2974       else
2975         for (i = 0; i < ic->parmBytes; i++)
2976           emitcode ("dec", "%s", spname);
2977     }
2978
2979   /* if we had saved some registers then unsave them */
2980   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2981     {
2982       if (accuse && !accPushed && options.useXstack)
2983         {
2984           /* xstack needs acc, but doesn't touch normal stack */
2985           emitcode ("push", "acc");
2986           accPushed = TRUE;
2987         }
2988       unsaveRegisters (ic);
2989     }
2990
2991 //  /* if register bank was saved then pop them */
2992 //  if (restoreBank)
2993 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2994
2995   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
2996     {
2997       if (resultInF0)
2998           emitcode ("mov", "c,F0");
2999
3000       aopOp (IC_RESULT (ic), ic, FALSE);
3001       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3002       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3003     }
3004
3005   if (accPushed)
3006     emitcode ("pop", "acc");
3007 }
3008
3009 /*-----------------------------------------------------------------*/
3010 /* genPcall - generates a call by pointer statement                */
3011 /*-----------------------------------------------------------------*/
3012 static void
3013 genPcall (iCode * ic)
3014 {
3015   sym_link *dtype;
3016   sym_link *etype;
3017   symbol *rlbl = newiTempLabel (NULL);
3018 //  bool restoreBank=FALSE;
3019   bool swapBanks = FALSE;
3020   bool resultInF0 = FALSE;
3021
3022   D (emitcode (";", "genPcall"));
3023
3024   dtype = operandType (IC_LEFT (ic))->next;
3025   etype = getSpec(dtype);
3026   /* if caller saves & we have not saved then */
3027   if (!ic->regsSaved)
3028     saveRegisters (ic);
3029
3030   /* if we are calling a not _naked function that is not using
3031      the same register bank then we need to save the
3032      destination registers on the stack */
3033   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3034       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3035       !IFFUNC_ISISR (dtype))
3036     {
3037 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3038 //    restoreBank=TRUE;
3039       swapBanks = TRUE;
3040       // need caution message to user here
3041     }
3042
3043   if (IS_LITERAL (etype))
3044     {
3045       /* if send set is not empty then assign */
3046       if (_G.sendSet)
3047         {
3048           genSend(reverseSet(_G.sendSet));
3049           _G.sendSet = NULL;
3050         }
3051
3052       if (swapBanks)
3053         {
3054           emitcode ("mov", "psw,#0x%02x",
3055            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3056         }
3057
3058       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3059         {
3060           if (IFFUNC_CALLEESAVES (dtype))
3061             {
3062               werror (E_BANKED_WITH_CALLEESAVES);
3063             }
3064           else
3065             {
3066               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3067
3068               emitcode ("mov", "r0,#%s", l);
3069               emitcode ("mov", "r1,#(%s >> 8)", l);
3070               emitcode ("mov", "r2,#(%s >> 16)", l);
3071               emitcode ("lcall", "__sdcc_banked_call");
3072             }
3073         }
3074       else
3075         {
3076           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3077         }
3078     }
3079   else
3080     {
3081       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3082         {
3083           if (IFFUNC_CALLEESAVES (dtype))
3084             {
3085               werror (E_BANKED_WITH_CALLEESAVES);
3086             }
3087           else
3088             {
3089               aopOp (IC_LEFT (ic), ic, FALSE);
3090
3091               if (!swapBanks)
3092                 {
3093                   /* what if aopGet needs r0 or r1 ??? */
3094                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3095                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3096                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3097                 }
3098               else
3099                 {
3100                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3101                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3102                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3103                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3104                 }
3105
3106               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3107
3108               /* if send set is not empty then assign */
3109               if (_G.sendSet)
3110                 {
3111                   genSend(reverseSet(_G.sendSet));
3112                   _G.sendSet = NULL;
3113                 }
3114
3115               if (swapBanks)
3116                 {
3117                   emitcode ("mov", "psw,#0x%02x",
3118                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3119                 }
3120
3121               /* make the call */
3122               emitcode ("lcall", "__sdcc_banked_call");
3123             }
3124         }
3125       else if (_G.sendSet)
3126         {
3127           /* push the return address on to the stack */
3128           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3129           emitcode ("push", "acc");
3130           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3131           emitcode ("push", "acc");
3132
3133           /* now push the calling address */
3134           aopOp (IC_LEFT (ic), ic, FALSE);
3135
3136           pushSide (IC_LEFT (ic), FPTRSIZE);
3137
3138           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3139
3140           /* if send set is not empty the assign */
3141           if (_G.sendSet)
3142             {
3143               genSend(reverseSet(_G.sendSet));
3144               _G.sendSet = NULL;
3145             }
3146
3147           if (swapBanks)
3148             {
3149               emitcode ("mov", "psw,#0x%02x",
3150                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3151             }
3152
3153           /* make the call */
3154           emitcode ("ret", "");
3155           emitLabel (rlbl);
3156         }
3157       else /* the send set is empty */
3158         {
3159           char *l;
3160           /* now get the calling address into dptr */
3161           aopOp (IC_LEFT (ic), ic, FALSE);
3162
3163           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3164           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3165             {
3166               emitcode ("mov", "r0,%s", l);
3167               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3168               emitcode ("mov", "dph,%s", l);
3169               emitcode ("mov", "dpl,r0");
3170             }
3171           else
3172             {
3173               emitcode ("mov", "dpl,%s", l);
3174               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3175               emitcode ("mov", "dph,%s", l);
3176             }
3177
3178           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3179
3180           if (swapBanks)
3181             {
3182               emitcode ("mov", "psw,#0x%02x",
3183                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3184             }
3185
3186           /* make the call */
3187           emitcode ("lcall", "__sdcc_call_dptr");
3188         }
3189     }
3190   if (swapBanks)
3191     {
3192       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3193     }
3194
3195   /* if we need assign a result value */
3196   if ((IS_ITEMP (IC_RESULT (ic)) &&
3197        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3198        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3199         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3200       IS_TRUE_SYMOP (IC_RESULT (ic)))
3201     {
3202
3203       _G.accInUse++;
3204       aopOp (IC_RESULT (ic), ic, FALSE);
3205       _G.accInUse--;
3206
3207       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3208
3209       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3210     }
3211
3212   /* adjust the stack for parameters if required */
3213   if (ic->parmBytes)
3214     {
3215       int i;
3216       if (ic->parmBytes > 3)
3217         {
3218           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3219               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3220             {
3221               emitcode ("mov", "F0,c");
3222               resultInF0 = TRUE;
3223             }
3224
3225           emitcode ("mov", "a,%s", spname);
3226           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3227           emitcode ("mov", "%s,a", spname);
3228         }
3229       else
3230         for (i = 0; i < ic->parmBytes; i++)
3231           emitcode ("dec", "%s", spname);
3232     }
3233
3234 //  /* if register bank was saved then unsave them */
3235 //  if (restoreBank)
3236 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3237
3238   /* if we had saved some registers then unsave them */
3239   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3240     unsaveRegisters (ic);
3241
3242   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3243     {
3244       if (resultInF0)
3245           emitcode ("mov", "c,F0");
3246
3247       aopOp (IC_RESULT (ic), ic, FALSE);
3248       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3249       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3250     }
3251 }
3252
3253 /*-----------------------------------------------------------------*/
3254 /* resultRemat - result  is rematerializable                       */
3255 /*-----------------------------------------------------------------*/
3256 static int
3257 resultRemat (iCode * ic)
3258 {
3259   if (SKIP_IC (ic) || ic->op == IFX)
3260     return 0;
3261
3262   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3263     {
3264       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3265       if (sym->remat && !POINTER_SET (ic))
3266         return 1;
3267     }
3268
3269   return 0;
3270 }
3271
3272 /*-----------------------------------------------------------------*/
3273 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3274 /*-----------------------------------------------------------------*/
3275 static int
3276 regsCmp(void *p1, void *p2)
3277 {
3278   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3279 }
3280
3281 static bool
3282 inExcludeList (char *s)
3283 {
3284   const char *p = setFirstItem(options.excludeRegsSet);
3285
3286   if (p == NULL || STRCASECMP(p, "none") == 0)
3287     return FALSE;
3288
3289
3290   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3291 }
3292
3293 /*-----------------------------------------------------------------*/
3294 /* genFunction - generated code for function entry                 */
3295 /*-----------------------------------------------------------------*/
3296 static void
3297 genFunction (iCode * ic)
3298 {
3299   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3300   sym_link *ftype;
3301   bool     switchedPSW = FALSE;
3302   int      calleesaves_saved_register = -1;
3303   int      stackAdjust = sym->stack;
3304   int      accIsFree = sym->recvSize < 4;
3305   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3306   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3307
3308   _G.nRegsSaved = 0;
3309   /* create the function header */
3310   emitcode (";", "-----------------------------------------");
3311   emitcode (";", " function %s", sym->name);
3312   emitcode (";", "-----------------------------------------");
3313
3314   emitcode ("", "%s:", sym->rname);
3315   lineCurr->isLabel = 1;
3316   ftype = operandType (IC_LEFT (ic));
3317   _G.currentFunc = sym;
3318
3319   if (IFFUNC_ISNAKED(ftype))
3320   {
3321       emitcode(";", "naked function: no prologue.");
3322       return;
3323   }
3324
3325   /* here we need to generate the equates for the
3326      register bank if required */
3327   if (FUNC_REGBANK (ftype) != rbank)
3328     {
3329       int i;
3330
3331       rbank = FUNC_REGBANK (ftype);
3332       for (i = 0; i < mcs51_nRegs; i++)
3333         {
3334           if (regs8051[i].type != REG_BIT)
3335             {
3336               if (strcmp (regs8051[i].base, "0") == 0)
3337                 emitcode ("", "%s = 0x%02x",
3338                           regs8051[i].dname,
3339                           8 * rbank + regs8051[i].offset);
3340               else
3341                 emitcode ("", "%s = %s + 0x%02x",
3342                           regs8051[i].dname,
3343                           regs8051[i].base,
3344                           8 * rbank + regs8051[i].offset);
3345             }
3346         }
3347     }
3348
3349   /* if this is an interrupt service routine then
3350      save acc, b, dpl, dph  */
3351   if (IFFUNC_ISISR (sym->type))
3352     {
3353       bitVect *rsavebits;
3354
3355       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3356       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3357         {
3358           emitcode ("push", "bits");
3359           BitBankUsed = 1;
3360         }
3361       freeBitVect (rsavebits);
3362
3363       if (!inExcludeList ("acc"))
3364         emitcode ("push", "acc");
3365       if (!inExcludeList ("b"))
3366         emitcode ("push", "b");
3367       if (!inExcludeList ("dpl"))
3368         emitcode ("push", "dpl");
3369       if (!inExcludeList ("dph"))
3370         emitcode ("push", "dph");
3371       /* if this isr has no bank i.e. is going to
3372          run with bank 0 , then we need to save more
3373          registers :-) */
3374       if (!FUNC_REGBANK (sym->type))
3375         {
3376           int i;
3377
3378           /* if this function does not call any other
3379              function then we can be economical and
3380              save only those registers that are used */
3381           if (!IFFUNC_HASFCALL(sym->type))
3382             {
3383               /* if any registers used */
3384               if (sym->regsUsed)
3385                 {
3386                   /* save the registers used */
3387                   for (i = 0; i < sym->regsUsed->size; i++)
3388                     {
3389                       if (bitVectBitValue (sym->regsUsed, i))
3390                         pushReg (i, TRUE);
3391                     }
3392                 }
3393             }
3394           else
3395             {
3396               /* this function has a function call. We cannot
3397                  determine register usage so we will have to push the
3398                  entire bank */
3399                 saveRBank (0, ic, FALSE);
3400                 if (options.parms_in_bank1) {
3401                     for (i=0; i < 8 ; i++ ) {
3402                         emitcode ("push","%s",rb1regs[i]);
3403                     }
3404                 }
3405             }
3406         }
3407         else
3408         {
3409             /* This ISR uses a non-zero bank.
3410              *
3411              * We assume that the bank is available for our
3412              * exclusive use.
3413              *
3414              * However, if this ISR calls a function which uses some
3415              * other bank, we must save that bank entirely.
3416              */
3417             unsigned long banksToSave = 0;
3418
3419             if (IFFUNC_HASFCALL(sym->type))
3420             {
3421
3422 #define MAX_REGISTER_BANKS 4
3423
3424                 iCode *i;
3425                 int ix;
3426
3427                 for (i = ic; i; i = i->next)
3428                 {
3429                     if (i->op == ENDFUNCTION)
3430                     {
3431                         /* we got to the end OK. */
3432                         break;
3433                     }
3434
3435                     if (i->op == CALL)
3436                     {
3437                         sym_link *dtype;
3438
3439                         dtype = operandType (IC_LEFT(i));
3440                         if (dtype
3441                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3442                         {
3443                              /* Mark this bank for saving. */
3444                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3445                              {
3446                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3447                              }
3448                              else
3449                              {
3450                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3451                              }
3452
3453                              /* And note that we don't need to do it in
3454                               * genCall.
3455                               */
3456                              i->bankSaved = 1;
3457                         }
3458                     }
3459                     if (i->op == PCALL)
3460                     {
3461                         /* This is a mess; we have no idea what
3462                          * register bank the called function might
3463                          * use.
3464                          *
3465                          * The only thing I can think of to do is
3466                          * throw a warning and hope.
3467                          */
3468                         werror(W_FUNCPTR_IN_USING_ISR);
3469                     }
3470                 }
3471
3472                 if (banksToSave && options.useXstack)
3473                 {
3474                     /* Since we aren't passing it an ic,
3475                      * saveRBank will assume r0 is available to abuse.
3476                      *
3477                      * So switch to our (trashable) bank now, so
3478                      * the caller's R0 isn't trashed.
3479                      */
3480                     emitcode ("push", "psw");
3481                     emitcode ("mov", "psw,#0x%02x",
3482                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3483                     switchedPSW = TRUE;
3484                 }
3485
3486                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3487                 {
3488                      if (banksToSave & (1 << ix))
3489                      {
3490                          saveRBank(ix, NULL, FALSE);
3491                      }
3492                 }
3493             }
3494             // TODO: this needs a closer look
3495             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3496         }
3497
3498       /* Set the register bank to the desired value if nothing else */
3499       /* has done so yet. */
3500       if (!switchedPSW)
3501         {
3502           emitcode ("push", "psw");
3503           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3504         }
3505     }
3506   else
3507     {
3508       /* This is a non-ISR function. The caller has already switched register */
3509       /* banks, if necessary, so just handle the callee-saves option. */
3510
3511       /* if callee-save to be used for this function
3512          then save the registers being used in this function */
3513       if (IFFUNC_CALLEESAVES(sym->type))
3514         {
3515           int i;
3516
3517           /* if any registers used */
3518           if (sym->regsUsed)
3519             {
3520               bool bits_pushed = FALSE;
3521               /* save the registers used */
3522               for (i = 0; i < sym->regsUsed->size; i++)
3523                 {
3524                   if (bitVectBitValue (sym->regsUsed, i))
3525                     {
3526                       /* remember one saved register for later usage */
3527                       if (calleesaves_saved_register < 0)
3528                         calleesaves_saved_register = i;
3529                       bits_pushed = pushReg (i, bits_pushed);
3530                       _G.nRegsSaved++;
3531                     }
3532                 }
3533             }
3534         }
3535     }
3536
3537   if (fReentrant)
3538     {
3539       if (options.useXstack)
3540         {
3541           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3542             {
3543               emitcode ("mov", "r0,%s", spname);
3544               emitcode ("inc", "%s", spname);
3545               emitcode ("xch", "a,_bpx");
3546               emitcode ("movx", "@r0,a");
3547               emitcode ("inc", "r0");
3548               emitcode ("mov", "a,r0");
3549               emitcode ("xch", "a,_bpx");
3550             }
3551           if (sym->stack)
3552             {
3553               emitcode ("push", "_bp");     /* save the callers stack  */
3554               emitcode ("mov", "_bp,sp");
3555             }
3556         }
3557       else
3558         {
3559           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3560             {
3561               /* set up the stack */
3562               emitcode ("push", "_bp");     /* save the callers stack  */
3563               emitcode ("mov", "_bp,sp");
3564             }
3565         }
3566     }
3567
3568   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3569   /* before setting up the stack frame completely. */
3570   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3571     {
3572       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3573
3574       if (rsym->isitmp)
3575         {
3576           if (rsym && rsym->regType == REG_CND)
3577             rsym = NULL;
3578           if (rsym && (rsym->accuse || rsym->ruonly))
3579             rsym = NULL;
3580           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3581             rsym = rsym->usl.spillLoc;
3582         }
3583
3584       /* If the RECEIVE operand immediately spills to the first entry on the */
3585       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3586       /* rather than the usual @r0/r1 machinations. */
3587       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3588         {
3589           int ofs;
3590
3591           _G.current_iCode = ric;
3592           D(emitcode (";     genReceive",""));
3593           for (ofs=0; ofs < sym->recvSize; ofs++)
3594             {
3595               if (!strcmp (fReturn[ofs], "a"))
3596                 emitcode ("push", "acc");
3597               else
3598                 emitcode ("push", fReturn[ofs]);
3599             }
3600           stackAdjust -= sym->recvSize;
3601           if (stackAdjust<0)
3602             {
3603               assert (stackAdjust>=0);
3604               stackAdjust = 0;
3605             }
3606           _G.current_iCode = ic;
3607           ric->generated = 1;
3608           accIsFree = 1;
3609         }
3610       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3611       /* to free up the accumulator. */
3612       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3613         {
3614           int ofs;
3615
3616           _G.current_iCode = ric;
3617           D(emitcode (";     genReceive",""));
3618           for (ofs=0; ofs < sym->recvSize; ofs++)
3619             {
3620               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3621             }
3622           _G.current_iCode = ic;
3623           ric->generated = 1;
3624           accIsFree = 1;
3625         }
3626     }
3627
3628   /* adjust the stack for the function */
3629   if (stackAdjust)
3630     {
3631       int i = stackAdjust;
3632       if (i > 256)
3633         werror (W_STACK_OVERFLOW, sym->name);
3634
3635       if (i > 3 && accIsFree)
3636         {
3637           emitcode ("mov", "a,sp");
3638           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3639           emitcode ("mov", "sp,a");
3640         }
3641       else if (i > 5)
3642         {
3643           /* The accumulator is not free, so we will need another register */
3644           /* to clobber. No need to worry about a possible conflict with */
3645           /* the above early RECEIVE optimizations since they would have */
3646           /* freed the accumulator if they were generated. */
3647
3648           if (IFFUNC_CALLEESAVES(sym->type))
3649             {
3650               /* if it's a callee-saves function we need a saved register */
3651               if (calleesaves_saved_register >= 0)
3652                 {
3653                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3654                   emitcode ("mov", "a,sp");
3655                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3656                   emitcode ("mov", "sp,a");
3657                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3658                 }
3659               else
3660                 /* do it the hard way */
3661                 while (i--)
3662                   emitcode ("inc", "sp");
3663             }
3664           else
3665             {
3666               /* not callee-saves, we can clobber r0 */
3667               emitcode ("mov", "r0,a");
3668               emitcode ("mov", "a,sp");
3669               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3670               emitcode ("mov", "sp,a");
3671               emitcode ("mov", "a,r0");
3672             }
3673         }
3674       else
3675         while (i--)
3676           emitcode ("inc", "sp");
3677     }
3678
3679   if (sym->xstack)
3680     {
3681       char i = ((char) sym->xstack & 0xff);
3682
3683       if (i > 3 && accIsFree)
3684         {
3685           emitcode ("mov", "a,_spx");
3686           emitcode ("add", "a,#0x%02x", i & 0xff);
3687           emitcode ("mov", "_spx,a");
3688         }
3689       else if (i > 5)
3690         {
3691           emitcode ("push", "acc");
3692           emitcode ("mov", "a,_spx");
3693           emitcode ("add", "a,#0x%02x", i & 0xff);
3694           emitcode ("mov", "_spx,a");
3695           emitcode ("pop", "acc");
3696         }
3697       else
3698         {
3699           while (i--)
3700             emitcode ("inc", "_spx");
3701         }
3702     }
3703
3704   /* if critical function then turn interrupts off */
3705   if (IFFUNC_ISCRITICAL (ftype))
3706     {
3707       symbol *tlbl = newiTempLabel (NULL);
3708       emitcode ("setb", "c");
3709       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3710       emitcode ("clr", "c");
3711       emitLabel (tlbl);
3712       emitcode ("push", "psw"); /* save old ea via c in psw */
3713     }
3714 }
3715
3716 /*-----------------------------------------------------------------*/
3717 /* genEndFunction - generates epilogue for functions               */
3718 /*-----------------------------------------------------------------*/
3719 static void
3720 genEndFunction (iCode * ic)
3721 {
3722   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3723   lineNode *lnp = lineCurr;
3724   bitVect  *regsUsed;
3725   bitVect  *regsUsedPrologue;
3726   bitVect  *regsUnneeded;
3727   int      idx;
3728
3729   _G.currentFunc = NULL;
3730   if (IFFUNC_ISNAKED(sym->type))
3731   {
3732       emitcode(";", "naked function: no epilogue.");
3733       if (options.debug && currFunc)
3734         debugFile->writeEndFunction (currFunc, ic, 0);
3735       return;
3736   }
3737
3738   if (IFFUNC_ISCRITICAL (sym->type))
3739     {
3740       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3741         {
3742           emitcode ("rlc", "a");   /* save c in a */
3743           emitcode ("pop", "psw"); /* restore ea via c in psw */
3744           emitcode ("mov", "ea,c");
3745           emitcode ("rrc", "a");   /* restore c from a */
3746         }
3747       else
3748         {
3749           emitcode ("pop", "psw"); /* restore ea via c in psw */
3750           emitcode ("mov", "ea,c");
3751         }
3752     }
3753
3754   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3755     {
3756       if (options.useXstack)
3757         {
3758           if (sym->stack)
3759             {
3760               emitcode ("mov", "sp,_bp");
3761               emitcode ("pop", "_bp");
3762             }
3763           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3764             {
3765               emitcode ("xch", "a,_bpx");
3766               emitcode ("mov", "r0,a");
3767               emitcode ("dec", "r0");
3768               emitcode ("movx", "a,@r0");
3769               emitcode ("xch", "a,_bpx");
3770               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3771             }
3772         }
3773       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3774         {
3775           if (sym->stack)
3776             emitcode ("mov", "sp,_bp");
3777           emitcode ("pop", "_bp");
3778         }
3779     }
3780
3781   /* restore the register bank  */
3782   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3783   {
3784     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3785      || !options.useXstack)
3786     {
3787         /* Special case of ISR using non-zero bank with useXstack
3788          * is handled below.
3789          */
3790         emitcode ("pop", "psw");
3791     }
3792   }
3793
3794   if (IFFUNC_ISISR (sym->type))
3795     {
3796       bitVect *rsavebits;
3797
3798       /* now we need to restore the registers */
3799       /* if this isr has no bank i.e. is going to
3800          run with bank 0 , then we need to save more
3801          registers :-) */
3802       if (!FUNC_REGBANK (sym->type))
3803         {
3804           int i;
3805           /* if this function does not call any other
3806              function then we can be economical and
3807              save only those registers that are used */
3808           if (!IFFUNC_HASFCALL(sym->type))
3809             {
3810               /* if any registers used */
3811               if (sym->regsUsed)
3812                 {
3813                   /* save the registers used */
3814                   for (i = sym->regsUsed->size; i >= 0; i--)
3815                     {
3816                       if (bitVectBitValue (sym->regsUsed, i))
3817                         popReg (i, TRUE);
3818                     }
3819                 }
3820             }
3821           else
3822             {
3823               if (options.parms_in_bank1) {
3824                   for (i = 7 ; i >= 0 ; i-- ) {
3825                       emitcode ("pop","%s",rb1regs[i]);
3826                   }
3827               }
3828               /* this function has a function call. We cannot
3829                  determine register usage so we will have to pop the
3830                  entire bank */
3831               unsaveRBank (0, ic, FALSE);
3832             }
3833         }
3834         else
3835         {
3836             /* This ISR uses a non-zero bank.
3837              *
3838              * Restore any register banks saved by genFunction
3839              * in reverse order.
3840              */
3841             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3842             int ix;
3843
3844             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3845             {
3846                 if (savedBanks & (1 << ix))
3847                 {
3848                     unsaveRBank(ix, NULL, FALSE);
3849                 }
3850             }
3851
3852             if (options.useXstack)
3853             {
3854                 /* Restore bank AFTER calling unsaveRBank,
3855                  * since it can trash r0.
3856                  */
3857                 emitcode ("pop", "psw");
3858             }
3859         }
3860
3861       if (!inExcludeList ("dph"))
3862         emitcode ("pop", "dph");
3863       if (!inExcludeList ("dpl"))
3864         emitcode ("pop", "dpl");
3865       if (!inExcludeList ("b"))
3866         emitcode ("pop", "b");
3867       if (!inExcludeList ("acc"))
3868         emitcode ("pop", "acc");
3869
3870       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3871       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3872         emitcode ("pop", "bits");
3873       freeBitVect (rsavebits);
3874
3875       /* if debug then send end of function */
3876       if (options.debug && currFunc)
3877         {
3878           debugFile->writeEndFunction (currFunc, ic, 1);
3879         }
3880
3881       emitcode ("reti", "");
3882     }
3883   else
3884     {
3885       if (IFFUNC_CALLEESAVES(sym->type))
3886         {
3887           int i;
3888
3889           /* if any registers used */
3890           if (sym->regsUsed)
3891             {
3892               /* save the registers used */
3893               for (i = sym->regsUsed->size; i >= 0; i--)
3894                 {
3895                   if (bitVectBitValue (sym->regsUsed, i) ||
3896                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3897                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3898                 }
3899             }
3900           else if (mcs51_ptrRegReq)
3901             {
3902               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3903               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3904             }
3905
3906         }
3907
3908       /* if debug then send end of function */
3909       if (options.debug && currFunc)
3910         {
3911           debugFile->writeEndFunction (currFunc, ic, 1);
3912         }
3913
3914       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3915         {
3916           emitcode ("ljmp", "__sdcc_banked_ret");
3917         }
3918       else
3919         {
3920           emitcode ("ret", "");
3921         }
3922     }
3923
3924   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3925     return;
3926
3927   /* If this was an interrupt handler using bank 0 that called another */
3928   /* function, then all registers must be saved; nothing to optimized. */
3929   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3930       && !FUNC_REGBANK(sym->type))
3931     return;
3932
3933   /* There are no push/pops to optimize if not callee-saves or ISR */
3934   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3935     return;
3936
3937   /* If there were stack parameters, we cannot optimize without also    */
3938   /* fixing all of the stack offsets; this is too dificult to consider. */
3939   if (FUNC_HASSTACKPARM(sym->type))
3940     return;
3941
3942   /* Compute the registers actually used */
3943   regsUsed = newBitVect (mcs51_nRegs);
3944   regsUsedPrologue = newBitVect (mcs51_nRegs);
3945   while (lnp)
3946     {
3947       if (lnp->ic && lnp->ic->op == FUNCTION)
3948         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3949       else
3950         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3951
3952       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3953           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3954         break;
3955       if (!lnp->prev)
3956         break;
3957       lnp = lnp->prev;
3958     }
3959
3960   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3961       && !bitVectBitValue (regsUsed, CND_IDX))
3962     {
3963       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3964       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3965           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3966         bitVectUnSetBit (regsUsed, CND_IDX);
3967     }
3968   else
3969     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3970
3971   /* If this was an interrupt handler that called another function */
3972   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3973   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3974     {
3975       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3976       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3980     }
3981
3982   /* Remove the unneeded push/pops */
3983   regsUnneeded = newBitVect (mcs51_nRegs);
3984   while (lnp)
3985     {
3986       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3987         {
3988           if (!strncmp(lnp->line, "push", 4))
3989             {
3990               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3991               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3992                 {
3993                   connectLine (lnp->prev, lnp->next);
3994                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3995                 }
3996             }
3997           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3998             {
3999               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4000               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4001                 {
4002                   connectLine (lnp->prev, lnp->next);
4003                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4004                 }
4005             }
4006         }
4007       lnp = lnp->next;
4008     }
4009
4010   for (idx = 0; idx < regsUnneeded->size; idx++)
4011     if (bitVectBitValue (regsUnneeded, idx))
4012       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4013
4014   freeBitVect (regsUnneeded);
4015   freeBitVect (regsUsed);
4016   freeBitVect (regsUsedPrologue);
4017 }
4018
4019 /*-----------------------------------------------------------------*/
4020 /* genRet - generate code for return statement                     */
4021 /*-----------------------------------------------------------------*/
4022 static void
4023 genRet (iCode * ic)
4024 {
4025   int size, offset = 0, pushed = 0;
4026
4027   D (emitcode (";", "genRet"));
4028
4029   /* if we have no return value then
4030      just generate the "ret" */
4031   if (!IC_LEFT (ic))
4032     goto jumpret;
4033
4034   /* we have something to return then
4035      move the return value into place */
4036   aopOp (IC_LEFT (ic), ic, FALSE);
4037   size = AOP_SIZE (IC_LEFT (ic));
4038
4039   if (IS_BIT(_G.currentFunc->etype))
4040     {
4041       toCarry (IC_LEFT (ic));
4042     }
4043   else
4044     {
4045       while (size--)
4046         {
4047           char *l;
4048           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4049             {
4050               /* #NOCHANGE */
4051               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4052               emitcode ("push", "%s", l);
4053               pushed++;
4054             }
4055           else
4056             {
4057               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4058               if (strcmp (fReturn[offset], l))
4059                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4060             }
4061         }
4062
4063       while (pushed)
4064         {
4065           pushed--;
4066           if (strcmp (fReturn[pushed], "a"))
4067             emitcode ("pop", fReturn[pushed]);
4068           else
4069             emitcode ("pop", "acc");
4070         }
4071     }
4072   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4073
4074 jumpret:
4075   /* generate a jump to the return label
4076      if the next is not the return statement */
4077   if (!(ic->next && ic->next->op == LABEL &&
4078         IC_LABEL (ic->next) == returnLabel))
4079
4080     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4081
4082 }
4083
4084 /*-----------------------------------------------------------------*/
4085 /* genLabel - generates a label                                    */
4086 /*-----------------------------------------------------------------*/
4087 static void
4088 genLabel (iCode * ic)
4089 {
4090   /* special case never generate */
4091   if (IC_LABEL (ic) == entryLabel)
4092     return;
4093
4094   emitLabel (IC_LABEL (ic));
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /* genGoto - generates a ljmp                                      */
4099 /*-----------------------------------------------------------------*/
4100 static void
4101 genGoto (iCode * ic)
4102 {
4103   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4104 }
4105
4106 /*-----------------------------------------------------------------*/
4107 /* findLabelBackwards: walks back through the iCode chain looking  */
4108 /* for the given label. Returns number of iCode instructions     */
4109 /* between that label and given ic.          */
4110 /* Returns zero if label not found.          */
4111 /*-----------------------------------------------------------------*/
4112 static int
4113 findLabelBackwards (iCode * ic, int key)
4114 {
4115   int count = 0;
4116
4117   while (ic->prev)
4118     {
4119       ic = ic->prev;
4120       count++;
4121
4122       /* If we have any pushes or pops, we cannot predict the distance.
4123          I don't like this at all, this should be dealt with in the
4124          back-end */
4125       if (ic->op == IPUSH || ic->op == IPOP) {
4126         return 0;
4127       }
4128
4129       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4130         {
4131           return count;
4132         }
4133     }
4134
4135   return 0;
4136 }
4137
4138 /*-----------------------------------------------------------------*/
4139 /* genPlusIncr :- does addition with increment if possible         */
4140 /*-----------------------------------------------------------------*/
4141 static bool
4142 genPlusIncr (iCode * ic)
4143 {
4144   unsigned int icount;
4145   unsigned int size = getDataSize (IC_RESULT (ic));
4146
4147   /* will try to generate an increment */
4148   /* if the right side is not a literal
4149      we cannot */
4150   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4151     return FALSE;
4152
4153   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4154
4155   D(emitcode (";","genPlusIncr"));
4156
4157   /* if increment >=16 bits in register or direct space */
4158   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4159         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4160         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4161       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4162       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4163       (size > 1) &&
4164       (icount == 1))
4165     {
4166       symbol *tlbl;
4167       int emitTlbl;
4168       int labelRange;
4169
4170       /* If the next instruction is a goto and the goto target
4171        * is < 10 instructions previous to this, we can generate
4172        * jumps straight to that target.
4173        */
4174       if (ic->next && ic->next->op == GOTO
4175           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4176           && labelRange <= 10)
4177         {
4178           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4179           tlbl = IC_LABEL (ic->next);
4180           emitTlbl = 0;
4181         }
4182       else
4183         {
4184           tlbl = newiTempLabel (NULL);
4185           emitTlbl = 1;
4186         }
4187       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4188       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4189           IS_AOP_PREG (IC_RESULT (ic)))
4190         emitcode ("cjne", "%s,#0x00,%05d$",
4191                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4192                   tlbl->key + 100);
4193       else
4194         {
4195           emitcode ("clr", "a");
4196           emitcode ("cjne", "a,%s,%05d$",
4197                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4198                     tlbl->key + 100);
4199         }
4200
4201       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4202       if (size > 2)
4203         {
4204           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4205               IS_AOP_PREG (IC_RESULT (ic)))
4206             emitcode ("cjne", "%s,#0x00,%05d$",
4207                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4208                       tlbl->key + 100);
4209           else
4210             emitcode ("cjne", "a,%s,%05d$",
4211                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4212                       tlbl->key + 100);
4213
4214           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4215         }
4216       if (size > 3)
4217         {
4218           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4219               IS_AOP_PREG (IC_RESULT (ic)))
4220             emitcode ("cjne", "%s,#0x00,%05d$",
4221                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4222                       tlbl->key + 100);
4223           else
4224             {
4225               emitcode ("cjne", "a,%s,%05d$",
4226                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4227                         tlbl->key + 100);
4228             }
4229           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4230         }
4231
4232       if (emitTlbl)
4233         {
4234           emitLabel (tlbl);
4235         }
4236       return TRUE;
4237     }
4238
4239   /* if result is dptr */
4240   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4241       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4242       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4243       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4244     {
4245       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4246         return FALSE;
4247
4248       if (icount > 9)
4249         return FALSE;
4250
4251       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4252         return FALSE;
4253
4254       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4255       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4256       while (icount--)
4257         emitcode ("inc", "dptr");
4258
4259       return TRUE;
4260     }
4261
4262   /* if the literal value of the right hand side
4263      is greater than 4 then it is not worth it */
4264   if (icount > 4)
4265     return FALSE;
4266
4267   /* if the sizes are greater than 1 then we cannot */
4268   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4269       AOP_SIZE (IC_LEFT (ic)) > 1)
4270     return FALSE;
4271
4272   /* we can if the aops of the left & result match or
4273      if they are in registers and the registers are the
4274      same */
4275   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4276     {
4277       if (icount > 3)
4278         {
4279           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4280           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4281           aopPut (IC_RESULT (ic), "a", 0);
4282         }
4283       else
4284         {
4285           while (icount--)
4286             {
4287               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4288             }
4289         }
4290
4291       return TRUE;
4292     }
4293
4294   if (icount == 1)
4295     {
4296       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4297       emitcode ("inc", "a");
4298       aopPut (IC_RESULT (ic), "a", 0);
4299       return TRUE;
4300     }
4301
4302   return FALSE;
4303 }
4304
4305 /*-----------------------------------------------------------------*/
4306 /* outBitAcc - output a bit in acc                                 */
4307 /*-----------------------------------------------------------------*/
4308 static void
4309 outBitAcc (operand * result)
4310 {
4311   symbol *tlbl = newiTempLabel (NULL);
4312   /* if the result is a bit */
4313   if (AOP_TYPE (result) == AOP_CRY)
4314     {
4315       aopPut (result, "a", 0);
4316     }
4317   else
4318     {
4319       emitcode ("jz", "%05d$", tlbl->key + 100);
4320       emitcode ("mov", "a,%s", one);
4321       emitLabel (tlbl);
4322       outAcc (result);
4323     }
4324 }
4325
4326 /*-----------------------------------------------------------------*/
4327 /* genPlusBits - generates code for addition of two bits           */
4328 /*-----------------------------------------------------------------*/
4329 static void
4330 genPlusBits (iCode * ic)
4331 {
4332   D (emitcode (";", "genPlusBits"));
4333
4334   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4335   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4336     {
4337       symbol *lbl = newiTempLabel (NULL);
4338       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4339       emitcode ("cpl", "c");
4340       emitLabel (lbl);
4341       outBitC (IC_RESULT (ic));
4342     }
4343   else
4344     {
4345       emitcode ("clr", "a");
4346       emitcode ("rlc", "a");
4347       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4348       emitcode ("addc", "a,%s", zero);
4349       outAcc (IC_RESULT (ic));
4350     }
4351 }
4352
4353 #if 0
4354 /* This is the original version of this code.
4355
4356  * This is being kept around for reference,
4357  * because I am not entirely sure I got it right...
4358  */
4359 static void
4360 adjustArithmeticResult (iCode * ic)
4361 {
4362   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4363       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4364       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4365     aopPut (IC_RESULT (ic),
4366             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4367             2);
4368
4369   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4370       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4371       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4372     aopPut (IC_RESULT (ic),
4373             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4374             2);
4375
4376   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4377       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4378       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4379       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4380       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4381     {
4382       char buffer[5];
4383       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4384       aopPut (IC_RESULT (ic), buffer, 2);
4385     }
4386 }
4387 #else
4388 /* This is the pure and virtuous version of this code.
4389  * I'm pretty certain it's right, but not enough to toss the old
4390  * code just yet...
4391  */
4392 static void
4393 adjustArithmeticResult (iCode * ic)
4394 {
4395   if (opIsGptr (IC_RESULT (ic)) &&
4396       opIsGptr (IC_LEFT (ic)) &&
4397       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4398     {
4399       aopPut (IC_RESULT (ic),
4400               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4401               GPTRSIZE - 1);
4402     }
4403
4404   if (opIsGptr (IC_RESULT (ic)) &&
4405       opIsGptr (IC_RIGHT (ic)) &&
4406       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4407     {
4408       aopPut (IC_RESULT (ic),
4409               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4410               GPTRSIZE - 1);
4411     }
4412
4413   if (opIsGptr (IC_RESULT (ic)) &&
4414       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4415       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4416       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4417       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4418     {
4419       char buffer[5];
4420       SNPRINTF (buffer, sizeof(buffer),
4421                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4422       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4423     }
4424 }
4425 #endif
4426
4427 /*-----------------------------------------------------------------*/
4428 /* genPlus - generates code for addition                           */
4429 /*-----------------------------------------------------------------*/
4430 static void
4431 genPlus (iCode * ic)
4432 {
4433   int size, offset = 0;
4434   int skip_bytes = 0;
4435   char *add = "add";
4436   bool swappedLR = FALSE;
4437   operand *leftOp, *rightOp;
4438   operand * op;
4439
4440   D (emitcode (";", "genPlus"));
4441
4442   /* special cases :- */
4443
4444   aopOp (IC_LEFT (ic), ic, FALSE);
4445   aopOp (IC_RIGHT (ic), ic, FALSE);
4446   aopOp (IC_RESULT (ic), ic, TRUE);
4447
4448   /* if literal, literal on the right or
4449      if left requires ACC or right is already
4450      in ACC */
4451   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4452       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4453       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4454     {
4455       operand *t = IC_RIGHT (ic);
4456       IC_RIGHT (ic) = IC_LEFT (ic);
4457       IC_LEFT (ic) = t;
4458       swappedLR = TRUE;
4459     }
4460
4461   /* if both left & right are in bit
4462      space */
4463   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4464       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4465     {
4466       genPlusBits (ic);
4467       goto release;
4468     }
4469
4470   /* if left in bit space & right literal */
4471   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4472       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4473     {
4474       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4475       /* if result in bit space */
4476       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4477         {
4478           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4479             emitcode ("cpl", "c");
4480           outBitC (IC_RESULT (ic));
4481         }
4482       else
4483         {
4484           size = getDataSize (IC_RESULT (ic));
4485           while (size--)
4486             {
4487               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4488               emitcode ("addc", "a,%s", zero);
4489               aopPut (IC_RESULT (ic), "a", offset++);
4490             }
4491         }
4492       goto release;
4493     }
4494
4495   /* if I can do an increment instead
4496      of add then GOOD for ME */
4497   if (genPlusIncr (ic) == TRUE)
4498     goto release;
4499
4500   size = getDataSize (IC_RESULT (ic));
4501   leftOp = IC_LEFT(ic);
4502   rightOp = IC_RIGHT(ic);
4503   op = IC_LEFT(ic);
4504
4505   /* if this is an add for an array access
4506      at a 256 byte boundary */
4507   if ( 2 == size
4508        && AOP_TYPE (op) == AOP_IMMD
4509        && IS_SYMOP (op)
4510        && IS_SPEC (OP_SYM_ETYPE (op))
4511        && SPEC_ABSA (OP_SYM_ETYPE (op))
4512        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4513      )
4514     {
4515       D(emitcode (";     genPlus aligned array",""));
4516       aopPut (IC_RESULT (ic),
4517               aopGet (rightOp, 0, FALSE, FALSE),
4518               0);
4519
4520       if( 1 == getDataSize (IC_RIGHT (ic)) )
4521         {
4522           aopPut (IC_RESULT (ic),
4523                   aopGet (leftOp, 1, FALSE, FALSE),
4524                   1);
4525         }
4526       else
4527         {
4528           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4529           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4530           aopPut (IC_RESULT (ic), "a", 1);
4531         }
4532       goto release;
4533     }
4534
4535   /* if the lower bytes of a literal are zero skip the addition */
4536   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4537     {
4538        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4539               (skip_bytes+1 < size))
4540          {
4541            skip_bytes++;
4542          }
4543        if (skip_bytes)
4544          D(emitcode (";     genPlus shortcut",""));
4545     }
4546
4547   while (size--)
4548     {
4549       if( offset >= skip_bytes )
4550         {
4551           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4552             {
4553               bool pushedB;
4554               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4555               pushedB = pushB ();
4556               emitcode("xch", "a,b");
4557               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4558               emitcode (add, "a,b");
4559               popB (pushedB);
4560             }
4561           else if (aopGetUsesAcc (leftOp, offset))
4562             {
4563               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4564               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4565             }
4566           else
4567             {
4568               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4569               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4570             }
4571           aopPut (IC_RESULT (ic), "a", offset);
4572           add = "addc";  /* further adds must propagate carry */
4573         }
4574       else
4575         {
4576           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4577               isOperandVolatile (IC_RESULT (ic), FALSE))
4578             {
4579               /* just move */
4580               aopPut (IC_RESULT (ic),
4581                       aopGet (leftOp, offset, FALSE, FALSE),
4582                       offset);
4583             }
4584         }
4585       offset++;
4586     }
4587
4588   adjustArithmeticResult (ic);
4589
4590 release:
4591   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4592   if (!swappedLR)
4593     {
4594       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4595       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4596     }
4597   else
4598     {
4599       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4600       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4601     }
4602 }
4603
4604 /*-----------------------------------------------------------------*/
4605 /* genMinusDec :- does subtraction with decrement if possible      */
4606 /*-----------------------------------------------------------------*/
4607 static bool
4608 genMinusDec (iCode * ic)
4609 {
4610   unsigned int icount;
4611   unsigned int size = getDataSize (IC_RESULT (ic));
4612
4613   /* will try to generate an increment */
4614   /* if the right side is not a literal
4615      we cannot */
4616   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4617     return FALSE;
4618
4619   /* if the literal value of the right hand side
4620      is greater than 4 then it is not worth it */
4621   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4622     return FALSE;
4623
4624   D (emitcode (";", "genMinusDec"));
4625
4626   /* if decrement >=16 bits in register or direct space */
4627   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4628         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4629         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4630       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4631       (size > 1) &&
4632       (icount == 1))
4633     {
4634       symbol *tlbl;
4635       int emitTlbl;
4636       int labelRange;
4637
4638       /* If the next instruction is a goto and the goto target
4639        * is <= 10 instructions previous to this, we can generate
4640        * jumps straight to that target.
4641        */
4642       if (ic->next && ic->next->op == GOTO
4643           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4644           && labelRange <= 10)
4645         {
4646           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4647           tlbl = IC_LABEL (ic->next);
4648           emitTlbl = 0;
4649         }
4650       else
4651         {
4652           tlbl = newiTempLabel (NULL);
4653           emitTlbl = 1;
4654         }
4655
4656       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4657       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4658           IS_AOP_PREG (IC_RESULT (ic)))
4659         emitcode ("cjne", "%s,#0xff,%05d$"
4660                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4661                   ,tlbl->key + 100);
4662       else
4663         {
4664           emitcode ("mov", "a,#0xff");
4665           emitcode ("cjne", "a,%s,%05d$"
4666                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4667                     ,tlbl->key + 100);
4668         }
4669       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4670       if (size > 2)
4671         {
4672           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4673               IS_AOP_PREG (IC_RESULT (ic)))
4674             emitcode ("cjne", "%s,#0xff,%05d$"
4675                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4676                       ,tlbl->key + 100);
4677           else
4678             {
4679               emitcode ("cjne", "a,%s,%05d$"
4680                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4681                         ,tlbl->key + 100);
4682             }
4683           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4684         }
4685       if (size > 3)
4686         {
4687           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4688               IS_AOP_PREG (IC_RESULT (ic)))
4689             emitcode ("cjne", "%s,#0xff,%05d$"
4690                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4691                       ,tlbl->key + 100);
4692           else
4693             {
4694               emitcode ("cjne", "a,%s,%05d$"
4695                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4696                         ,tlbl->key + 100);
4697             }
4698           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4699         }
4700       if (emitTlbl)
4701         {
4702           emitLabel (tlbl);
4703         }
4704       return TRUE;
4705     }
4706
4707   /* if the sizes are greater than 1 then we cannot */
4708   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4709       AOP_SIZE (IC_LEFT (ic)) > 1)
4710     return FALSE;
4711
4712   /* we can if the aops of the left & result match or
4713      if they are in registers and the registers are the
4714      same */
4715   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4716     {
4717       char *l;
4718
4719       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4720         {
4721           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4722           l = "a";
4723         }
4724       else
4725         {
4726           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4727         }
4728
4729       while (icount--)
4730         {
4731           emitcode ("dec", "%s", l);
4732         }
4733
4734       if (AOP_NEEDSACC (IC_RESULT (ic)))
4735         aopPut (IC_RESULT (ic), "a", 0);
4736
4737       return TRUE;
4738     }
4739
4740   if (icount == 1)
4741     {
4742       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4743       emitcode ("dec", "a");
4744       aopPut (IC_RESULT (ic), "a", 0);
4745       return TRUE;
4746     }
4747
4748   return FALSE;
4749 }
4750
4751 /*-----------------------------------------------------------------*/
4752 /* addSign - complete with sign                                    */
4753 /*-----------------------------------------------------------------*/
4754 static void
4755 addSign (operand * result, int offset, int sign)
4756 {
4757   int size = (getDataSize (result) - offset);
4758   if (size > 0)
4759     {
4760       if (sign)
4761         {
4762           emitcode ("rlc", "a");
4763           emitcode ("subb", "a,acc");
4764           while (size--)
4765             {
4766               aopPut (result, "a", offset++);
4767             }
4768         }
4769       else
4770         {
4771           while (size--)
4772             {
4773               aopPut (result, zero, offset++);
4774             }
4775         }
4776     }
4777 }
4778
4779 /*-----------------------------------------------------------------*/
4780 /* genMinusBits - generates code for subtraction  of two bits      */
4781 /*-----------------------------------------------------------------*/
4782 static void
4783 genMinusBits (iCode * ic)
4784 {
4785   symbol *lbl = newiTempLabel (NULL);
4786
4787   D (emitcode (";", "genMinusBits"));
4788
4789   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4790     {
4791       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4792       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4793       emitcode ("cpl", "c");
4794       emitLabel (lbl);
4795       outBitC (IC_RESULT (ic));
4796     }
4797   else
4798     {
4799       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4800       emitcode ("subb", "a,acc");
4801       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4802       emitcode ("inc", "a");
4803       emitLabel (lbl);
4804       aopPut (IC_RESULT (ic), "a", 0);
4805       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4806     }
4807 }
4808
4809 /*-----------------------------------------------------------------*/
4810 /* genMinus - generates code for subtraction                       */
4811 /*-----------------------------------------------------------------*/
4812 static void
4813 genMinus (iCode * ic)
4814 {
4815   int size, offset = 0;
4816
4817   D (emitcode (";", "genMinus"));
4818
4819   aopOp (IC_LEFT (ic), ic, FALSE);
4820   aopOp (IC_RIGHT (ic), ic, FALSE);
4821   aopOp (IC_RESULT (ic), ic, TRUE);
4822
4823   /* special cases :- */
4824   /* if both left & right are in bit space */
4825   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4826       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4827     {
4828       genMinusBits (ic);
4829       goto release;
4830     }
4831
4832   /* if I can do an decrement instead
4833      of subtract then GOOD for ME */
4834   if (genMinusDec (ic) == TRUE)
4835     goto release;
4836
4837   size = getDataSize (IC_RESULT (ic));
4838
4839   /* if literal, add a,#-lit, else normal subb */
4840   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4841     {
4842       unsigned long lit = 0L;
4843       bool useCarry = FALSE;
4844
4845       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4846       lit = -(long) lit;
4847
4848       while (size--)
4849         {
4850           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4851             {
4852               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4853               if (!offset && !size && lit== (unsigned long) -1)
4854                 {
4855                   emitcode ("dec", "a");
4856                 }
4857               else if (!useCarry)
4858                 {
4859                   /* first add without previous c */
4860                   emitcode ("add", "a,#0x%02x",
4861                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4862                   useCarry = TRUE;
4863                 }
4864               else
4865                 {
4866                   emitcode ("addc", "a,#0x%02x",
4867                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4868                 }
4869               aopPut (IC_RESULT (ic), "a", offset++);
4870             }
4871           else
4872             {
4873               /* no need to add zeroes */
4874               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4875                 {
4876                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4877                           offset);
4878                 }
4879               offset++;
4880             }
4881         }
4882     }
4883   else
4884     {
4885       operand *leftOp, *rightOp;
4886
4887       leftOp = IC_LEFT(ic);
4888       rightOp = IC_RIGHT(ic);
4889
4890       while (size--)
4891         {
4892           if (aopGetUsesAcc(rightOp, offset)) {
4893             if (aopGetUsesAcc(leftOp, offset)) {
4894               bool pushedB;
4895
4896               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4897               pushedB = pushB ();
4898               emitcode ("mov", "b,a");
4899               if (offset == 0)
4900                 CLRC;
4901               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4902               emitcode ("subb", "a,b");
4903               popB (pushedB);
4904             } else {
4905               /* reverse subtraction with 2's complement */
4906               if (offset == 0)
4907                 emitcode( "setb", "c");
4908               else
4909                 emitcode( "cpl", "c");
4910               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4911               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4912               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4913               emitcode("cpl", "a");
4914               if (size) /* skip if last byte */
4915                 emitcode( "cpl", "c");
4916             }
4917           } else {
4918             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4919             if (offset == 0)
4920               CLRC;
4921             emitcode ("subb", "a,%s",
4922                       aopGet(rightOp, offset, FALSE, TRUE));
4923           }
4924
4925           aopPut (IC_RESULT (ic), "a", offset++);
4926         }
4927     }
4928
4929   adjustArithmeticResult (ic);
4930
4931 release:
4932   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4933   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4934   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4935 }
4936
4937
4938 /*-----------------------------------------------------------------*/
4939 /* genMultbits :- multiplication of bits                           */
4940 /*-----------------------------------------------------------------*/
4941 static void
4942 genMultbits (operand * left,
4943              operand * right,
4944              operand * result)
4945 {
4946   D (emitcode (";", "genMultbits"));
4947
4948   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4949   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4950   outBitC (result);
4951 }
4952
4953 /*-----------------------------------------------------------------*/
4954 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4955 /*-----------------------------------------------------------------*/
4956 static void
4957 genMultOneByte (operand * left,
4958                 operand * right,
4959                 operand * result)
4960 {
4961   symbol *lbl;
4962   int size = AOP_SIZE (result);
4963   bool runtimeSign, compiletimeSign;
4964   bool lUnsigned, rUnsigned, pushedB;
4965
4966   D (emitcode (";", "genMultOneByte"));
4967
4968   if (size < 1 || size > 2)
4969     {
4970       /* this should never happen */
4971       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4972                AOP_SIZE(result), __FILE__, lineno);
4973       exit (1);
4974     }
4975
4976   /* (if two literals: the value is computed before) */
4977   /* if one literal, literal on the right */
4978   if (AOP_TYPE (left) == AOP_LIT)
4979     {
4980       operand *t = right;
4981       right = left;
4982       left = t;
4983       /* emitcode (";", "swapped left and right"); */
4984     }
4985   /* if no literal, unsigned on the right: shorter code */
4986   if (   AOP_TYPE (right) != AOP_LIT
4987       && SPEC_USIGN (getSpec (operandType (left))))
4988     {
4989       operand *t = right;
4990       right = left;
4991       left = t;
4992     }
4993
4994   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4995   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4996
4997   pushedB = pushB ();
4998
4999   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5000                    no need to take care about the signedness! */
5001       || (lUnsigned && rUnsigned))
5002     {
5003       /* just an unsigned 8 * 8 = 8 multiply
5004          or 8u * 8u = 16u */
5005       /* emitcode (";","unsigned"); */
5006       /* TODO: check for accumulator clash between left & right aops? */
5007
5008       if (AOP_TYPE (right) == AOP_LIT)
5009         {
5010           /* moving to accumulator first helps peepholes */
5011           MOVA (aopGet (left, 0, FALSE, FALSE));
5012           MOVB (aopGet (right, 0, FALSE, FALSE));
5013         }
5014       else
5015         {
5016           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5017           MOVA (aopGet (left, 0, FALSE, FALSE));
5018         }
5019
5020       emitcode ("mul", "ab");
5021       aopPut (result, "a", 0);
5022       if (size == 2)
5023         aopPut (result, "b", 1);
5024
5025       popB (pushedB);
5026       return;
5027     }
5028
5029   /* we have to do a signed multiply */
5030   /* emitcode (";", "signed"); */
5031
5032   /* now sign adjust for both left & right */
5033
5034   /* let's see what's needed: */
5035   /* apply negative sign during runtime */
5036   runtimeSign = FALSE;
5037   /* negative sign from literals */
5038   compiletimeSign = FALSE;
5039
5040   if (!lUnsigned)
5041     {
5042       if (AOP_TYPE(left) == AOP_LIT)
5043         {
5044           /* signed literal */
5045           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5046           if (val < 0)
5047             compiletimeSign = TRUE;
5048         }
5049       else
5050         /* signed but not literal */
5051         runtimeSign = TRUE;
5052     }
5053
5054   if (!rUnsigned)
5055     {
5056       if (AOP_TYPE(right) == AOP_LIT)
5057         {
5058           /* signed literal */
5059           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5060           if (val < 0)
5061             compiletimeSign ^= TRUE;
5062         }
5063       else
5064         /* signed but not literal */
5065         runtimeSign = TRUE;
5066     }
5067
5068   /* initialize F0, which stores the runtime sign */
5069   if (runtimeSign)
5070     {
5071       if (compiletimeSign)
5072         emitcode ("setb", "F0"); /* set sign flag */
5073       else
5074         emitcode ("clr", "F0"); /* reset sign flag */
5075     }
5076
5077   /* save the signs of the operands */
5078   if (AOP_TYPE(right) == AOP_LIT)
5079     {
5080       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5081
5082       if (!rUnsigned && val < 0)
5083         emitcode ("mov", "b,#0x%02x", -val);
5084       else
5085         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5086     }
5087   else /* ! literal */
5088     {
5089       if (rUnsigned)  /* emitcode (";", "signed"); */
5090         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5091       else
5092         {
5093           MOVA (aopGet (right, 0, FALSE, FALSE));
5094           lbl = newiTempLabel (NULL);
5095           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5096           emitcode ("cpl", "F0"); /* complement sign flag */
5097           emitcode ("cpl", "a");  /* 2's complement */
5098           emitcode ("inc", "a");
5099           emitLabel (lbl);
5100           emitcode ("mov", "b,a");
5101         }
5102     }
5103
5104   if (AOP_TYPE(left) == AOP_LIT)
5105     {
5106       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5107
5108       if (!lUnsigned && val < 0)
5109         emitcode ("mov", "a,#0x%02x", -val);
5110       else
5111         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5112     }
5113   else /* ! literal */
5114     {
5115       MOVA (aopGet (left, 0, FALSE, FALSE));
5116
5117       if (!lUnsigned)
5118         {
5119           lbl = newiTempLabel (NULL);
5120           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5121           emitcode ("cpl", "F0"); /* complement sign flag */
5122           emitcode ("cpl", "a"); /* 2's complement */
5123           emitcode ("inc", "a");
5124           emitLabel (lbl);
5125         }
5126     }
5127
5128   /* now the multiplication */
5129   emitcode ("mul", "ab");
5130   if (runtimeSign || compiletimeSign)
5131     {
5132       lbl = newiTempLabel (NULL);
5133       if (runtimeSign)
5134         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5135       emitcode ("cpl", "a"); /* lsb 2's complement */
5136       if (size != 2)
5137         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5138       else
5139         {
5140           emitcode ("add", "a,#1"); /* this sets carry flag */
5141           emitcode ("xch", "a,b");
5142           emitcode ("cpl", "a"); /* msb 2's complement */
5143           emitcode ("addc", "a,#0");
5144           emitcode ("xch", "a,b");
5145         }
5146       emitLabel (lbl);
5147     }
5148   aopPut (result, "a", 0);
5149   if (size == 2)
5150     aopPut (result, "b", 1);
5151
5152   popB (pushedB);
5153 }
5154
5155 /*-----------------------------------------------------------------*/
5156 /* genMult - generates code for multiplication                     */
5157 /*-----------------------------------------------------------------*/
5158 static void
5159 genMult (iCode * ic)
5160 {
5161   operand *left = IC_LEFT (ic);
5162   operand *right = IC_RIGHT (ic);
5163   operand *result = IC_RESULT (ic);
5164
5165   D (emitcode (";", "genMult"));
5166
5167   /* assign the asmops */
5168   aopOp (left, ic, FALSE);
5169   aopOp (right, ic, FALSE);
5170   aopOp (result, ic, TRUE);
5171
5172   /* special cases first */
5173   /* both are bits */
5174   if (AOP_TYPE (left) == AOP_CRY &&
5175       AOP_TYPE (right) == AOP_CRY)
5176     {
5177       genMultbits (left, right, result);
5178       goto release;
5179     }
5180
5181   /* if both are of size == 1 */
5182 #if 0 // one of them can be a sloc shared with the result
5183     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5184 #else
5185   if (getSize(operandType(left)) == 1 &&
5186       getSize(operandType(right)) == 1)
5187 #endif
5188     {
5189       genMultOneByte (left, right, result);
5190       goto release;
5191     }
5192
5193   /* should have been converted to function call */
5194     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5195              getSize(OP_SYMBOL(right)->type));
5196   assert (0);
5197
5198 release:
5199   freeAsmop (result, NULL, ic, TRUE);
5200   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5201   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5202 }
5203
5204 /*-----------------------------------------------------------------*/
5205 /* genDivbits :- division of bits                                  */
5206 /*-----------------------------------------------------------------*/
5207 static void
5208 genDivbits (operand * left,
5209             operand * right,
5210             operand * result)
5211 {
5212   char *l;
5213   bool pushedB;
5214
5215   D(emitcode (";     genDivbits",""));
5216
5217   pushedB = pushB ();
5218
5219   /* the result must be bit */
5220   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5221   l = aopGet (left, 0, FALSE, FALSE);
5222
5223   MOVA (l);
5224
5225   emitcode ("div", "ab");
5226   emitcode ("rrc", "a");
5227
5228   popB (pushedB);
5229
5230   aopPut (result, "c", 0);
5231 }
5232
5233 /*-----------------------------------------------------------------*/
5234 /* genDivOneByte : 8 bit division                                  */
5235 /*-----------------------------------------------------------------*/
5236 static void
5237 genDivOneByte (operand * left,
5238                operand * right,
5239                operand * result)
5240 {
5241   bool lUnsigned, rUnsigned, pushedB;
5242   bool runtimeSign, compiletimeSign;
5243   bool accuse = FALSE;
5244   bool pushedA = FALSE;
5245   symbol *lbl;
5246   int size, offset;
5247
5248   D(emitcode (";     genDivOneByte",""));
5249
5250   /* Why is it necessary that genDivOneByte() can return an int result?
5251      Have a look at:
5252
5253         volatile unsigned char uc;
5254         volatile signed char sc1, sc2;
5255         volatile int i;
5256
5257         uc  = 255;
5258         sc1 = -1;
5259         i = uc / sc1;
5260
5261      Or:
5262
5263         sc1 = -128;
5264         sc2 = -1;
5265         i = sc1 / sc2;
5266
5267      In all cases a one byte result would overflow, the following cast to int
5268      would return the wrong result.
5269
5270      Two possible solution:
5271         a) cast operands to int, if ((unsigned) / (signed)) or
5272            ((signed) / (signed))
5273         b) return an 16 bit signed int; this is what we're doing here!
5274   */
5275
5276   size = AOP_SIZE (result) - 1;
5277   offset = 1;
5278   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5279   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5280
5281   pushedB = pushB ();
5282
5283   /* signed or unsigned */
5284   if (lUnsigned && rUnsigned)
5285     {
5286       /* unsigned is easy */
5287       MOVB (aopGet (right, 0, FALSE, FALSE));
5288       MOVA (aopGet (left, 0, FALSE, FALSE));
5289       emitcode ("div", "ab");
5290       aopPut (result, "a", 0);
5291       while (size--)
5292         aopPut (result, zero, offset++);
5293
5294       popB (pushedB);
5295       return;
5296     }
5297
5298   /* signed is a little bit more difficult */
5299
5300   /* now sign adjust for both left & right */
5301
5302   /* let's see what's needed: */
5303   /* apply negative sign during runtime */
5304   runtimeSign = FALSE;
5305   /* negative sign from literals */
5306   compiletimeSign = FALSE;
5307
5308   if (!lUnsigned)
5309     {
5310       if (AOP_TYPE(left) == AOP_LIT)
5311         {
5312           /* signed literal */
5313           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5314           if (val < 0)
5315             compiletimeSign = TRUE;
5316         }
5317       else
5318         /* signed but not literal */
5319         runtimeSign = TRUE;
5320     }
5321
5322   if (!rUnsigned)
5323     {
5324       if (AOP_TYPE(right) == AOP_LIT)
5325         {
5326           /* signed literal */
5327           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5328           if (val < 0)
5329             compiletimeSign ^= TRUE;
5330         }
5331       else
5332         /* signed but not literal */
5333         runtimeSign = TRUE;
5334     }
5335
5336   /* initialize F0, which stores the runtime sign */
5337   if (runtimeSign)
5338     {
5339       if (compiletimeSign)
5340         emitcode ("setb", "F0"); /* set sign flag */
5341       else
5342         emitcode ("clr", "F0"); /* reset sign flag */
5343     }
5344
5345   /* save the signs of the operands */
5346   if (AOP_TYPE(right) == AOP_LIT)
5347     {
5348       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5349
5350       if (!rUnsigned && val < 0)
5351         emitcode ("mov", "b,#0x%02x", -val);
5352       else
5353         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5354     }
5355   else /* ! literal */
5356     {
5357       if (rUnsigned)
5358         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5359       else
5360         {
5361           MOVA (aopGet (right, 0, FALSE, FALSE));
5362           lbl = newiTempLabel (NULL);
5363           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5364           emitcode ("cpl", "F0"); /* complement sign flag */
5365           emitcode ("cpl", "a");  /* 2's complement */
5366           emitcode ("inc", "a");
5367           emitLabel (lbl);
5368           emitcode ("mov", "b,a");
5369         }
5370     }
5371
5372   if (AOP_TYPE(left) == AOP_LIT)
5373     {
5374       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5375
5376       if (!lUnsigned && val < 0)
5377         emitcode ("mov", "a,#0x%02x", -val);
5378       else
5379         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5380     }
5381   else /* ! literal */
5382     {
5383       MOVA (aopGet (left, 0, FALSE, FALSE));
5384
5385       if (!lUnsigned)
5386         {
5387           lbl = newiTempLabel (NULL);
5388           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5389           emitcode ("cpl", "F0"); /* complement sign flag */
5390           emitcode ("cpl", "a");  /* 2's complement */
5391           emitcode ("inc", "a");
5392           emitLabel (lbl);
5393         }
5394     }
5395
5396   /* now the division */
5397   emitcode ("div", "ab");
5398
5399   if (runtimeSign || compiletimeSign)
5400     {
5401       lbl = newiTempLabel (NULL);
5402       if (runtimeSign)
5403         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5404       emitcode ("cpl", "a"); /* lsb 2's complement */
5405       emitcode ("inc", "a");
5406       emitLabel (lbl);
5407
5408       accuse = aopPut (result, "a", 0);
5409       if (size > 0)
5410         {
5411           /* msb is 0x00 or 0xff depending on the sign */
5412           if (runtimeSign)
5413             {
5414               if (accuse)
5415                 {
5416                   emitcode ("push", "acc");
5417                   pushedA = TRUE;
5418                 }
5419               emitcode ("mov", "c,F0");
5420               emitcode ("subb", "a,acc");
5421               while (size--)
5422                 aopPut (result, "a", offset++);
5423             }
5424           else /* compiletimeSign */
5425             {
5426               if (aopPutUsesAcc (result, "#0xFF", offset))
5427                 {
5428                   emitcode ("push", "acc");
5429                   pushedA = TRUE;
5430                 }
5431               while (size--)
5432                 aopPut (result, "#0xff", offset++);
5433             }
5434         }
5435     }
5436   else
5437     {
5438       aopPut (result, "a", 0);
5439       while (size--)
5440         aopPut (result, zero, offset++);
5441     }
5442
5443   if (pushedA)
5444     emitcode ("pop", "acc");
5445   popB (pushedB);
5446 }
5447
5448 /*-----------------------------------------------------------------*/
5449 /* genDiv - generates code for division                            */
5450 /*-----------------------------------------------------------------*/
5451 static void
5452 genDiv (iCode * ic)
5453 {
5454   operand *left = IC_LEFT (ic);
5455   operand *right = IC_RIGHT (ic);
5456   operand *result = IC_RESULT (ic);
5457
5458   D (emitcode (";", "genDiv"));
5459
5460   /* assign the amsops */
5461   aopOp (left, ic, FALSE);
5462   aopOp (right, ic, FALSE);
5463   aopOp (result, ic, TRUE);
5464
5465   /* special cases first */
5466   /* both are bits */
5467   if (AOP_TYPE (left) == AOP_CRY &&
5468       AOP_TYPE (right) == AOP_CRY)
5469     {
5470       genDivbits (left, right, result);
5471       goto release;
5472     }
5473
5474   /* if both are of size == 1 */
5475   if (AOP_SIZE (left) == 1 &&
5476       AOP_SIZE (right) == 1)
5477     {
5478       genDivOneByte (left, right, result);
5479       goto release;
5480     }
5481
5482   /* should have been converted to function call */
5483   assert (0);
5484 release:
5485   freeAsmop (result, NULL, ic, TRUE);
5486   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5487   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5488 }
5489
5490 /*-----------------------------------------------------------------*/
5491 /* genModbits :- modulus of bits                                   */
5492 /*-----------------------------------------------------------------*/
5493 static void
5494 genModbits (operand * left,
5495             operand * right,
5496             operand * result)
5497 {
5498   char *l;
5499   bool pushedB;
5500
5501   D (emitcode (";", "genModbits"));
5502
5503   pushedB = pushB ();
5504
5505   /* the result must be bit */
5506   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5507   l = aopGet (left, 0, FALSE, FALSE);
5508
5509   MOVA (l);
5510
5511   emitcode ("div", "ab");
5512   emitcode ("mov", "a,b");
5513   emitcode ("rrc", "a");
5514
5515   popB (pushedB);
5516
5517   aopPut (result, "c", 0);
5518 }
5519
5520 /*-----------------------------------------------------------------*/
5521 /* genModOneByte : 8 bit modulus                                   */
5522 /*-----------------------------------------------------------------*/
5523 static void
5524 genModOneByte (operand * left,
5525                operand * right,
5526                operand * result)
5527 {
5528   bool lUnsigned, rUnsigned, pushedB;
5529   bool runtimeSign, compiletimeSign;
5530   symbol *lbl;
5531   int size, offset;
5532
5533   D (emitcode (";", "genModOneByte"));
5534
5535   size = AOP_SIZE (result) - 1;
5536   offset = 1;
5537   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5538   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5539
5540   /* if right is a literal, check it for 2^n */
5541   if (AOP_TYPE(right) == AOP_LIT)
5542     {
5543       unsigned char val = abs((int) operandLitValue(right));
5544       symbol *lbl2 = NULL;
5545
5546       switch (val)
5547         {
5548           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5549           case 2:
5550           case 4:
5551           case 8:
5552           case 16:
5553           case 32:
5554           case 64:
5555           case 128:
5556             if (lUnsigned)
5557               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5558                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5559               /* because iCode should have been changed to genAnd  */
5560               /* see file "SDCCopt.c", function "convertToFcall()" */
5561
5562             MOVA (aopGet (left, 0, FALSE, FALSE));
5563             emitcode ("mov", "c,acc.7");
5564             emitcode ("anl", "a,#0x%02x", val - 1);
5565             lbl = newiTempLabel (NULL);
5566             emitcode ("jz", "%05d$", (lbl->key + 100));
5567             emitcode ("jnc", "%05d$", (lbl->key + 100));
5568             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5569             if (size)
5570               {
5571                 int size2 = size;
5572                 int offs2 = offset;
5573
5574                 aopPut (result, "a", 0);
5575                 while (size2--)
5576                   aopPut (result, "#0xff", offs2++);
5577                 lbl2 = newiTempLabel (NULL);
5578                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5579               }
5580             emitLabel (lbl);
5581             aopPut (result, "a", 0);
5582             while (size--)
5583               aopPut (result, zero, offset++);
5584             if (lbl2)
5585               {
5586                 emitLabel (lbl2);
5587               }
5588             return;
5589
5590           default:
5591             break;
5592         }
5593     }
5594
5595   pushedB = pushB ();
5596
5597   /* signed or unsigned */
5598   if (lUnsigned && rUnsigned)
5599     {
5600       /* unsigned is easy */
5601       MOVB (aopGet (right, 0, FALSE, FALSE));
5602       MOVA (aopGet (left, 0, FALSE, FALSE));
5603       emitcode ("div", "ab");
5604       aopPut (result, "b", 0);
5605       while (size--)
5606         aopPut (result, zero, offset++);
5607
5608       popB (pushedB);
5609       return;
5610     }
5611
5612   /* signed is a little bit more difficult */
5613
5614   /* now sign adjust for both left & right */
5615
5616   /* modulus: sign of the right operand has no influence on the result! */
5617   if (AOP_TYPE(right) == AOP_LIT)
5618     {
5619       signed char val = (char) operandLitValue(right);
5620
5621       if (!rUnsigned && val < 0)
5622         emitcode ("mov", "b,#0x%02x", -val);
5623       else
5624         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5625     }
5626   else /* not literal */
5627     {
5628       if (rUnsigned)
5629         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5630       else
5631         {
5632           MOVA (aopGet (right, 0, FALSE, FALSE));
5633           lbl = newiTempLabel (NULL);
5634           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5635           emitcode ("cpl", "a"); /* 2's complement */
5636           emitcode ("inc", "a");
5637           emitLabel (lbl);
5638           emitcode ("mov", "b,a");
5639         }
5640     }
5641
5642   /* let's see what's needed: */
5643   /* apply negative sign during runtime */
5644   runtimeSign = FALSE;
5645   /* negative sign from literals */
5646   compiletimeSign = FALSE;
5647
5648   /* sign adjust left side */
5649   if (AOP_TYPE(left) == AOP_LIT)
5650     {
5651       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5652
5653       if (!lUnsigned && val < 0)
5654         {
5655           compiletimeSign = TRUE; /* set sign flag */
5656           emitcode ("mov", "a,#0x%02x", -val);
5657         }
5658       else
5659         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5660     }
5661   else /* ! literal */
5662     {
5663       MOVA (aopGet (left, 0, FALSE, FALSE));
5664
5665       if (!lUnsigned)
5666         {
5667           runtimeSign = TRUE;
5668           emitcode ("clr", "F0"); /* clear sign flag */
5669
5670           lbl = newiTempLabel (NULL);
5671           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5672           emitcode ("setb", "F0"); /* set sign flag */
5673           emitcode ("cpl", "a");   /* 2's complement */
5674           emitcode ("inc", "a");
5675           emitLabel (lbl);
5676         }
5677     }
5678
5679   /* now the modulus */
5680   emitcode ("div", "ab");
5681
5682   if (runtimeSign || compiletimeSign)
5683     {
5684       emitcode ("mov", "a,b");
5685       lbl = newiTempLabel (NULL);
5686       if (runtimeSign)
5687         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5688       emitcode ("cpl", "a"); /* 2's complement */
5689       emitcode ("inc", "a");
5690       emitLabel (lbl);
5691
5692       aopPut (result, "a", 0);
5693       if (size > 0)
5694         {
5695           /* msb is 0x00 or 0xff depending on the sign */
5696           if (runtimeSign)
5697             {
5698               emitcode ("mov", "c,F0");
5699               emitcode ("subb", "a,acc");
5700               while (size--)
5701                 aopPut (result, "a", offset++);
5702             }
5703           else /* compiletimeSign */
5704             while (size--)
5705               aopPut (result, "#0xff", offset++);
5706         }
5707     }
5708   else
5709     {
5710       aopPut (result, "b", 0);
5711       while (size--)
5712         aopPut (result, zero, offset++);
5713     }
5714
5715   popB (pushedB);
5716 }
5717
5718 /*-----------------------------------------------------------------*/
5719 /* genMod - generates code for division                            */
5720 /*-----------------------------------------------------------------*/
5721 static void
5722 genMod (iCode * ic)
5723 {
5724   operand *left = IC_LEFT (ic);
5725   operand *right = IC_RIGHT (ic);
5726   operand *result = IC_RESULT (ic);
5727
5728   D (emitcode (";", "genMod"));
5729
5730   /* assign the asmops */
5731   aopOp (left, ic, FALSE);
5732   aopOp (right, ic, FALSE);
5733   aopOp (result, ic, TRUE);
5734
5735   /* special cases first */
5736   /* both are bits */
5737   if (AOP_TYPE (left) == AOP_CRY &&
5738       AOP_TYPE (right) == AOP_CRY)
5739     {
5740       genModbits (left, right, result);
5741       goto release;
5742     }
5743
5744   /* if both are of size == 1 */
5745   if (AOP_SIZE (left) == 1 &&
5746       AOP_SIZE (right) == 1)
5747     {
5748       genModOneByte (left, right, result);
5749       goto release;
5750     }
5751
5752   /* should have been converted to function call */
5753   assert (0);
5754
5755 release:
5756   freeAsmop (result, NULL, ic, TRUE);
5757   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5758   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5759 }
5760
5761 /*-----------------------------------------------------------------*/
5762 /* genIfxJump :- will create a jump depending on the ifx           */
5763 /*-----------------------------------------------------------------*/
5764 static void
5765 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5766 {
5767   symbol *jlbl;
5768   symbol *tlbl = newiTempLabel (NULL);
5769   char *inst;
5770
5771   D (emitcode (";", "genIfxJump"));
5772
5773   /* if true label then we jump if condition
5774      supplied is true */
5775   if (IC_TRUE (ic))
5776     {
5777       jlbl = IC_TRUE (ic);
5778       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5779                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5780     }
5781   else
5782     {
5783       /* false label is present */
5784       jlbl = IC_FALSE (ic);
5785       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5786                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5787     }
5788   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5789     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5790   else
5791     emitcode (inst, "%05d$", tlbl->key + 100);
5792   freeForBranchAsmop (result);
5793   freeForBranchAsmop (right);
5794   freeForBranchAsmop (left);
5795   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5796   emitLabel (tlbl);
5797
5798   /* mark the icode as generated */
5799   ic->generated = 1;
5800 }
5801
5802 /*-----------------------------------------------------------------*/
5803 /* genCmp :- greater or less than comparison                       */
5804 /*-----------------------------------------------------------------*/
5805 static void
5806 genCmp (operand * left, operand * right,
5807         operand * result, iCode * ifx, int sign, iCode *ic)
5808 {
5809   int size, offset = 0;
5810   unsigned long lit = 0L;
5811   bool rightInB;
5812
5813   D (emitcode (";", "genCmp"));
5814
5815   /* if left & right are bit variables */
5816   if (AOP_TYPE (left) == AOP_CRY &&
5817       AOP_TYPE (right) == AOP_CRY)
5818     {
5819       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5820       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5821     }
5822   else
5823     {
5824       /* subtract right from left if at the
5825          end the carry flag is set then we know that
5826          left is greater than right */
5827       size = max (AOP_SIZE (left), AOP_SIZE (right));
5828
5829       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5830       if ((size == 1) && !sign &&
5831           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5832         {
5833           symbol *lbl = newiTempLabel (NULL);
5834           emitcode ("cjne", "%s,%s,%05d$",
5835                     aopGet (left, offset, FALSE, FALSE),
5836                     aopGet (right, offset, FALSE, FALSE),
5837                     lbl->key + 100);
5838           emitLabel (lbl);
5839         }
5840       else
5841         {
5842           if (AOP_TYPE (right) == AOP_LIT)
5843             {
5844               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5845               /* optimize if(x < 0) or if(x >= 0) */
5846               if (lit == 0L)
5847                 {
5848                   if (!sign)
5849                     {
5850                       CLRC;
5851                     }
5852                   else
5853                     {
5854                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5855                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5856                         {
5857                           genIfxJump (ifx, "acc.7", left, right, result);
5858                           freeAsmop (right, NULL, ic, TRUE);
5859                           freeAsmop (left, NULL, ic, TRUE);
5860
5861                           return;
5862                         }
5863                       else
5864                         {
5865                           emitcode ("rlc", "a");
5866                         }
5867                     }
5868                   goto release;
5869                 }
5870               else
5871                 {//nonzero literal
5872                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5873                   while (size && (bytelit == 0))
5874                     {
5875                       offset++;
5876                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5877                       size--;
5878                     }
5879                   CLRC;
5880                   while (size--)
5881                     {
5882                       MOVA (aopGet (left, offset, FALSE, FALSE));
5883                       if (sign && size == 0)
5884                         {
5885                           emitcode ("xrl", "a,#0x80");
5886                           emitcode ("subb", "a,#0x%02x",
5887                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5888                         }
5889                       else
5890                         {
5891                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5892                         }
5893                       offset++;
5894                     }
5895                   goto release;
5896                 }
5897             }
5898           CLRC;
5899           while (size--)
5900             {
5901               bool pushedB = FALSE;
5902               rightInB = aopGetUsesAcc(right, offset);
5903               if (rightInB)
5904                 {
5905                   pushedB = pushB ();
5906                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5907                 }
5908               MOVA (aopGet (left, offset, FALSE, FALSE));
5909               if (sign && size == 0)
5910                 {
5911                   emitcode ("xrl", "a,#0x80");
5912                   if (!rightInB)
5913                     {
5914                       pushedB = pushB ();
5915                       rightInB++;
5916                       MOVB (aopGet (right, offset, FALSE, FALSE));
5917                     }
5918                   emitcode ("xrl", "b,#0x80");
5919                   emitcode ("subb", "a,b");
5920                 }
5921               else
5922                 {
5923                   if (rightInB)
5924                     emitcode ("subb", "a,b");
5925                   else
5926                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5927                 }
5928               if (rightInB)
5929                 popB (pushedB);
5930               offset++;
5931             }
5932         }
5933     }
5934
5935 release:
5936   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5937   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5938   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5939     {
5940       outBitC (result);
5941     }
5942   else
5943     {
5944       /* if the result is used in the next
5945          ifx conditional branch then generate
5946          code a little differently */
5947       if (ifx)
5948         {
5949           genIfxJump (ifx, "c", NULL, NULL, result);
5950         }
5951       else
5952         {
5953           outBitC (result);
5954         }
5955       /* leave the result in acc */
5956     }
5957 }
5958
5959 /*-----------------------------------------------------------------*/
5960 /* genCmpGt :- greater than comparison                             */
5961 /*-----------------------------------------------------------------*/
5962 static void
5963 genCmpGt (iCode * ic, iCode * ifx)
5964 {
5965   operand *left, *right, *result;
5966   sym_link *letype, *retype;
5967   int sign;
5968
5969   D (emitcode (";", "genCmpGt"));
5970
5971   left = IC_LEFT (ic);
5972   right = IC_RIGHT (ic);
5973   result = IC_RESULT (ic);
5974
5975   letype = getSpec (operandType (left));
5976   retype = getSpec (operandType (right));
5977   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5978            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5979   /* assign the amsops */
5980   aopOp (result, ic, TRUE);
5981   aopOp (left, ic, FALSE);
5982   aopOp (right, ic, FALSE);
5983
5984   genCmp (right, left, result, ifx, sign, ic);
5985
5986   freeAsmop (result, NULL, ic, TRUE);
5987 }
5988
5989 /*-----------------------------------------------------------------*/
5990 /* genCmpLt - less than comparisons                                */
5991 /*-----------------------------------------------------------------*/
5992 static void
5993 genCmpLt (iCode * ic, iCode * ifx)
5994 {
5995   operand *left, *right, *result;
5996   sym_link *letype, *retype;
5997   int sign;
5998
5999   D (emitcode (";", "genCmpLt"));
6000
6001   left = IC_LEFT (ic);
6002   right = IC_RIGHT (ic);
6003   result = IC_RESULT (ic);
6004
6005   letype = getSpec (operandType (left));
6006   retype = getSpec (operandType (right));
6007   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6008            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6009   /* assign the amsops */
6010   aopOp (result, ic, TRUE);
6011   aopOp (left, ic, FALSE);
6012   aopOp (right, ic, FALSE);
6013
6014   genCmp (left, right, result, ifx, sign, ic);
6015
6016   freeAsmop (result, NULL, ic, TRUE);
6017 }
6018
6019 /*-----------------------------------------------------------------*/
6020 /* gencjneshort - compare and jump if not equal                    */
6021 /*-----------------------------------------------------------------*/
6022 static void
6023 gencjneshort (operand * left, operand * right, symbol * lbl)
6024 {
6025   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6026   int offset = 0;
6027   unsigned long lit = 0L;
6028
6029   D (emitcode (";", "gencjneshort"));
6030
6031   /* if the left side is a literal or
6032      if the right is in a pointer register and left
6033      is not */
6034   if ((AOP_TYPE (left) == AOP_LIT) ||
6035       (AOP_TYPE (left) == AOP_IMMD) ||
6036       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6037     {
6038       operand *t = right;
6039       right = left;
6040       left = t;
6041     }
6042
6043   if (AOP_TYPE (right) == AOP_LIT)
6044     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6045
6046   /* if the right side is a literal then anything goes */
6047   if (AOP_TYPE (right) == AOP_LIT &&
6048       AOP_TYPE (left) != AOP_DIR  &&
6049       AOP_TYPE (left) != AOP_IMMD)
6050     {
6051       while (size--)
6052         {
6053           emitcode ("cjne", "%s,%s,%05d$",
6054                     aopGet (left, offset, FALSE, FALSE),
6055                     aopGet (right, offset, FALSE, FALSE),
6056                     lbl->key + 100);
6057           offset++;
6058         }
6059     }
6060
6061   /* if the right side is in a register or in direct space or
6062      if the left is a pointer register & right is not */
6063   else if (AOP_TYPE (right) == AOP_REG ||
6064            AOP_TYPE (right) == AOP_DIR ||
6065            AOP_TYPE (right) == AOP_LIT ||
6066            AOP_TYPE (right) == AOP_IMMD ||
6067            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6068            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6069     {
6070       while (size--)
6071         {
6072           MOVA (aopGet (left, offset, FALSE, FALSE));
6073           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6074               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6075             emitcode ("jnz", "%05d$", lbl->key + 100);
6076           else
6077             emitcode ("cjne", "a,%s,%05d$",
6078                       aopGet (right, offset, FALSE, TRUE),
6079                       lbl->key + 100);
6080           offset++;
6081         }
6082     }
6083   else
6084     {
6085       /* right is a pointer reg need both a & b */
6086       while (size--)
6087         {
6088           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6089           wassertl(!BINUSE, "B was in use");
6090           MOVB (aopGet (left, offset, FALSE, FALSE));
6091           MOVA (aopGet (right, offset, FALSE, FALSE));
6092           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6093           offset++;
6094         }
6095     }
6096 }
6097
6098 /*-----------------------------------------------------------------*/
6099 /* gencjne - compare and jump if not equal                         */
6100 /*-----------------------------------------------------------------*/
6101 static void
6102 gencjne (operand * left, operand * right, symbol * lbl)
6103 {
6104   symbol *tlbl = newiTempLabel (NULL);
6105
6106   D (emitcode (";", "gencjne"));
6107
6108   gencjneshort (left, right, lbl);
6109
6110   emitcode ("mov", "a,%s", one);
6111   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6112   emitLabel (lbl);
6113   emitcode ("clr", "a");
6114   emitLabel (tlbl);
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /* genCmpEq - generates code for equal to                          */
6119 /*-----------------------------------------------------------------*/
6120 static void
6121 genCmpEq (iCode * ic, iCode * ifx)
6122 {
6123   bool swappedLR = FALSE;
6124   operand *left, *right, *result;
6125
6126   D (emitcode (";", "genCmpEq"));
6127
6128   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6129   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6130   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6131
6132   /* if literal, literal on the right or
6133      if the right is in a pointer register and left
6134      is not */
6135   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6136       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6137     {
6138       operand *t = IC_RIGHT (ic);
6139       IC_RIGHT (ic) = IC_LEFT (ic);
6140       IC_LEFT (ic) = t;
6141       swappedLR = TRUE;
6142     }
6143
6144   if (ifx && !AOP_SIZE (result))
6145     {
6146       symbol *tlbl;
6147       /* if they are both bit variables */
6148       if (AOP_TYPE (left) == AOP_CRY &&
6149           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6150         {
6151           if (AOP_TYPE (right) == AOP_LIT)
6152             {
6153               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6154               if (lit == 0L)
6155                 {
6156                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6157                   emitcode ("cpl", "c");
6158                 }
6159               else if (lit == 1L)
6160                 {
6161                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6162                 }
6163               else
6164                 {
6165                   emitcode ("clr", "c");
6166                 }
6167               /* AOP_TYPE(right) == AOP_CRY */
6168             }
6169           else
6170             {
6171               symbol *lbl = newiTempLabel (NULL);
6172               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6173               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6174               emitcode ("cpl", "c");
6175               emitLabel (lbl);
6176             }
6177           /* if true label then we jump if condition
6178              supplied is true */
6179           tlbl = newiTempLabel (NULL);
6180           if (IC_TRUE (ifx))
6181             {
6182               emitcode ("jnc", "%05d$", tlbl->key + 100);
6183               freeForBranchAsmop (result);
6184               freeForBranchAsmop (right);
6185               freeForBranchAsmop (left);
6186               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6187             }
6188           else
6189             {
6190               emitcode ("jc", "%05d$", tlbl->key + 100);
6191               freeForBranchAsmop (result);
6192               freeForBranchAsmop (right);
6193               freeForBranchAsmop (left);
6194               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6195             }
6196           emitLabel (tlbl);
6197         }
6198       else
6199         {
6200           tlbl = newiTempLabel (NULL);
6201           gencjneshort (left, right, tlbl);
6202           if (IC_TRUE (ifx))
6203             {
6204               freeForBranchAsmop (result);
6205               freeForBranchAsmop (right);
6206               freeForBranchAsmop (left);
6207               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6208               emitLabel (tlbl);
6209             }
6210           else
6211             {
6212               symbol *lbl = newiTempLabel (NULL);
6213               emitcode ("sjmp", "%05d$", lbl->key + 100);
6214               emitLabel (tlbl);
6215               freeForBranchAsmop (result);
6216               freeForBranchAsmop (right);
6217               freeForBranchAsmop (left);
6218               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6219               emitLabel (lbl);
6220             }
6221         }
6222       /* mark the icode as generated */
6223       ifx->generated = 1;
6224       goto release;
6225     }
6226
6227   /* if they are both bit variables */
6228   if (AOP_TYPE (left) == AOP_CRY &&
6229       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6230     {
6231       if (AOP_TYPE (right) == AOP_LIT)
6232         {
6233           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6234           if (lit == 0L)
6235             {
6236               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6237               emitcode ("cpl", "c");
6238             }
6239           else if (lit == 1L)
6240             {
6241               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6242             }
6243           else
6244             {
6245               emitcode ("clr", "c");
6246             }
6247           /* AOP_TYPE(right) == AOP_CRY */
6248         }
6249       else
6250         {
6251           symbol *lbl = newiTempLabel (NULL);
6252           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6253           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6254           emitcode ("cpl", "c");
6255           emitLabel (lbl);
6256         }
6257       /* c = 1 if egal */
6258       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6259         {
6260           outBitC (result);
6261           goto release;
6262         }
6263       if (ifx)
6264         {
6265           genIfxJump (ifx, "c", left, right, result);
6266           goto release;
6267         }
6268       /* if the result is used in an arithmetic operation
6269          then put the result in place */
6270       outBitC (result);
6271     }
6272   else
6273     {
6274       gencjne (left, right, newiTempLabel (NULL));
6275       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6276         {
6277           aopPut (result, "a", 0);
6278           goto release;
6279         }
6280       if (ifx)
6281         {
6282           genIfxJump (ifx, "a", left, right, result);
6283           goto release;
6284         }
6285       /* if the result is used in an arithmetic operation
6286          then put the result in place */
6287       if (AOP_TYPE (result) != AOP_CRY)
6288         outAcc (result);
6289       /* leave the result in acc */
6290     }
6291
6292 release:
6293   freeAsmop (result, NULL, ic, TRUE);
6294   if (!swappedLR)
6295     {
6296       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6297       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6298     }
6299   else
6300     {
6301       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6302       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6303     }
6304 }
6305
6306 /*-----------------------------------------------------------------*/
6307 /* ifxForOp - returns the icode containing the ifx for operand     */
6308 /*-----------------------------------------------------------------*/
6309 static iCode *
6310 ifxForOp (operand * op, iCode * ic)
6311 {
6312   /* if true symbol then needs to be assigned */
6313   if (IS_TRUE_SYMOP (op))
6314     return NULL;
6315
6316   /* if this has register type condition and
6317      the next instruction is ifx with the same operand
6318      and live to of the operand is upto the ifx only then */
6319   if (ic->next &&
6320       ic->next->op == IFX &&
6321       IC_COND (ic->next)->key == op->key &&
6322       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6323     return ic->next;
6324
6325   return NULL;
6326 }
6327
6328 /*-----------------------------------------------------------------*/
6329 /* hasInc - operand is incremented before any other use            */
6330 /*-----------------------------------------------------------------*/
6331 static iCode *
6332 hasInc (operand *op, iCode *ic, int osize)
6333 {
6334   sym_link *type = operandType(op);
6335   sym_link *retype = getSpec (type);
6336   iCode *lic = ic->next;
6337   int isize ;
6338
6339   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6340   if (!IS_SYMOP(op)) return NULL;
6341
6342   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6343   if (IS_AGGREGATE(type->next)) return NULL;
6344   if (osize != (isize = getSize(type->next))) return NULL;
6345
6346   while (lic) {
6347     /* if operand of the form op = op + <sizeof *op> */
6348     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6349         isOperandEqual(IC_RESULT(lic),op) &&
6350         isOperandLiteral(IC_RIGHT(lic)) &&
6351         operandLitValue(IC_RIGHT(lic)) == isize) {
6352       return lic;
6353     }
6354     /* if the operand used or deffed */
6355     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6356       return NULL;
6357     }
6358     /* if GOTO or IFX */
6359     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6360     lic = lic->next;
6361   }
6362   return NULL;
6363 }
6364
6365 /*-----------------------------------------------------------------*/
6366 /* genAndOp - for && operation                                     */
6367 /*-----------------------------------------------------------------*/
6368 static void
6369 genAndOp (iCode * ic)
6370 {
6371   operand *left, *right, *result;
6372   symbol *tlbl;
6373
6374   D (emitcode (";", "genAndOp"));
6375
6376   /* note here that && operations that are in an
6377      if statement are taken away by backPatchLabels
6378      only those used in arthmetic operations remain */
6379   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6380   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6381   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6382
6383   /* if both are bit variables */
6384   if (AOP_TYPE (left) == AOP_CRY &&
6385       AOP_TYPE (right) == AOP_CRY)
6386     {
6387       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6388       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6389       outBitC (result);
6390     }
6391   else
6392     {
6393       tlbl = newiTempLabel (NULL);
6394       toBoolean (left);
6395       emitcode ("jz", "%05d$", tlbl->key + 100);
6396       toBoolean (right);
6397       emitLabel (tlbl);
6398       outBitAcc (result);
6399     }
6400
6401   freeAsmop (result, NULL, ic, TRUE);
6402   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6403   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6404 }
6405
6406
6407 /*-----------------------------------------------------------------*/
6408 /* genOrOp - for || operation                                      */
6409 /*-----------------------------------------------------------------*/
6410 static void
6411 genOrOp (iCode * ic)
6412 {
6413   operand *left, *right, *result;
6414   symbol *tlbl;
6415
6416   D (emitcode (";", "genOrOp"));
6417
6418   /* note here that || operations that are in an
6419      if statement are taken away by backPatchLabels
6420      only those used in arthmetic operations remain */
6421   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6422   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6423   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6424
6425   /* if both are bit variables */
6426   if (AOP_TYPE (left) == AOP_CRY &&
6427       AOP_TYPE (right) == AOP_CRY)
6428     {
6429       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6430       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6431       outBitC (result);
6432     }
6433   else
6434     {
6435       tlbl = newiTempLabel (NULL);
6436       toBoolean (left);
6437       emitcode ("jnz", "%05d$", tlbl->key + 100);
6438       toBoolean (right);
6439       emitLabel (tlbl);
6440       outBitAcc (result);
6441     }
6442
6443   freeAsmop (result, NULL, ic, TRUE);
6444   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6445   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6446 }
6447
6448 /*-----------------------------------------------------------------*/
6449 /* isLiteralBit - test if lit == 2^n                               */
6450 /*-----------------------------------------------------------------*/
6451 static int
6452 isLiteralBit (unsigned long lit)
6453 {
6454   unsigned long pw[32] =
6455   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6456    0x100L, 0x200L, 0x400L, 0x800L,
6457    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6458    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6459    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6460    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6461    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6462   int idx;
6463
6464   for (idx = 0; idx < 32; idx++)
6465     if (lit == pw[idx])
6466       return idx + 1;
6467   return 0;
6468 }
6469
6470 /*-----------------------------------------------------------------*/
6471 /* continueIfTrue -                                                */
6472 /*-----------------------------------------------------------------*/
6473 static void
6474 continueIfTrue (iCode * ic)
6475 {
6476   if (IC_TRUE (ic))
6477     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6478   ic->generated = 1;
6479 }
6480
6481 /*-----------------------------------------------------------------*/
6482 /* jmpIfTrue -                                                     */
6483 /*-----------------------------------------------------------------*/
6484 static void
6485 jumpIfTrue (iCode * ic)
6486 {
6487   if (!IC_TRUE (ic))
6488     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6489   ic->generated = 1;
6490 }
6491
6492 /*-----------------------------------------------------------------*/
6493 /* jmpTrueOrFalse -                                                */
6494 /*-----------------------------------------------------------------*/
6495 static void
6496 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6497 {
6498   // ugly but optimized by peephole
6499   if (IC_TRUE (ic))
6500     {
6501       symbol *nlbl = newiTempLabel (NULL);
6502       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6503       emitLabel (tlbl);
6504       freeForBranchAsmop (result);
6505       freeForBranchAsmop (right);
6506       freeForBranchAsmop (left);
6507       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6508       emitLabel (nlbl);
6509     }
6510   else
6511     {
6512       freeForBranchAsmop (result);
6513       freeForBranchAsmop (right);
6514       freeForBranchAsmop (left);
6515       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6516       emitLabel (tlbl);
6517     }
6518   ic->generated = 1;
6519 }
6520
6521 /*-----------------------------------------------------------------*/
6522 /* genAnd  - code for and                                          */
6523 /*-----------------------------------------------------------------*/
6524 static void
6525 genAnd (iCode * ic, iCode * ifx)
6526 {
6527   operand *left, *right, *result;
6528   int size, offset = 0;
6529   unsigned long lit = 0L;
6530   int bytelit = 0;
6531   char buffer[10];
6532
6533   D (emitcode (";", "genAnd"));
6534
6535   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6536   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6537   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6538
6539 #ifdef DEBUG_TYPE
6540   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6541             AOP_TYPE (result),
6542             AOP_TYPE (left), AOP_TYPE (right));
6543   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6544             AOP_SIZE (result),
6545             AOP_SIZE (left), AOP_SIZE (right));
6546 #endif
6547
6548   /* if left is a literal & right is not then exchange them */
6549   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6550       AOP_NEEDSACC (left))
6551     {
6552       operand *tmp = right;
6553       right = left;
6554       left = tmp;
6555     }
6556
6557   /* if result = right then exchange left and right */
6558   if (sameRegs (AOP (result), AOP (right)))
6559     {
6560       operand *tmp = right;
6561       right = left;
6562       left = tmp;
6563     }
6564
6565   /* if right is bit then exchange them */
6566   if (AOP_TYPE (right) == AOP_CRY &&
6567       AOP_TYPE (left) != AOP_CRY)
6568     {
6569       operand *tmp = right;
6570       right = left;
6571       left = tmp;
6572     }
6573   if (AOP_TYPE (right) == AOP_LIT)
6574     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6575
6576   size = AOP_SIZE (result);
6577
6578   // if(bit & yy)
6579   // result = bit & yy;
6580   if (AOP_TYPE (left) == AOP_CRY)
6581     {
6582       // c = bit & literal;
6583       if (AOP_TYPE (right) == AOP_LIT)
6584         {
6585           if (lit & 1)
6586             {
6587               if (size && sameRegs (AOP (result), AOP (left)))
6588                 // no change
6589                 goto release;
6590               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6591             }
6592           else
6593             {
6594               // bit(result) = 0;
6595               if (size && (AOP_TYPE (result) == AOP_CRY))
6596                 {
6597                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6598                   goto release;
6599                 }
6600               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6601                 {
6602                   jumpIfTrue (ifx);
6603                   goto release;
6604                 }
6605               emitcode ("clr", "c");
6606             }
6607         }
6608       else
6609         {
6610           if (AOP_TYPE (right) == AOP_CRY)
6611             {
6612               // c = bit & bit;
6613               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6614               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6615             }
6616           else
6617             {
6618               // c = bit & val;
6619               MOVA (aopGet (right, 0, FALSE, FALSE));
6620               // c = lsb
6621               emitcode ("rrc", "a");
6622               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6623             }
6624         }
6625       // bit = c
6626       // val = c
6627       if (size)
6628         outBitC (result);
6629       // if(bit & ...)
6630       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6631         genIfxJump (ifx, "c", left, right, result);
6632       goto release;
6633     }
6634
6635   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6636   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6637   if ((AOP_TYPE (right) == AOP_LIT) &&
6638       (AOP_TYPE (result) == AOP_CRY) &&
6639       (AOP_TYPE (left) != AOP_CRY))
6640     {
6641       int posbit = isLiteralBit (lit);
6642       /* left &  2^n */
6643       if (posbit)
6644         {
6645           posbit--;
6646           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6647           // bit = left & 2^n
6648           if (size)
6649             {
6650               switch (posbit & 0x07)
6651                 {
6652                   case 0: emitcode ("rrc", "a");
6653                           break;
6654                   case 7: emitcode ("rlc", "a");
6655                           break;
6656                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6657                           break;
6658                 }
6659             }
6660           // if(left &  2^n)
6661           else
6662             {
6663               if (ifx)
6664                 {
6665                   SNPRINTF (buffer, sizeof(buffer),
6666                             "acc.%d", posbit & 0x07);
6667                   genIfxJump (ifx, buffer, left, right, result);
6668                 }
6669               else
6670                 {// what is this case? just found it in ds390/gen.c
6671                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6672                 }
6673               goto release;
6674             }
6675         }
6676       else
6677         {
6678           symbol *tlbl = newiTempLabel (NULL);
6679           int sizel = AOP_SIZE (left);
6680           if (size)
6681             emitcode ("setb", "c");
6682           while (sizel--)
6683             {
6684               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6685                 {
6686                   MOVA (aopGet (left, offset, FALSE, FALSE));
6687                   // byte ==  2^n ?
6688                   if ((posbit = isLiteralBit (bytelit)) != 0)
6689                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6690                   else
6691                     {
6692                       if (bytelit != 0x0FFL)
6693                         emitcode ("anl", "a,%s",
6694                                   aopGet (right, offset, FALSE, TRUE));
6695                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6696                     }
6697                 }
6698               offset++;
6699             }
6700           // bit = left & literal
6701           if (size)
6702             {
6703               emitcode ("clr", "c");
6704               emitLabel (tlbl);
6705             }
6706           // if(left & literal)
6707           else
6708             {
6709               if (ifx)
6710                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6711               else
6712                 emitLabel (tlbl);
6713               goto release;
6714             }
6715         }
6716       outBitC (result);
6717       goto release;
6718     }
6719
6720   /* if left is same as result */
6721   if (sameRegs (AOP (result), AOP (left)))
6722     {
6723       for (; size--; offset++)
6724         {
6725           if (AOP_TYPE (right) == AOP_LIT)
6726             {
6727               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6728               if (bytelit == 0x0FF)
6729                 {
6730                   /* dummy read of volatile operand */
6731                   if (isOperandVolatile (left, FALSE))
6732                     MOVA (aopGet (left, offset, FALSE, FALSE));
6733                   else
6734                     continue;
6735                 }
6736               else if (bytelit == 0)
6737                 {
6738                   aopPut (result, zero, offset);
6739                 }
6740               else if (IS_AOP_PREG (result))
6741                 {
6742                   MOVA (aopGet (left, offset, FALSE, TRUE));
6743                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6744                   aopPut (result, "a", offset);
6745                 }
6746               else
6747                 emitcode ("anl", "%s,%s",
6748                           aopGet (left, offset, FALSE, TRUE),
6749                           aopGet (right, offset, FALSE, FALSE));
6750             }
6751           else
6752             {
6753               if (AOP_TYPE (left) == AOP_ACC)
6754                 {
6755                   if (offset)
6756                     emitcode("mov", "a,b");
6757                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6758                 }
6759               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6760                 {
6761                   MOVB (aopGet (left, offset, FALSE, FALSE));
6762                   MOVA (aopGet (right, offset, FALSE, FALSE));
6763                   emitcode ("anl", "a,b");
6764                   aopPut (result, "a", offset);
6765                 }
6766               else if (aopGetUsesAcc (left, offset))
6767                 {
6768                   MOVA (aopGet (left, offset, FALSE, FALSE));
6769                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6770                   aopPut (result, "a", offset);
6771                 }
6772               else
6773                 {
6774                   MOVA (aopGet (right, offset, FALSE, FALSE));
6775                   if (IS_AOP_PREG (result))
6776                     {
6777                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6778                       aopPut (result, "a", offset);
6779                     }
6780                   else
6781                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6782                 }
6783             }
6784         }
6785     }
6786   else
6787     {
6788       // left & result in different registers
6789       if (AOP_TYPE (result) == AOP_CRY)
6790         {
6791           // result = bit
6792           // if(size), result in bit
6793           // if(!size && ifx), conditional oper: if(left & right)
6794           symbol *tlbl = newiTempLabel (NULL);
6795           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6796           if (size)
6797             emitcode ("setb", "c");
6798           while (sizer--)
6799             {
6800               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6801                   && AOP_TYPE(left)==AOP_ACC)
6802                 {
6803                   if (offset)
6804                     emitcode("mov", "a,b");
6805                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6806                 }
6807               else if (AOP_TYPE(left)==AOP_ACC)
6808                 {
6809                   if (!offset)
6810                     {
6811                       bool pushedB = pushB ();
6812                       emitcode("mov", "b,a");
6813                       MOVA (aopGet (right, offset, FALSE, FALSE));
6814                       emitcode("anl", "a,b");
6815                       popB (pushedB);
6816                     }
6817                   else
6818                     {
6819                       MOVA (aopGet (right, offset, FALSE, FALSE));
6820                       emitcode("anl", "a,b");
6821                     }
6822                 }
6823               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6824                 {
6825                   MOVB (aopGet (left, offset, FALSE, FALSE));
6826                   MOVA (aopGet (right, offset, FALSE, FALSE));
6827                   emitcode ("anl", "a,b");
6828                 }
6829               else if (aopGetUsesAcc (left, offset))
6830                 {
6831                   MOVA (aopGet (left, offset, FALSE, FALSE));
6832                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6833                     }
6834               else
6835                 {
6836                   MOVA (aopGet (right, offset, FALSE, FALSE));
6837                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6838                 }
6839
6840               emitcode ("jnz", "%05d$", tlbl->key + 100);
6841               offset++;
6842             }
6843           if (size)
6844             {
6845               CLRC;
6846               emitLabel (tlbl);
6847               outBitC (result);
6848             }
6849           else if (ifx)
6850             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6851           else
6852             emitLabel (tlbl);
6853         }
6854       else
6855         {
6856           for (; (size--); offset++)
6857             {
6858               // normal case
6859               // result = left & right
6860               if (AOP_TYPE (right) == AOP_LIT)
6861                 {
6862                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6863                   if (bytelit == 0x0FF)
6864                     {
6865                       aopPut (result,
6866                               aopGet (left, offset, FALSE, FALSE),
6867                               offset);
6868                       continue;
6869                     }
6870                   else if (bytelit == 0)
6871                     {
6872                       /* dummy read of volatile operand */
6873                       if (isOperandVolatile (left, FALSE))
6874                         MOVA (aopGet (left, offset, FALSE, FALSE));
6875                       aopPut (result, zero, offset);
6876                       continue;
6877                     }
6878                   else if (AOP_TYPE (left) == AOP_ACC)
6879                     {
6880                       if (!offset)
6881                         {
6882                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6883                           aopPut (result, "a", offset);
6884                           continue;
6885                         }
6886                       else
6887                         {
6888                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6889                           aopPut (result, "b", offset);
6890                           continue;
6891                         }
6892                     }
6893                 }
6894               // faster than result <- left, anl result,right
6895               // and better if result is SFR
6896               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6897                   && AOP_TYPE(left)==AOP_ACC)
6898                 {
6899                   if (offset)
6900                     emitcode("mov", "a,b");
6901                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6902                 }
6903               else if (AOP_TYPE(left)==AOP_ACC)
6904                 {
6905                   if (!offset)
6906                     {
6907                       bool pushedB = pushB ();
6908                       emitcode("mov", "b,a");
6909                       MOVA (aopGet (right, offset, FALSE, FALSE));
6910                       emitcode("anl", "a,b");
6911                       popB (pushedB);
6912                     }
6913                   else
6914                     {
6915                       MOVA (aopGet (right, offset, FALSE, FALSE));
6916                       emitcode("anl", "a,b");
6917                     }
6918                 }
6919               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6920                 {
6921                   MOVB (aopGet (left, offset, FALSE, FALSE));
6922                   MOVA (aopGet (right, offset, FALSE, FALSE));
6923                   emitcode ("anl", "a,b");
6924                 }
6925               else if (aopGetUsesAcc (left, offset))
6926                 {
6927                   MOVA (aopGet (left, offset, FALSE, FALSE));
6928                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6929                 }
6930               else
6931                 {
6932                   MOVA (aopGet (right, offset, FALSE, FALSE));
6933                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6934                 }
6935               aopPut (result, "a", offset);
6936             }
6937         }
6938     }
6939
6940 release:
6941   freeAsmop (result, NULL, ic, TRUE);
6942   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6943   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6944 }
6945
6946 /*-----------------------------------------------------------------*/
6947 /* genOr  - code for or                                            */
6948 /*-----------------------------------------------------------------*/
6949 static void
6950 genOr (iCode * ic, iCode * ifx)
6951 {
6952   operand *left, *right, *result;
6953   int size, offset = 0;
6954   unsigned long lit = 0L;
6955   int bytelit = 0;
6956
6957   D (emitcode (";", "genOr"));
6958
6959   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6960   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6961   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6962
6963 #ifdef DEBUG_TYPE
6964   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6965             AOP_TYPE (result),
6966             AOP_TYPE (left), AOP_TYPE (right));
6967   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6968             AOP_SIZE (result),
6969             AOP_SIZE (left), AOP_SIZE (right));
6970 #endif
6971
6972   /* if left is a literal & right is not then exchange them */
6973   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6974       AOP_NEEDSACC (left))
6975     {
6976       operand *tmp = right;
6977       right = left;
6978       left = tmp;
6979     }
6980
6981   /* if result = right then exchange them */
6982   if (sameRegs (AOP (result), AOP (right)))
6983     {
6984       operand *tmp = right;
6985       right = left;
6986       left = tmp;
6987     }
6988
6989   /* if right is bit then exchange them */
6990   if (AOP_TYPE (right) == AOP_CRY &&
6991       AOP_TYPE (left) != AOP_CRY)
6992     {
6993       operand *tmp = right;
6994       right = left;
6995       left = tmp;
6996     }
6997   if (AOP_TYPE (right) == AOP_LIT)
6998     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6999
7000   size = AOP_SIZE (result);
7001
7002   // if(bit | yy)
7003   // xx = bit | yy;
7004   if (AOP_TYPE (left) == AOP_CRY)
7005     {
7006       if (AOP_TYPE (right) == AOP_LIT)
7007         {
7008           // c = bit | literal;
7009           if (lit)
7010             {
7011               // lit != 0 => result = 1
7012               if (AOP_TYPE (result) == AOP_CRY)
7013                 {
7014                   if (size)
7015                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7016                   else if (ifx)
7017                     continueIfTrue (ifx);
7018                   goto release;
7019                 }
7020               emitcode ("setb", "c");
7021             }
7022           else
7023             {
7024               // lit == 0 => result = left
7025               if (size && sameRegs (AOP (result), AOP (left)))
7026                 goto release;
7027               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7028             }
7029         }
7030       else
7031         {
7032           if (AOP_TYPE (right) == AOP_CRY)
7033             {
7034               // c = bit | bit;
7035               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7036               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7037             }
7038           else
7039             {
7040               // c = bit | val;
7041               symbol *tlbl = newiTempLabel (NULL);
7042               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7043                 emitcode ("setb", "c");
7044               emitcode ("jb", "%s,%05d$",
7045                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7046               toBoolean (right);
7047               emitcode ("jnz", "%05d$", tlbl->key + 100);
7048               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7049                 {
7050                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7051                   goto release;
7052                 }
7053               else
7054                 {
7055                   CLRC;
7056                   emitLabel (tlbl);
7057                 }
7058             }
7059         }
7060       // bit = c
7061       // val = c
7062       if (size)
7063         outBitC (result);
7064       // if(bit | ...)
7065       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7066         genIfxJump (ifx, "c", left, right, result);
7067       goto release;
7068     }
7069
7070   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7071   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7072   if ((AOP_TYPE (right) == AOP_LIT) &&
7073       (AOP_TYPE (result) == AOP_CRY) &&
7074       (AOP_TYPE (left) != AOP_CRY))
7075     {
7076       if (lit)
7077         {
7078           // result = 1
7079           if (size)
7080             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7081           else
7082             continueIfTrue (ifx);
7083           goto release;
7084         }
7085       else
7086         {
7087           // lit = 0, result = boolean(left)
7088           if (size)
7089             emitcode ("setb", "c");
7090           toBoolean (right);
7091           if (size)
7092             {
7093               symbol *tlbl = newiTempLabel (NULL);
7094               emitcode ("jnz", "%05d$", tlbl->key + 100);
7095               CLRC;
7096               emitLabel (tlbl);
7097             }
7098           else
7099             {
7100               genIfxJump (ifx, "a", left, right, result);
7101               goto release;
7102             }
7103         }
7104       outBitC (result);
7105       goto release;
7106     }
7107
7108   /* if left is same as result */
7109   if (sameRegs (AOP (result), AOP (left)))
7110     {
7111       for (; size--; offset++)
7112         {
7113           if (AOP_TYPE (right) == AOP_LIT)
7114             {
7115               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7116               if (bytelit == 0)
7117                 {
7118                   /* dummy read of volatile operand */
7119                   if (isOperandVolatile (left, FALSE))
7120                     MOVA (aopGet (left, offset, FALSE, FALSE));
7121                   else
7122                     continue;
7123                 }
7124               else if (bytelit == 0x0FF)
7125                 {
7126                   aopPut (result, "#0xFF", offset);
7127                 }
7128               else if (IS_AOP_PREG (left))
7129                 {
7130                   MOVA (aopGet (left, offset, FALSE, TRUE));
7131                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7132                   aopPut (result, "a", offset);
7133                 }
7134               else
7135                 {
7136                   emitcode ("orl", "%s,%s",
7137                             aopGet (left, offset, FALSE, TRUE),
7138                             aopGet (right, offset, FALSE, FALSE));
7139                 }
7140             }
7141           else
7142             {
7143               if (AOP_TYPE (left) == AOP_ACC)
7144                 {
7145                   if (offset)
7146                     emitcode("mov", "a,b");
7147                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7148                 }
7149               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7150                 {
7151                   MOVB (aopGet (left, offset, FALSE, FALSE));
7152                   MOVA (aopGet (right, offset, FALSE, FALSE));
7153                   emitcode ("orl", "a,b");
7154                   aopPut (result, "a", offset);
7155                 }
7156               else if (aopGetUsesAcc (left, offset))
7157                 {
7158                   MOVA (aopGet (left, offset, FALSE, FALSE));
7159                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7160                   aopPut (result, "a", offset);
7161                 }
7162               else
7163                 {
7164                   MOVA (aopGet (right, offset, FALSE, FALSE));
7165                   if (IS_AOP_PREG (left))
7166                     {
7167                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7168                       aopPut (result, "a", offset);
7169                     }
7170                   else
7171                     {
7172                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7173                     }
7174                 }
7175             }
7176         }
7177     }
7178   else
7179     {
7180       // left & result in different registers
7181       if (AOP_TYPE (result) == AOP_CRY)
7182         {
7183           // result = bit
7184           // if(size), result in bit
7185           // if(!size && ifx), conditional oper: if(left | right)
7186           symbol *tlbl = newiTempLabel (NULL);
7187           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7188           if (size)
7189             emitcode ("setb", "c");
7190           while (sizer--)
7191             {
7192               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7193                   && AOP_TYPE(left)==AOP_ACC)
7194                 {
7195                   if (offset)
7196                     emitcode("mov", "a,b");
7197                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7198                 }
7199               else if (AOP_TYPE(left)==AOP_ACC)
7200                 {
7201                   if (!offset)
7202                     {
7203                       bool pushedB = pushB ();
7204                       emitcode("mov", "b,a");
7205                       MOVA (aopGet (right, offset, FALSE, FALSE));
7206                       emitcode("orl", "a,b");
7207                       popB (pushedB);
7208                     }
7209                   else
7210                     {
7211                       MOVA (aopGet (right, offset, FALSE, FALSE));
7212                       emitcode("orl", "a,b");
7213                     }
7214                 }
7215               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7216                 {
7217                   MOVB (aopGet (left, offset, FALSE, FALSE));
7218                   MOVA (aopGet (right, offset, FALSE, FALSE));
7219                   emitcode ("orl", "a,b");
7220                 }
7221               else if (aopGetUsesAcc (left, offset))
7222                 {
7223                   MOVA (aopGet (left, offset, FALSE, FALSE));
7224                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7225                 }
7226               else
7227                 {
7228                   MOVA (aopGet (right, offset, FALSE, FALSE));
7229                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7230               }
7231
7232               emitcode ("jnz", "%05d$", tlbl->key + 100);
7233               offset++;
7234             }
7235           if (size)
7236             {
7237               CLRC;
7238               emitLabel (tlbl);
7239               outBitC (result);
7240             }
7241           else if (ifx)
7242             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7243           else
7244             emitLabel (tlbl);
7245         }
7246       else
7247         {
7248           for (; (size--); offset++)
7249             {
7250               // normal case
7251               // result = left | right
7252               if (AOP_TYPE (right) == AOP_LIT)
7253                 {
7254                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7255                   if (bytelit == 0)
7256                     {
7257                       aopPut (result,
7258                               aopGet (left, offset, FALSE, FALSE),
7259                               offset);
7260                       continue;
7261                     }
7262                   else if (bytelit == 0x0FF)
7263                     {
7264                       /* dummy read of volatile operand */
7265                       if (isOperandVolatile (left, FALSE))
7266                         MOVA (aopGet (left, offset, FALSE, FALSE));
7267                       aopPut (result, "#0xFF", offset);
7268                       continue;
7269                     }
7270                 }
7271               // faster than result <- left, orl result,right
7272               // and better if result is SFR
7273               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7274                   && AOP_TYPE(left)==AOP_ACC)
7275                 {
7276                   if (offset)
7277                     emitcode("mov", "a,b");
7278                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7279                 }
7280               else if (AOP_TYPE(left)==AOP_ACC)
7281                 {
7282                   if (!offset)
7283                     {
7284                       bool pushedB = pushB ();
7285                       emitcode("mov", "b,a");
7286                       MOVA (aopGet (right, offset, FALSE, FALSE));
7287                       emitcode("orl", "a,b");
7288                       popB (pushedB);
7289                     }
7290                   else
7291                     {
7292                       MOVA (aopGet (right, offset, FALSE, FALSE));
7293                       emitcode("orl", "a,b");
7294                     }
7295                 }
7296               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7297                 {
7298                   MOVB (aopGet (left, offset, FALSE, FALSE));
7299                   MOVA (aopGet (right, offset, FALSE, FALSE));
7300                   emitcode ("orl", "a,b");
7301                 }
7302               else if (aopGetUsesAcc (left, offset))
7303                 {
7304                   MOVA (aopGet (left, offset, FALSE, FALSE));
7305                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7306                 }
7307               else
7308                 {
7309                   MOVA (aopGet (right, offset, FALSE, FALSE));
7310                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7311                 }
7312               aopPut (result, "a", offset);
7313             }
7314         }
7315     }
7316
7317 release:
7318   freeAsmop (result, NULL, ic, TRUE);
7319   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7320   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7321 }
7322
7323 /*-----------------------------------------------------------------*/
7324 /* genXor - code for xclusive or                                   */
7325 /*-----------------------------------------------------------------*/
7326 static void
7327 genXor (iCode * ic, iCode * ifx)
7328 {
7329   operand *left, *right, *result;
7330   int size, offset = 0;
7331   unsigned long lit = 0L;
7332   int bytelit = 0;
7333
7334   D (emitcode (";", "genXor"));
7335
7336   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7337   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7338   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7339
7340 #ifdef DEBUG_TYPE
7341   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7342             AOP_TYPE (result),
7343             AOP_TYPE (left), AOP_TYPE (right));
7344   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7345             AOP_SIZE (result),
7346             AOP_SIZE (left), AOP_SIZE (right));
7347 #endif
7348
7349   /* if left is a literal & right is not ||
7350      if left needs acc & right does not */
7351   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7352       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7353     {
7354       operand *tmp = right;
7355       right = left;
7356       left = tmp;
7357     }
7358
7359   /* if result = right then exchange them */
7360   if (sameRegs (AOP (result), AOP (right)))
7361     {
7362       operand *tmp = right;
7363       right = left;
7364       left = tmp;
7365     }
7366
7367   /* if right is bit then exchange them */
7368   if (AOP_TYPE (right) == AOP_CRY &&
7369       AOP_TYPE (left) != AOP_CRY)
7370     {
7371       operand *tmp = right;
7372       right = left;
7373       left = tmp;
7374     }
7375   if (AOP_TYPE (right) == AOP_LIT)
7376     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7377
7378   size = AOP_SIZE (result);
7379
7380   // if(bit ^ yy)
7381   // xx = bit ^ yy;
7382   if (AOP_TYPE (left) == AOP_CRY)
7383     {
7384       if (AOP_TYPE (right) == AOP_LIT)
7385         {
7386           // c = bit & literal;
7387           if (lit >> 1)
7388             {
7389               // lit>>1  != 0 => result = 1
7390               if (AOP_TYPE (result) == AOP_CRY)
7391                 {
7392                   if (size)
7393                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7394                   else if (ifx)
7395                     continueIfTrue (ifx);
7396                   goto release;
7397                 }
7398               emitcode ("setb", "c");
7399             }
7400           else
7401             {
7402               // lit == (0 or 1)
7403               if (lit == 0)
7404                 {
7405                   // lit == 0, result = left
7406                   if (size && sameRegs (AOP (result), AOP (left)))
7407                     goto release;
7408                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7409                 }
7410               else
7411                 {
7412                   // lit == 1, result = not(left)
7413                   if (size && sameRegs (AOP (result), AOP (left)))
7414                     {
7415                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7416                       goto release;
7417                     }
7418                   else
7419                     {
7420                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7421                       emitcode ("cpl", "c");
7422                     }
7423                 }
7424             }
7425         }
7426       else
7427         {
7428           // right != literal
7429           symbol *tlbl = newiTempLabel (NULL);
7430           if (AOP_TYPE (right) == AOP_CRY)
7431             {
7432               // c = bit ^ bit;
7433               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7434             }
7435           else
7436             {
7437               int sizer = AOP_SIZE (right);
7438               // c = bit ^ val
7439               // if val>>1 != 0, result = 1
7440               emitcode ("setb", "c");
7441               while (sizer)
7442                 {
7443                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7444                   if (sizer == 1)
7445                     // test the msb of the lsb
7446                     emitcode ("anl", "a,#0xfe");
7447                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7448                   sizer--;
7449                 }
7450               // val = (0,1)
7451               emitcode ("rrc", "a");
7452             }
7453           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7454           emitcode ("cpl", "c");
7455           emitLabel (tlbl);
7456         }
7457       // bit = c
7458       // val = c
7459       if (size)
7460         outBitC (result);
7461       // if(bit | ...)
7462       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7463         genIfxJump (ifx, "c", left, right, result);
7464       goto release;
7465     }
7466
7467   /* if left is same as result */
7468   if (sameRegs (AOP (result), AOP (left)))
7469     {
7470       for (; size--; offset++)
7471         {
7472           if (AOP_TYPE (right) == AOP_LIT)
7473             {
7474               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7475               if (bytelit == 0)
7476                 {
7477                   /* dummy read of volatile operand */
7478                   if (isOperandVolatile (left, FALSE))
7479                     MOVA (aopGet (left, offset, FALSE, FALSE));
7480                   else
7481                     continue;
7482                 }
7483               else if (IS_AOP_PREG (left))
7484                 {
7485                   MOVA (aopGet (left, offset, FALSE, TRUE));
7486                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7487                   aopPut (result, "a", offset);
7488                 }
7489               else
7490                 {
7491                   emitcode ("xrl", "%s,%s",
7492                             aopGet (left, offset, FALSE, TRUE),
7493                             aopGet (right, offset, FALSE, FALSE));
7494                 }
7495             }
7496           else
7497             {
7498               if (AOP_TYPE (left) == AOP_ACC)
7499                 {
7500                   if (offset)
7501                     emitcode("mov", "a,b");
7502                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7503                 }
7504               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7505                 {
7506                   MOVB (aopGet (left, offset, FALSE, FALSE));
7507                   MOVA (aopGet (right, offset, FALSE, FALSE));
7508                   emitcode ("xrl", "a,b");
7509                   aopPut (result, "a", offset);
7510                 }
7511               else if (aopGetUsesAcc (left, offset))
7512                 {
7513                   MOVA (aopGet (left, offset, FALSE, FALSE));
7514                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7515                   aopPut (result, "a", offset);
7516                 }
7517               else
7518                 {
7519                   MOVA (aopGet (right, offset, FALSE, FALSE));
7520                   if (IS_AOP_PREG (left))
7521                     {
7522                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7523                       aopPut (result, "a", offset);
7524                     }
7525                   else
7526                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7527                 }
7528             }
7529         }
7530     }
7531   else
7532     {
7533       // left & result in different registers
7534       if (AOP_TYPE (result) == AOP_CRY)
7535         {
7536           // result = bit
7537           // if(size), result in bit
7538           // if(!size && ifx), conditional oper: if(left ^ right)
7539           symbol *tlbl = newiTempLabel (NULL);
7540           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7541
7542           if (size)
7543             emitcode ("setb", "c");
7544           while (sizer--)
7545             {
7546               if ((AOP_TYPE (right) == AOP_LIT) &&
7547                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7548                 {
7549                   MOVA (aopGet (left, offset, FALSE, FALSE));
7550                 }
7551               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7552                   && AOP_TYPE(left)==AOP_ACC)
7553                 {
7554                   if (offset)
7555                     emitcode("mov", "a,b");
7556                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7557                 }
7558               else if (AOP_TYPE(left)==AOP_ACC)
7559                 {
7560                   if (!offset)
7561                     {
7562                       bool pushedB = pushB ();
7563                       emitcode("mov", "b,a");
7564                       MOVA (aopGet (right, offset, FALSE, FALSE));
7565                       emitcode("xrl", "a,b");
7566                       popB (pushedB);
7567                     }
7568                   else
7569                     {
7570                       MOVA (aopGet (right, offset, FALSE, FALSE));
7571                       emitcode("xrl", "a,b");
7572                     }
7573                 }
7574               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7575                 {
7576                   MOVB (aopGet (left, offset, FALSE, FALSE));
7577                   MOVA (aopGet (right, offset, FALSE, FALSE));
7578                   emitcode ("xrl", "a,b");
7579                 }
7580               else if (aopGetUsesAcc (left, offset))
7581                 {
7582                   MOVA (aopGet (left, offset, FALSE, FALSE));
7583                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7584                 }
7585               else
7586                 {
7587                   MOVA (aopGet (right, offset, FALSE, FALSE));
7588                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7589                 }
7590
7591               emitcode ("jnz", "%05d$", tlbl->key + 100);
7592               offset++;
7593             }
7594           if (size)
7595             {
7596               CLRC;
7597               emitLabel (tlbl);
7598               outBitC (result);
7599             }
7600           else if (ifx)
7601             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7602         }
7603       else
7604         {
7605           for (; (size--); offset++)
7606             {
7607               // normal case
7608               // result = left ^ right
7609               if (AOP_TYPE (right) == AOP_LIT)
7610                 {
7611                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7612                   if (bytelit == 0)
7613                     {
7614                       aopPut (result,
7615                               aopGet (left, offset, FALSE, FALSE),
7616                               offset);
7617                       continue;
7618                     }
7619                 }
7620               // faster than result <- left, xrl result,right
7621               // and better if result is SFR
7622               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7623                   && AOP_TYPE(left)==AOP_ACC)
7624                 {
7625                   if (offset)
7626                     emitcode("mov", "a,b");
7627                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7628                 }
7629               else if (AOP_TYPE(left)==AOP_ACC)
7630                 {
7631                   if (!offset)
7632                     {
7633                       bool pushedB = pushB ();
7634                       emitcode("mov", "b,a");
7635                       MOVA (aopGet (right, offset, FALSE, FALSE));
7636                       emitcode("xrl", "a,b");
7637                       popB (pushedB);
7638                     }
7639                   else
7640                     {
7641                       MOVA (aopGet (right, offset, FALSE, FALSE));
7642                       emitcode("xrl", "a,b");
7643                     }
7644                 }
7645               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7646                 {
7647                   MOVB (aopGet (left, offset, FALSE, FALSE));
7648                   MOVA (aopGet (right, offset, FALSE, FALSE));
7649                   emitcode ("xrl", "a,b");
7650                 }
7651               else if (aopGetUsesAcc (left, offset))
7652                 {
7653                   MOVA (aopGet (left, offset, FALSE, FALSE));
7654                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7655                 }
7656               else
7657                 {
7658                   MOVA (aopGet (right, offset, FALSE, FALSE));
7659                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7660                 }
7661               aopPut (result, "a", offset);
7662             }
7663         }
7664     }
7665
7666 release:
7667   freeAsmop (result, NULL, ic, TRUE);
7668   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7669   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7670 }
7671
7672 /*-----------------------------------------------------------------*/
7673 /* genInline - write the inline code out                           */
7674 /*-----------------------------------------------------------------*/
7675 static void
7676 genInline (iCode * ic)
7677 {
7678   char *buffer, *bp, *bp1;
7679
7680   D (emitcode (";", "genInline"));
7681
7682   _G.inLine += (!options.asmpeep);
7683
7684   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7685
7686   /* emit each line as a code */
7687   while (*bp)
7688     {
7689       if (*bp == '\n')
7690         {
7691           *bp++ = '\0';
7692           emitcode (bp1, "");
7693           bp1 = bp;
7694         }
7695       else
7696         {
7697           /* Add \n for labels, not dirs such as c:\mydir */
7698           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7699             {
7700               bp++;
7701               *bp = '\0';
7702               bp++;
7703               emitcode (bp1, "");
7704               bp1 = bp;
7705             }
7706           else
7707             bp++;
7708         }
7709     }
7710   if (bp1 != bp)
7711     emitcode (bp1, "");
7712   /*     emitcode("",buffer); */
7713   _G.inLine -= (!options.asmpeep);
7714 }
7715
7716 /*-----------------------------------------------------------------*/
7717 /* genRRC - rotate right with carry                                */
7718 /*-----------------------------------------------------------------*/
7719 static void
7720 genRRC (iCode * ic)
7721 {
7722   operand *left, *result;
7723   int size, offset;
7724   char *l;
7725
7726   D (emitcode (";", "genRRC"));
7727
7728   /* rotate right with carry */
7729   left = IC_LEFT (ic);
7730   result = IC_RESULT (ic);
7731   aopOp (left, ic, FALSE);
7732   aopOp (result, ic, FALSE);
7733
7734   /* move it to the result */
7735   size = AOP_SIZE (result);
7736   offset = size - 1;
7737   if (size == 1) { /* special case for 1 byte */
7738       l = aopGet (left, offset, FALSE, FALSE);
7739       MOVA (l);
7740       emitcode ("rr", "a");
7741       goto release;
7742   }
7743   /* no need to clear carry, bit7 will be written later */
7744   while (size--)
7745     {
7746       l = aopGet (left, offset, FALSE, FALSE);
7747       MOVA (l);
7748       emitcode ("rrc", "a");
7749       if (AOP_SIZE (result) > 1)
7750         aopPut (result, "a", offset--);
7751     }
7752   /* now we need to put the carry into the
7753      highest order byte of the result */
7754   if (AOP_SIZE (result) > 1)
7755     {
7756       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7757       MOVA (l);
7758     }
7759   emitcode ("mov", "acc.7,c");
7760  release:
7761   aopPut (result, "a", AOP_SIZE (result) - 1);
7762   freeAsmop (result, NULL, ic, TRUE);
7763   freeAsmop (left, NULL, ic, TRUE);
7764 }
7765
7766 /*-----------------------------------------------------------------*/
7767 /* genRLC - generate code for rotate left with carry               */
7768 /*-----------------------------------------------------------------*/
7769 static void
7770 genRLC (iCode * ic)
7771 {
7772   operand *left, *result;
7773   int size, offset;
7774   char *l;
7775
7776   D (emitcode (";", "genRLC"));
7777
7778   /* rotate right with carry */
7779   left = IC_LEFT (ic);
7780   result = IC_RESULT (ic);
7781   aopOp (left, ic, FALSE);
7782   aopOp (result, ic, FALSE);
7783
7784   /* move it to the result */
7785   size = AOP_SIZE (result);
7786   offset = 0;
7787   if (size--)
7788     {
7789       l = aopGet (left, offset, FALSE, FALSE);
7790       MOVA (l);
7791       if (size == 0) { /* special case for 1 byte */
7792               emitcode("rl","a");
7793               goto release;
7794       }
7795       emitcode("rlc","a"); /* bit0 will be written later */
7796       if (AOP_SIZE (result) > 1)
7797         {
7798           aopPut (result, "a", offset++);
7799         }
7800
7801       while (size--)
7802         {
7803           l = aopGet (left, offset, FALSE, FALSE);
7804           MOVA (l);
7805           emitcode ("rlc", "a");
7806           if (AOP_SIZE (result) > 1)
7807             aopPut (result, "a", offset++);
7808         }
7809     }
7810   /* now we need to put the carry into the
7811      highest order byte of the result */
7812   if (AOP_SIZE (result) > 1)
7813     {
7814       l = aopGet (result, 0, FALSE, FALSE);
7815       MOVA (l);
7816     }
7817   emitcode ("mov", "acc.0,c");
7818  release:
7819   aopPut (result, "a", 0);
7820   freeAsmop (result, NULL, ic, TRUE);
7821   freeAsmop (left, NULL, ic, TRUE);
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* genGetHbit - generates code get highest order bit               */
7826 /*-----------------------------------------------------------------*/
7827 static void
7828 genGetHbit (iCode * ic)
7829 {
7830   operand *left, *result;
7831
7832   D (emitcode (";", "genGetHbit"));
7833
7834   left = IC_LEFT (ic);
7835   result = IC_RESULT (ic);
7836   aopOp (left, ic, FALSE);
7837   aopOp (result, ic, FALSE);
7838
7839   /* get the highest order byte into a */
7840   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7841   if (AOP_TYPE (result) == AOP_CRY)
7842     {
7843       emitcode ("rlc", "a");
7844       outBitC (result);
7845     }
7846   else
7847     {
7848       emitcode ("rl", "a");
7849       emitcode ("anl", "a,#0x01");
7850       outAcc (result);
7851     }
7852
7853   freeAsmop (result, NULL, ic, TRUE);
7854   freeAsmop (left, NULL, ic, TRUE);
7855 }
7856
7857 /*-----------------------------------------------------------------*/
7858 /* genGetAbit - generates code get a single bit                    */
7859 /*-----------------------------------------------------------------*/
7860 static void
7861 genGetAbit (iCode * ic)
7862 {
7863   operand *left, *right, *result;
7864   int shCount;
7865
7866   D (emitcode (";", "genGetAbit"));
7867
7868   left = IC_LEFT (ic);
7869   right = IC_RIGHT (ic);
7870   result = IC_RESULT (ic);
7871   aopOp (left, ic, FALSE);
7872   aopOp (right, ic, FALSE);
7873   aopOp (result, ic, FALSE);
7874
7875   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7876
7877   /* get the needed byte into a */
7878   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7879   shCount %= 8;
7880   if (AOP_TYPE (result) == AOP_CRY)
7881     {
7882       if ((shCount) == 7)
7883           emitcode ("rlc", "a");
7884       else if ((shCount) == 0)
7885           emitcode ("rrc", "a");
7886       else
7887           emitcode ("mov", "c,acc[%d]", shCount);
7888       outBitC (result);
7889     }
7890   else
7891     {
7892       switch (shCount)
7893         {
7894         case 2:
7895           emitcode ("rr", "a");
7896           //fallthrough
7897         case 1:
7898           emitcode ("rr", "a");
7899           //fallthrough
7900         case 0:
7901           emitcode ("anl", "a,#0x01");
7902           break;
7903         case 3:
7904         case 5:
7905           emitcode ("mov", "c,acc[%d]", shCount);
7906           emitcode ("clr", "a");
7907           emitcode ("rlc", "a");
7908           break;
7909         case 4:
7910           emitcode ("swap", "a");
7911           emitcode ("anl", "a,#0x01");
7912           break;
7913         case 6:
7914           emitcode ("rl", "a");
7915           //fallthrough
7916         case 7:
7917           emitcode ("rl", "a");
7918           emitcode ("anl", "a,#0x01");
7919           break;
7920         }
7921       outAcc (result);
7922     }
7923
7924   freeAsmop (result, NULL, ic, TRUE);
7925   freeAsmop (right, NULL, ic, TRUE);
7926   freeAsmop (left, NULL, ic, TRUE);
7927 }
7928
7929 /*-----------------------------------------------------------------*/
7930 /* genGetByte - generates code get a single byte                   */
7931 /*-----------------------------------------------------------------*/
7932 static void
7933 genGetByte (iCode * ic)
7934 {
7935   operand *left, *right, *result;
7936   int offset;
7937
7938   D (emitcode (";", "genGetByte"));
7939
7940   left = IC_LEFT (ic);
7941   right = IC_RIGHT (ic);
7942   result = IC_RESULT (ic);
7943   aopOp (left, ic, FALSE);
7944   aopOp (right, ic, FALSE);
7945   aopOp (result, ic, FALSE);
7946
7947   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7948   aopPut (result,
7949           aopGet (left, offset, FALSE, FALSE),
7950           0);
7951
7952   freeAsmop (result, NULL, ic, TRUE);
7953   freeAsmop (right, NULL, ic, TRUE);
7954   freeAsmop (left, NULL, ic, TRUE);
7955 }
7956
7957 /*-----------------------------------------------------------------*/
7958 /* genGetWord - generates code get two bytes                       */
7959 /*-----------------------------------------------------------------*/
7960 static void
7961 genGetWord (iCode * ic)
7962 {
7963   operand *left, *right, *result;
7964   int offset;
7965
7966   D (emitcode (";", "genGetWord"));
7967
7968   left = IC_LEFT (ic);
7969   right = IC_RIGHT (ic);
7970   result = IC_RESULT (ic);
7971   aopOp (left, ic, FALSE);
7972   aopOp (right, ic, FALSE);
7973   aopOp (result, ic, FALSE);
7974
7975   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7976   aopPut (result,
7977           aopGet (left, offset, FALSE, FALSE),
7978           0);
7979   aopPut (result,
7980           aopGet (left, offset+1, FALSE, FALSE),
7981           1);
7982
7983   freeAsmop (result, NULL, ic, TRUE);
7984   freeAsmop (right, NULL, ic, TRUE);
7985   freeAsmop (left, NULL, ic, TRUE);
7986 }
7987
7988 /*-----------------------------------------------------------------*/
7989 /* genSwap - generates code to swap nibbles or bytes               */
7990 /*-----------------------------------------------------------------*/
7991 static void
7992 genSwap (iCode * ic)
7993 {
7994   operand *left, *result;
7995
7996   D(emitcode (";     genSwap",""));
7997
7998   left = IC_LEFT (ic);
7999   result = IC_RESULT (ic);
8000   aopOp (left, ic, FALSE);
8001   aopOp (result, ic, FALSE);
8002
8003   switch (AOP_SIZE (left))
8004     {
8005     case 1: /* swap nibbles in byte */
8006       MOVA (aopGet (left, 0, FALSE, FALSE));
8007       emitcode ("swap", "a");
8008       aopPut (result, "a", 0);
8009       break;
8010     case 2: /* swap bytes in word */
8011       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8012         {
8013           MOVA (aopGet (left, 0, FALSE, FALSE));
8014           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8015           aopPut (result, "a", 1);
8016         }
8017       else if (operandsEqu (left, result))
8018         {
8019           char * reg = "a";
8020           bool pushedB = FALSE, leftInB = FALSE;
8021
8022           MOVA (aopGet (left, 0, FALSE, FALSE));
8023           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8024             {
8025               pushedB = pushB ();
8026               emitcode ("mov", "b,a");
8027               reg = "b";
8028               leftInB = TRUE;
8029             }
8030           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8031           aopPut (result, reg, 1);
8032
8033           if (leftInB)
8034             popB (pushedB);
8035         }
8036       else
8037         {
8038           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8039           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8040         }
8041       break;
8042     default:
8043       wassertl(FALSE, "unsupported SWAP operand size");
8044     }
8045
8046   freeAsmop (result, NULL, ic, TRUE);
8047   freeAsmop (left, NULL, ic, TRUE);
8048 }
8049
8050 /*-----------------------------------------------------------------*/
8051 /* AccRol - rotate left accumulator by known count                 */
8052 /*-----------------------------------------------------------------*/
8053 static void
8054 AccRol (int shCount)
8055 {
8056   shCount &= 0x0007;            // shCount : 0..7
8057
8058   switch (shCount)
8059     {
8060     case 0:
8061       break;
8062     case 1:
8063       emitcode ("rl", "a");
8064       break;
8065     case 2:
8066       emitcode ("rl", "a");
8067       emitcode ("rl", "a");
8068       break;
8069     case 3:
8070       emitcode ("swap", "a");
8071       emitcode ("rr", "a");
8072       break;
8073     case 4:
8074       emitcode ("swap", "a");
8075       break;
8076     case 5:
8077       emitcode ("swap", "a");
8078       emitcode ("rl", "a");
8079       break;
8080     case 6:
8081       emitcode ("rr", "a");
8082       emitcode ("rr", "a");
8083       break;
8084     case 7:
8085       emitcode ("rr", "a");
8086       break;
8087     }
8088 }
8089
8090 /*-----------------------------------------------------------------*/
8091 /* AccLsh - left shift accumulator by known count                  */
8092 /*-----------------------------------------------------------------*/
8093 static void
8094 AccLsh (int shCount)
8095 {
8096   if (shCount != 0)
8097     {
8098       if (shCount == 1)
8099         emitcode ("add", "a,acc");
8100       else if (shCount == 2)
8101         {
8102           emitcode ("add", "a,acc");
8103           emitcode ("add", "a,acc");
8104         }
8105       else
8106         {
8107           /* rotate left accumulator */
8108           AccRol (shCount);
8109           /* and kill the lower order bits */
8110           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8111         }
8112     }
8113 }
8114
8115 /*-----------------------------------------------------------------*/
8116 /* AccRsh - right shift accumulator by known count                 */
8117 /*-----------------------------------------------------------------*/
8118 static void
8119 AccRsh (int shCount)
8120 {
8121   if (shCount != 0)
8122     {
8123       if (shCount == 1)
8124         {
8125           CLRC;
8126           emitcode ("rrc", "a");
8127         }
8128       else
8129         {
8130           /* rotate right accumulator */
8131           AccRol (8 - shCount);
8132           /* and kill the higher order bits */
8133           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8134         }
8135     }
8136 }
8137
8138 /*-----------------------------------------------------------------*/
8139 /* AccSRsh - signed right shift accumulator by known count                 */
8140 /*-----------------------------------------------------------------*/
8141 static void
8142 AccSRsh (int shCount)
8143 {
8144   symbol *tlbl;
8145   if (shCount != 0)
8146     {
8147       if (shCount == 1)
8148         {
8149           emitcode ("mov", "c,acc.7");
8150           emitcode ("rrc", "a");
8151         }
8152       else if (shCount == 2)
8153         {
8154           emitcode ("mov", "c,acc.7");
8155           emitcode ("rrc", "a");
8156           emitcode ("mov", "c,acc.7");
8157           emitcode ("rrc", "a");
8158         }
8159       else
8160         {
8161           tlbl = newiTempLabel (NULL);
8162           /* rotate right accumulator */
8163           AccRol (8 - shCount);
8164           /* and kill the higher order bits */
8165           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8166           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8167           emitcode ("orl", "a,#0x%02x",
8168                     (unsigned char) ~SRMask[shCount]);
8169           emitLabel (tlbl);
8170         }
8171     }
8172 }
8173
8174 /*-----------------------------------------------------------------*/
8175 /* shiftR1Left2Result - shift right one byte from left to result   */
8176 /*-----------------------------------------------------------------*/
8177 static void
8178 shiftR1Left2Result (operand * left, int offl,
8179                     operand * result, int offr,
8180                     int shCount, int sign)
8181 {
8182   MOVA (aopGet (left, offl, FALSE, FALSE));
8183   /* shift right accumulator */
8184   if (sign)
8185     AccSRsh (shCount);
8186   else
8187     AccRsh (shCount);
8188   aopPut (result, "a", offr);
8189 }
8190
8191 /*-----------------------------------------------------------------*/
8192 /* shiftL1Left2Result - shift left one byte from left to result    */
8193 /*-----------------------------------------------------------------*/
8194 static void
8195 shiftL1Left2Result (operand * left, int offl,
8196                     operand * result, int offr, int shCount)
8197 {
8198   char *l;
8199   l = aopGet (left, offl, FALSE, FALSE);
8200   MOVA (l);
8201   /* shift left accumulator */
8202   AccLsh (shCount);
8203   aopPut (result, "a", offr);
8204 }
8205
8206 /*-----------------------------------------------------------------*/
8207 /* movLeft2Result - move byte from left to result                  */
8208 /*-----------------------------------------------------------------*/
8209 static void
8210 movLeft2Result (operand * left, int offl,
8211                 operand * result, int offr, int sign)
8212 {
8213   char *l;
8214   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8215     {
8216       l = aopGet (left, offl, FALSE, FALSE);
8217
8218       if (*l == '@' && (IS_AOP_PREG (result)))
8219         {
8220           emitcode ("mov", "a,%s", l);
8221           aopPut (result, "a", offr);
8222         }
8223       else
8224         {
8225           if (!sign)
8226             {
8227               aopPut (result, l, offr);
8228             }
8229           else
8230             {
8231               /* MSB sign in acc.7 ! */
8232               if (getDataSize (left) == offl + 1)
8233                 {
8234                   MOVA (l);
8235                   aopPut (result, "a", offr);
8236                 }
8237             }
8238         }
8239     }
8240 }
8241
8242 /*-----------------------------------------------------------------*/
8243 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8244 /*-----------------------------------------------------------------*/
8245 static void
8246 AccAXRrl1 (char *x)
8247 {
8248   emitcode ("rrc", "a");
8249   emitcode ("xch", "a,%s", x);
8250   emitcode ("rrc", "a");
8251   emitcode ("xch", "a,%s", x);
8252 }
8253
8254 /*-----------------------------------------------------------------*/
8255 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8256 /*-----------------------------------------------------------------*/
8257 static void
8258 AccAXLrl1 (char *x)
8259 {
8260   emitcode ("xch", "a,%s", x);
8261   emitcode ("rlc", "a");
8262   emitcode ("xch", "a,%s", x);
8263   emitcode ("rlc", "a");
8264 }
8265
8266 /*-----------------------------------------------------------------*/
8267 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8268 /*-----------------------------------------------------------------*/
8269 static void
8270 AccAXLsh1 (char *x)
8271 {
8272   emitcode ("xch", "a,%s", x);
8273   emitcode ("add", "a,acc");
8274   emitcode ("xch", "a,%s", x);
8275   emitcode ("rlc", "a");
8276 }
8277
8278 /*-----------------------------------------------------------------*/
8279 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8280 /*-----------------------------------------------------------------*/
8281 static void
8282 AccAXLsh (char *x, int shCount)
8283 {
8284   switch (shCount)
8285     {
8286     case 0:
8287       break;
8288     case 1:
8289       AccAXLsh1 (x);
8290       break;
8291     case 2:
8292       AccAXLsh1 (x);
8293       AccAXLsh1 (x);
8294       break;
8295     case 3:
8296     case 4:
8297     case 5:                     // AAAAABBB:CCCCCDDD
8298
8299       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8300
8301       emitcode ("anl", "a,#0x%02x",
8302                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8303
8304       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8305
8306       AccRol (shCount);         // DDDCCCCC:BBB00000
8307
8308       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8309
8310       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8311
8312       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8313
8314       emitcode ("anl", "a,#0x%02x",
8315                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8316
8317       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8318
8319       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8320
8321       break;
8322     case 6:                     // AAAAAABB:CCCCCCDD
8323       emitcode ("anl", "a,#0x%02x",
8324                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8325       emitcode ("mov", "c,acc.0");      // c = B
8326       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8327 #if 0 // REMOVE ME
8328       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8329       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8330 #else
8331       emitcode("rrc","a");
8332       emitcode("xch","a,%s", x);
8333       emitcode("rrc","a");
8334       emitcode("mov","c,acc.0"); //<< get correct bit
8335       emitcode("xch","a,%s", x);
8336
8337       emitcode("rrc","a");
8338       emitcode("xch","a,%s", x);
8339       emitcode("rrc","a");
8340       emitcode("xch","a,%s", x);
8341 #endif
8342       break;
8343     case 7:                     // a:x <<= 7
8344
8345       emitcode ("anl", "a,#0x%02x",
8346                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8347
8348       emitcode ("mov", "c,acc.0");      // c = B
8349
8350       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8351
8352       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8353
8354       break;
8355     default:
8356       break;
8357     }
8358 }
8359
8360 /*-----------------------------------------------------------------*/
8361 /* AccAXRsh - right shift a:x known count (0..7)                   */
8362 /*-----------------------------------------------------------------*/
8363 static void
8364 AccAXRsh (char *x, int shCount)
8365 {
8366   switch (shCount)
8367     {
8368     case 0:
8369       break;
8370     case 1:
8371       CLRC;
8372       AccAXRrl1 (x);            // 0->a:x
8373
8374       break;
8375     case 2:
8376       CLRC;
8377       AccAXRrl1 (x);            // 0->a:x
8378
8379       CLRC;
8380       AccAXRrl1 (x);            // 0->a:x
8381
8382       break;
8383     case 3:
8384     case 4:
8385     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8386
8387       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8388
8389       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8390
8391       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8392
8393       emitcode ("anl", "a,#0x%02x",
8394                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8395
8396       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8397
8398       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8399
8400       emitcode ("anl", "a,#0x%02x",
8401                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8402
8403       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8404
8405       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8406
8407       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8408
8409       break;
8410     case 6:                     // AABBBBBB:CCDDDDDD
8411
8412       emitcode ("mov", "c,acc.7");
8413       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8414
8415       emitcode ("mov", "c,acc.7");
8416       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8417
8418       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8419
8420       emitcode ("anl", "a,#0x%02x",
8421                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8422
8423       break;
8424     case 7:                     // ABBBBBBB:CDDDDDDD
8425
8426       emitcode ("mov", "c,acc.7");      // c = A
8427
8428       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8429
8430       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8431
8432       emitcode ("anl", "a,#0x%02x",
8433                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8434
8435       break;
8436     default:
8437       break;
8438     }
8439 }
8440
8441 /*-----------------------------------------------------------------*/
8442 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8443 /*-----------------------------------------------------------------*/
8444 static void
8445 AccAXRshS (char *x, int shCount)
8446 {
8447   symbol *tlbl;
8448   switch (shCount)
8449     {
8450     case 0:
8451       break;
8452     case 1:
8453       emitcode ("mov", "c,acc.7");
8454       AccAXRrl1 (x);            // s->a:x
8455
8456       break;
8457     case 2:
8458       emitcode ("mov", "c,acc.7");
8459       AccAXRrl1 (x);            // s->a:x
8460
8461       emitcode ("mov", "c,acc.7");
8462       AccAXRrl1 (x);            // s->a:x
8463
8464       break;
8465     case 3:
8466     case 4:
8467     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8468
8469       tlbl = newiTempLabel (NULL);
8470       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8471
8472       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8473
8474       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8475
8476       emitcode ("anl", "a,#0x%02x",
8477                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8478
8479       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8480
8481       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8482
8483       emitcode ("anl", "a,#0x%02x",
8484                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8485
8486       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8487
8488       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8489
8490       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8491
8492       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8493       emitcode ("orl", "a,#0x%02x",
8494                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8495
8496       emitLabel (tlbl);
8497       break;                    // SSSSAAAA:BBBCCCCC
8498
8499     case 6:                     // AABBBBBB:CCDDDDDD
8500
8501       tlbl = newiTempLabel (NULL);
8502       emitcode ("mov", "c,acc.7");
8503       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8504
8505       emitcode ("mov", "c,acc.7");
8506       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8507
8508       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8509
8510       emitcode ("anl", "a,#0x%02x",
8511                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8512
8513       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8514       emitcode ("orl", "a,#0x%02x",
8515                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8516
8517       emitLabel (tlbl);
8518       break;
8519     case 7:                     // ABBBBBBB:CDDDDDDD
8520
8521       tlbl = newiTempLabel (NULL);
8522       emitcode ("mov", "c,acc.7");      // c = A
8523
8524       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8525
8526       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8527
8528       emitcode ("anl", "a,#0x%02x",
8529                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8530
8531       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8532       emitcode ("orl", "a,#0x%02x",
8533                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8534
8535       emitLabel (tlbl);
8536       break;
8537     default:
8538       break;
8539     }
8540 }
8541
8542 /*-----------------------------------------------------------------*/
8543 /* shiftL2Left2Result - shift left two bytes from left to result   */
8544 /*-----------------------------------------------------------------*/
8545 static void
8546 shiftL2Left2Result (operand * left, int offl,
8547                     operand * result, int offr, int shCount)
8548 {
8549   char * x;
8550   bool pushedB = FALSE;
8551   bool usedB = FALSE;
8552
8553   if (sameRegs (AOP (result), AOP (left)) &&
8554       ((offl + MSB16) == offr))
8555     {
8556       /* don't crash result[offr] */
8557       MOVA (aopGet (left, offl, FALSE, FALSE));
8558       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8559       usedB = !strncmp(x, "b", 1);
8560     }
8561   else if (aopGetUsesAcc (result, offr))
8562     {
8563       movLeft2Result (left, offl, result, offr, 0);
8564       pushedB = pushB ();
8565       usedB = TRUE;
8566       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8567       MOVA (aopGet (result, offr, FALSE, FALSE));
8568       emitcode ("xch", "a,b");
8569       x = "b";
8570     }
8571   else
8572     {
8573       movLeft2Result (left, offl, result, offr, 0);
8574       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8575       x = aopGet (result, offr, FALSE, FALSE);
8576     }
8577   /* ax << shCount (x = lsb(result)) */
8578   AccAXLsh (x, shCount);
8579   if (usedB)
8580     {
8581       emitcode ("xch", "a,b");
8582       aopPut (result, "a", offr);
8583       aopPut (result, "b", offr + MSB16);
8584       popB (pushedB);
8585     }
8586   else
8587     {
8588       aopPut (result, "a", offr + MSB16);
8589     }
8590 }
8591
8592
8593 /*-----------------------------------------------------------------*/
8594 /* shiftR2Left2Result - shift right two bytes from left to result  */
8595 /*-----------------------------------------------------------------*/
8596 static void
8597 shiftR2Left2Result (operand * left, int offl,
8598                     operand * result, int offr,
8599                     int shCount, int sign)
8600 {
8601   char * x;
8602   bool pushedB = FALSE;
8603   bool usedB = FALSE;
8604
8605   if (sameRegs (AOP (result), AOP (left)) &&
8606       ((offl + MSB16) == offr))
8607     {
8608       /* don't crash result[offr] */
8609       MOVA (aopGet (left, offl, FALSE, FALSE));
8610       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8611       usedB = !strncmp(x, "b", 1);
8612     }
8613   else if (aopGetUsesAcc (result, offr))
8614     {
8615       movLeft2Result (left, offl, result, offr, 0);
8616       pushedB = pushB ();
8617       usedB = TRUE;
8618       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8619       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8620       x = "b";
8621     }
8622   else
8623     {
8624       movLeft2Result (left, offl, result, offr, 0);
8625       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8626       x = aopGet (result, offr, FALSE, FALSE);
8627     }
8628   /* a:x >> shCount (x = lsb(result)) */
8629   if (sign)
8630     AccAXRshS (x, shCount);
8631   else
8632     AccAXRsh (x, shCount);
8633   if (usedB)
8634     {
8635       emitcode ("xch", "a,b");
8636       aopPut (result, "a", offr);
8637       emitcode ("xch", "a,b");
8638       popB (pushedB);
8639     }
8640   if (getDataSize (result) > 1)
8641     aopPut (result, "a", offr + MSB16);
8642 }
8643
8644 /*-----------------------------------------------------------------*/
8645 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8646 /*-----------------------------------------------------------------*/
8647 static void
8648 shiftLLeftOrResult (operand * left, int offl,
8649                     operand * result, int offr, int shCount)
8650 {
8651   MOVA (aopGet (left, offl, FALSE, FALSE));
8652   /* shift left accumulator */
8653   AccLsh (shCount);
8654   /* or with result */
8655   if (aopGetUsesAcc (result, offr))
8656     {
8657       emitcode ("xch", "a,b");
8658       MOVA (aopGet (result, offr, FALSE, FALSE));
8659       emitcode ("orl", "a,b");
8660     }
8661   else
8662     {
8663       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8664     }
8665   /* back to result */
8666   aopPut (result, "a", offr);
8667 }
8668
8669 /*-----------------------------------------------------------------*/
8670 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8671 /*-----------------------------------------------------------------*/
8672 static void
8673 shiftRLeftOrResult (operand * left, int offl,
8674                     operand * result, int offr, int shCount)
8675 {
8676   MOVA (aopGet (left, offl, FALSE, FALSE));
8677   /* shift right accumulator */
8678   AccRsh (shCount);
8679   /* or with result */
8680   if (aopGetUsesAcc(result, offr))
8681     {
8682       emitcode ("xch", "a,b");
8683       MOVA (aopGet (result, offr, FALSE, FALSE));
8684       emitcode ("orl", "a,b");
8685     }
8686   else
8687     {
8688       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8689     }
8690   /* back to result */
8691   aopPut (result, "a", offr);
8692 }
8693
8694 /*-----------------------------------------------------------------*/
8695 /* genlshOne - left shift a one byte quantity by known count       */
8696 /*-----------------------------------------------------------------*/
8697 static void
8698 genlshOne (operand * result, operand * left, int shCount)
8699 {
8700   D (emitcode (";", "genlshOne"));
8701
8702   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8703 }
8704
8705 /*-----------------------------------------------------------------*/
8706 /* genlshTwo - left shift two bytes by known amount != 0           */
8707 /*-----------------------------------------------------------------*/
8708 static void
8709 genlshTwo (operand * result, operand * left, int shCount)
8710 {
8711   int size;
8712
8713   D (emitcode (";", "genlshTwo"));
8714
8715   size = getDataSize (result);
8716
8717   /* if shCount >= 8 */
8718   if (shCount >= 8)
8719     {
8720       shCount -= 8;
8721
8722       if (size > 1)
8723         {
8724           if (shCount)
8725             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8726           else
8727             movLeft2Result (left, LSB, result, MSB16, 0);
8728         }
8729       aopPut (result, zero, LSB);
8730     }
8731
8732   /*  1 <= shCount <= 7 */
8733   else
8734     {
8735       if (size == 1)
8736         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8737       else
8738         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8739     }
8740 }
8741
8742 /*-----------------------------------------------------------------*/
8743 /* shiftLLong - shift left one long from left to result            */
8744 /* offl = LSB or MSB16                                             */
8745 /*-----------------------------------------------------------------*/
8746 static void
8747 shiftLLong (operand * left, operand * result, int offr)
8748 {
8749   char *l;
8750   int size = AOP_SIZE (result);
8751
8752   if (size >= LSB + offr)
8753     {
8754       l = aopGet (left, LSB, FALSE, FALSE);
8755       MOVA (l);
8756       emitcode ("add", "a,acc");
8757       if (sameRegs (AOP (left), AOP (result)) &&
8758           size >= MSB16 + offr && offr != LSB)
8759         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8760       else
8761         aopPut (result, "a", LSB + offr);
8762     }
8763
8764   if (size >= MSB16 + offr)
8765     {
8766       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8767         {
8768           l = aopGet (left, MSB16, FALSE, FALSE);
8769           MOVA (l);
8770         }
8771       emitcode ("rlc", "a");
8772       if (sameRegs (AOP (left), AOP (result)) &&
8773           size >= MSB24 + offr && offr != LSB)
8774         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8775       else
8776         aopPut (result, "a", MSB16 + offr);
8777     }
8778
8779   if (size >= MSB24 + offr)
8780     {
8781       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8782         {
8783           l = aopGet (left, MSB24, FALSE, FALSE);
8784           MOVA (l);
8785         }
8786       emitcode ("rlc", "a");
8787       if (sameRegs (AOP (left), AOP (result)) &&
8788           size >= MSB32 + offr && offr != LSB)
8789         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8790       else
8791         aopPut (result, "a", MSB24 + offr);
8792     }
8793
8794   if (size > MSB32 + offr)
8795     {
8796       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8797         {
8798           l = aopGet (left, MSB32, FALSE, FALSE);
8799           MOVA (l);
8800         }
8801       emitcode ("rlc", "a");
8802       aopPut (result, "a", MSB32 + offr);
8803     }
8804   if (offr != LSB)
8805     aopPut (result, zero, LSB);
8806 }
8807
8808 /*-----------------------------------------------------------------*/
8809 /* genlshFour - shift four byte by a known amount != 0             */
8810 /*-----------------------------------------------------------------*/
8811 static void
8812 genlshFour (operand * result, operand * left, int shCount)
8813 {
8814   int size;
8815
8816   D (emitcode (";", "genlshFour"));
8817
8818   size = AOP_SIZE (result);
8819
8820   /* if shifting more that 3 bytes */
8821   if (shCount >= 24)
8822     {
8823       shCount -= 24;
8824       if (shCount)
8825         /* lowest order of left goes to the highest
8826            order of the destination */
8827         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8828       else
8829         movLeft2Result (left, LSB, result, MSB32, 0);
8830       aopPut (result, zero, LSB);
8831       aopPut (result, zero, MSB16);
8832       aopPut (result, zero, MSB24);
8833       return;
8834     }
8835
8836   /* more than two bytes */
8837   else if (shCount >= 16)
8838     {
8839       /* lower order two bytes goes to higher order two bytes */
8840       shCount -= 16;
8841       /* if some more remaining */
8842       if (shCount)
8843         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8844       else
8845         {
8846           movLeft2Result (left, MSB16, result, MSB32, 0);
8847           movLeft2Result (left, LSB, result, MSB24, 0);
8848         }
8849       aopPut (result, zero, MSB16);
8850       aopPut (result, zero, LSB);
8851       return;
8852     }
8853
8854   /* if more than 1 byte */
8855   else if (shCount >= 8)
8856     {
8857       /* lower order three bytes goes to higher order  three bytes */
8858       shCount -= 8;
8859       if (size == 2)
8860         {
8861           if (shCount)
8862             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8863           else
8864             movLeft2Result (left, LSB, result, MSB16, 0);
8865         }
8866       else
8867         {                       /* size = 4 */
8868           if (shCount == 0)
8869             {
8870               movLeft2Result (left, MSB24, result, MSB32, 0);
8871               movLeft2Result (left, MSB16, result, MSB24, 0);
8872               movLeft2Result (left, LSB, result, MSB16, 0);
8873               aopPut (result, zero, LSB);
8874             }
8875           else if (shCount == 1)
8876             shiftLLong (left, result, MSB16);
8877           else
8878             {
8879               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8880               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8881               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8882               aopPut (result, zero, LSB);
8883             }
8884         }
8885     }
8886
8887   /* 1 <= shCount <= 7 */
8888   else if (shCount <= 2)
8889     {
8890       shiftLLong (left, result, LSB);
8891       if (shCount == 2)
8892         shiftLLong (result, result, LSB);
8893     }
8894   /* 3 <= shCount <= 7, optimize */
8895   else
8896     {
8897       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8898       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8899       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8900     }
8901 }
8902
8903 /*-----------------------------------------------------------------*/
8904 /* genLeftShiftLiteral - left shifting by known count              */
8905 /*-----------------------------------------------------------------*/
8906 static void
8907 genLeftShiftLiteral (operand * left,
8908                      operand * right,
8909                      operand * result,
8910                      iCode * ic)
8911 {
8912   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8913   int size;
8914
8915   D (emitcode (";", "genLeftShiftLiteral"));
8916
8917   freeAsmop (right, NULL, ic, TRUE);
8918
8919   aopOp (left, ic, FALSE);
8920   aopOp (result, ic, FALSE);
8921
8922   size = getSize (operandType (result));
8923
8924 #if VIEW_SIZE
8925   emitcode ("; shift left ", "result %d, left %d", size,
8926             AOP_SIZE (left));
8927 #endif
8928
8929   /* I suppose that the left size >= result size */
8930   if (shCount == 0)
8931     {
8932       while (size--)
8933         {
8934           movLeft2Result (left, size, result, size, 0);
8935         }
8936     }
8937   else if (shCount >= (size * 8))
8938     {
8939       while (size--)
8940         {
8941           aopPut (result, zero, size);
8942         }
8943     }
8944   else
8945     {
8946       switch (size)
8947         {
8948         case 1:
8949           genlshOne (result, left, shCount);
8950           break;
8951
8952         case 2:
8953           genlshTwo (result, left, shCount);
8954           break;
8955
8956         case 4:
8957           genlshFour (result, left, shCount);
8958           break;
8959         default:
8960           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8961                   "*** ack! mystery literal shift!\n");
8962           break;
8963         }
8964     }
8965   freeAsmop (result, NULL, ic, TRUE);
8966   freeAsmop (left, NULL, ic, TRUE);
8967 }
8968
8969 /*-----------------------------------------------------------------*/
8970 /* genLeftShift - generates code for left shifting                 */
8971 /*-----------------------------------------------------------------*/
8972 static void
8973 genLeftShift (iCode * ic)
8974 {
8975   operand *left, *right, *result;
8976   int size, offset;
8977   char *l;
8978   symbol *tlbl, *tlbl1;
8979   bool pushedB;
8980
8981   D (emitcode (";", "genLeftShift"));
8982
8983   right = IC_RIGHT (ic);
8984   left = IC_LEFT (ic);
8985   result = IC_RESULT (ic);
8986
8987   aopOp (right, ic, FALSE);
8988
8989   /* if the shift count is known then do it
8990      as efficiently as possible */
8991   if (AOP_TYPE (right) == AOP_LIT)
8992     {
8993       genLeftShiftLiteral (left, right, result, ic);
8994       return;
8995     }
8996
8997   /* shift count is unknown then we have to form
8998      a loop get the loop count in B : Note: we take
8999      only the lower order byte since shifting
9000      more that 32 bits make no sense anyway, ( the
9001      largest size of an object can be only 32 bits ) */
9002
9003   pushedB = pushB ();
9004   MOVB (aopGet (right, 0, FALSE, FALSE));
9005   emitcode ("inc", "b");
9006   freeAsmop (right, NULL, ic, TRUE);
9007   aopOp (left, ic, FALSE);
9008   aopOp (result, ic, FALSE);
9009
9010   /* now move the left to the result if they are not the same */
9011   if (!sameRegs (AOP (left), AOP (result)) &&
9012       AOP_SIZE (result) > 1)
9013     {
9014
9015       size = AOP_SIZE (result);
9016       offset = 0;
9017       while (size--)
9018         {
9019           l = aopGet (left, offset, FALSE, TRUE);
9020           if (*l == '@' && (IS_AOP_PREG (result)))
9021             {
9022
9023               emitcode ("mov", "a,%s", l);
9024               aopPut (result, "a", offset);
9025             }
9026           else
9027             aopPut (result, l, offset);
9028           offset++;
9029         }
9030     }
9031
9032   tlbl = newiTempLabel (NULL);
9033   size = AOP_SIZE (result);
9034   offset = 0;
9035   tlbl1 = newiTempLabel (NULL);
9036
9037   /* if it is only one byte then */
9038   if (size == 1)
9039     {
9040       symbol *tlbl1 = newiTempLabel (NULL);
9041
9042       l = aopGet (left, 0, FALSE, FALSE);
9043       MOVA (l);
9044       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9045       emitLabel (tlbl);
9046       emitcode ("add", "a,acc");
9047       emitLabel (tlbl1);
9048       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9049       popB (pushedB);
9050       aopPut (result, "a", 0);
9051       goto release;
9052     }
9053
9054   reAdjustPreg (AOP (result));
9055
9056   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9057   emitLabel (tlbl);
9058   l = aopGet (result, offset, FALSE, FALSE);
9059   MOVA (l);
9060   emitcode ("add", "a,acc");
9061   aopPut (result, "a", offset++);
9062   while (--size)
9063     {
9064       l = aopGet (result, offset, FALSE, FALSE);
9065       MOVA (l);
9066       emitcode ("rlc", "a");
9067       aopPut (result, "a", offset++);
9068     }
9069   reAdjustPreg (AOP (result));
9070
9071   emitLabel (tlbl1);
9072   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9073   popB (pushedB);
9074 release:
9075   freeAsmop (result, NULL, ic, TRUE);
9076   freeAsmop (left, NULL, ic, TRUE);
9077 }
9078
9079 /*-----------------------------------------------------------------*/
9080 /* genrshOne - right shift a one byte quantity by known count      */
9081 /*-----------------------------------------------------------------*/
9082 static void
9083 genrshOne (operand * result, operand * left,
9084            int shCount, int sign)
9085 {
9086   D (emitcode (";", "genrshOne"));
9087
9088   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9089 }
9090
9091 /*-----------------------------------------------------------------*/
9092 /* genrshTwo - right shift two bytes by known amount != 0          */
9093 /*-----------------------------------------------------------------*/
9094 static void
9095 genrshTwo (operand * result, operand * left,
9096            int shCount, int sign)
9097 {
9098   D (emitcode (";", "genrshTwo"));
9099
9100   /* if shCount >= 8 */
9101   if (shCount >= 8)
9102     {
9103       shCount -= 8;
9104       if (shCount)
9105         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9106       else
9107         movLeft2Result (left, MSB16, result, LSB, sign);
9108       addSign (result, MSB16, sign);
9109     }
9110
9111   /*  1 <= shCount <= 7 */
9112   else
9113     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9114 }
9115
9116 /*-----------------------------------------------------------------*/
9117 /* shiftRLong - shift right one long from left to result           */
9118 /* offl = LSB or MSB16                                             */
9119 /*-----------------------------------------------------------------*/
9120 static void
9121 shiftRLong (operand * left, int offl,
9122             operand * result, int sign)
9123 {
9124   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9125
9126   if (overlapping && offl>1)
9127     {
9128       // we are in big trouble, but this shouldn't happen
9129       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9130     }
9131
9132   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9133
9134   if (offl==MSB16)
9135     {
9136       // shift is > 8
9137       if (sign)
9138         {
9139           emitcode ("rlc", "a");
9140           emitcode ("subb", "a,acc");
9141           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9142             {
9143               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9144             }
9145           else
9146             {
9147               aopPut (result, "a", MSB32);
9148               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9149             }
9150         }
9151       else
9152         {
9153           if (aopPutUsesAcc (result, zero, MSB32))
9154             {
9155               emitcode("xch", "a,b");
9156               aopPut (result, zero, MSB32);
9157               emitcode("xch", "a,b");
9158             }
9159           else
9160             {
9161               aopPut (result, zero, MSB32);
9162             }
9163         }
9164     }
9165
9166   if (!sign)
9167     {
9168       emitcode ("clr", "c");
9169     }
9170   else
9171     {
9172       emitcode ("mov", "c,acc.7");
9173     }
9174
9175   emitcode ("rrc", "a");
9176
9177   if (overlapping && offl==MSB16 &&
9178       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9179     {
9180       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9181     }
9182   else
9183     {
9184       aopPut (result, "a", MSB32 - offl);
9185       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9186     }
9187
9188   emitcode ("rrc", "a");
9189   if (overlapping && offl==MSB16 &&
9190       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9191     {
9192       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9193     }
9194   else
9195     {
9196       aopPut (result, "a", MSB24 - offl);
9197       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9198     }
9199
9200   emitcode ("rrc", "a");
9201   if (offl != LSB)
9202     {
9203       aopPut (result, "a", MSB16 - offl);
9204     }
9205   else
9206     {
9207       if (overlapping &&
9208           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9209         {
9210           xch_a_aopGet (left, LSB, FALSE, FALSE);
9211         }
9212       else
9213         {
9214           aopPut (result, "a", MSB16 - offl);
9215           MOVA (aopGet (left, LSB, FALSE, FALSE));
9216         }
9217       emitcode ("rrc", "a");
9218       aopPut (result, "a", LSB);
9219     }
9220 }
9221
9222 /*-----------------------------------------------------------------*/
9223 /* genrshFour - shift four byte by a known amount != 0             */
9224 /*-----------------------------------------------------------------*/
9225 static void
9226 genrshFour (operand * result, operand * left,
9227             int shCount, int sign)
9228 {
9229   D (emitcode (";", "genrshFour"));
9230
9231   /* if shifting more that 3 bytes */
9232   if (shCount >= 24)
9233     {
9234       shCount -= 24;
9235       if (shCount)
9236         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9237       else
9238         movLeft2Result (left, MSB32, result, LSB, sign);
9239       addSign (result, MSB16, sign);
9240     }
9241   else if (shCount >= 16)
9242     {
9243       shCount -= 16;
9244       if (shCount)
9245         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9246       else
9247         {
9248           movLeft2Result (left, MSB24, result, LSB, 0);
9249           movLeft2Result (left, MSB32, result, MSB16, sign);
9250         }
9251       addSign (result, MSB24, sign);
9252     }
9253   else if (shCount >= 8)
9254     {
9255       shCount -= 8;
9256       if (shCount == 1)
9257         {
9258           shiftRLong (left, MSB16, result, sign);
9259         }
9260       else if (shCount == 0)
9261         {
9262           movLeft2Result (left, MSB16, result, LSB, 0);
9263           movLeft2Result (left, MSB24, result, MSB16, 0);
9264           movLeft2Result (left, MSB32, result, MSB24, sign);
9265           addSign (result, MSB32, sign);
9266         }
9267       else
9268         {
9269           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9270           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9271           /* the last shift is signed */
9272           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9273           addSign (result, MSB32, sign);
9274         }
9275     }
9276   else
9277     {
9278       /* 1 <= shCount <= 7 */
9279       if (shCount <= 2)
9280         {
9281           shiftRLong (left, LSB, result, sign);
9282           if (shCount == 2)
9283             shiftRLong (result, LSB, result, sign);
9284         }
9285       else
9286         {
9287           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9288           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9289           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9290         }
9291     }
9292 }
9293
9294 /*-----------------------------------------------------------------*/
9295 /* genRightShiftLiteral - right shifting by known count            */
9296 /*-----------------------------------------------------------------*/
9297 static void
9298 genRightShiftLiteral (operand * left,
9299                       operand * right,
9300                       operand * result,
9301                       iCode * ic,
9302                       int sign)
9303 {
9304   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9305   int size;
9306
9307   D (emitcode (";", "genRightShiftLiteral"));
9308
9309   freeAsmop (right, NULL, ic, TRUE);
9310
9311   aopOp (left, ic, FALSE);
9312   aopOp (result, ic, FALSE);
9313
9314 #if VIEW_SIZE
9315   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9316             AOP_SIZE (left));
9317 #endif
9318
9319   size = getDataSize (left);
9320   /* test the LEFT size !!! */
9321
9322   /* I suppose that the left size >= result size */
9323   if (shCount == 0)
9324     {
9325       size = getDataSize (result);
9326       while (size--)
9327         movLeft2Result (left, size, result, size, 0);
9328     }
9329
9330   else if (shCount >= (size * 8))
9331     {
9332       if (sign)
9333         {
9334           /* get sign in acc.7 */
9335           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9336         }
9337       addSign (result, LSB, sign);
9338     }
9339   else
9340     {
9341       switch (size)
9342         {
9343         case 1:
9344           genrshOne (result, left, shCount, sign);
9345           break;
9346
9347         case 2:
9348           genrshTwo (result, left, shCount, sign);
9349           break;
9350
9351         case 4:
9352           genrshFour (result, left, shCount, sign);
9353           break;
9354         default:
9355           break;
9356         }
9357     }
9358   freeAsmop (result, NULL, ic, TRUE);
9359   freeAsmop (left, NULL, ic, TRUE);
9360 }
9361
9362 /*-----------------------------------------------------------------*/
9363 /* genSignedRightShift - right shift of signed number              */
9364 /*-----------------------------------------------------------------*/
9365 static void
9366 genSignedRightShift (iCode * ic)
9367 {
9368   operand *right, *left, *result;
9369   int size, offset;
9370   char *l;
9371   symbol *tlbl, *tlbl1;
9372   bool pushedB;
9373
9374   D (emitcode (";", "genSignedRightShift"));
9375
9376   /* we do it the hard way put the shift count in b
9377      and loop thru preserving the sign */
9378
9379   right = IC_RIGHT (ic);
9380   left = IC_LEFT (ic);
9381   result = IC_RESULT (ic);
9382
9383   aopOp (right, ic, FALSE);
9384
9385
9386   if (AOP_TYPE (right) == AOP_LIT)
9387     {
9388       genRightShiftLiteral (left, right, result, ic, 1);
9389       return;
9390     }
9391   /* shift count is unknown then we have to form
9392      a loop get the loop count in B : Note: we take
9393      only the lower order byte since shifting
9394      more that 32 bits make no sense anyway, ( the
9395      largest size of an object can be only 32 bits ) */
9396
9397   pushedB = pushB ();
9398   MOVB (aopGet (right, 0, FALSE, FALSE));
9399   emitcode ("inc", "b");
9400   freeAsmop (right, NULL, ic, TRUE);
9401   aopOp (left, ic, FALSE);
9402   aopOp (result, ic, FALSE);
9403
9404   /* now move the left to the result if they are not the
9405      same */
9406   if (!sameRegs (AOP (left), AOP (result)) &&
9407       AOP_SIZE (result) > 1)
9408     {
9409
9410       size = AOP_SIZE (result);
9411       offset = 0;
9412       while (size--)
9413         {
9414           l = aopGet (left, offset, FALSE, TRUE);
9415           if (*l == '@' && IS_AOP_PREG (result))
9416             {
9417
9418               emitcode ("mov", "a,%s", l);
9419               aopPut (result, "a", offset);
9420             }
9421           else
9422             aopPut (result, l, offset);
9423           offset++;
9424         }
9425     }
9426
9427   /* mov the highest order bit to OVR */
9428   tlbl = newiTempLabel (NULL);
9429   tlbl1 = newiTempLabel (NULL);
9430
9431   size = AOP_SIZE (result);
9432   offset = size - 1;
9433   MOVA (aopGet (left, offset, FALSE, FALSE));
9434   emitcode ("rlc", "a");
9435   emitcode ("mov", "ov,c");
9436   /* if it is only one byte then */
9437   if (size == 1)
9438     {
9439       l = aopGet (left, 0, FALSE, FALSE);
9440       MOVA (l);
9441       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9442       emitLabel (tlbl);
9443       emitcode ("mov", "c,ov");
9444       emitcode ("rrc", "a");
9445       emitLabel (tlbl1);
9446       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9447       popB (pushedB);
9448       aopPut (result, "a", 0);
9449       goto release;
9450     }
9451
9452   reAdjustPreg (AOP (result));
9453   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9454   emitLabel (tlbl);
9455   emitcode ("mov", "c,ov");
9456   while (size--)
9457     {
9458       l = aopGet (result, offset, FALSE, FALSE);
9459       MOVA (l);
9460       emitcode ("rrc", "a");
9461       aopPut (result, "a", offset--);
9462     }
9463   reAdjustPreg (AOP (result));
9464   emitLabel (tlbl1);
9465   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9466   popB (pushedB);
9467
9468 release:
9469   freeAsmop (result, NULL, ic, TRUE);
9470   freeAsmop (left, NULL, ic, TRUE);
9471 }
9472
9473 /*-----------------------------------------------------------------*/
9474 /* genRightShift - generate code for right shifting                */
9475 /*-----------------------------------------------------------------*/
9476 static void
9477 genRightShift (iCode * ic)
9478 {
9479   operand *right, *left, *result;
9480   sym_link *letype;
9481   int size, offset;
9482   char *l;
9483   symbol *tlbl, *tlbl1;
9484   bool pushedB;
9485
9486   D (emitcode (";", "genRightShift"));
9487
9488   /* if signed then we do it the hard way preserve the
9489      sign bit moving it inwards */
9490   letype = getSpec (operandType (IC_LEFT (ic)));
9491
9492   if (!SPEC_USIGN (letype))
9493     {
9494       genSignedRightShift (ic);
9495       return;
9496     }
9497
9498   /* signed & unsigned types are treated the same : i.e. the
9499      signed is NOT propagated inwards : quoting from the
9500      ANSI - standard : "for E1 >> E2, is equivalent to division
9501      by 2**E2 if unsigned or if it has a non-negative value,
9502      otherwise the result is implementation defined ", MY definition
9503      is that the sign does not get propagated */
9504
9505   right = IC_RIGHT (ic);
9506   left = IC_LEFT (ic);
9507   result = IC_RESULT (ic);
9508
9509   aopOp (right, ic, FALSE);
9510
9511   /* if the shift count is known then do it
9512      as efficiently as possible */
9513   if (AOP_TYPE (right) == AOP_LIT)
9514     {
9515       genRightShiftLiteral (left, right, result, ic, 0);
9516       return;
9517     }
9518
9519   /* shift count is unknown then we have to form
9520      a loop get the loop count in B : Note: we take
9521      only the lower order byte since shifting
9522      more that 32 bits make no sense anyway, ( the
9523      largest size of an object can be only 32 bits ) */
9524
9525   pushedB = pushB ();
9526   MOVB (aopGet (right, 0, FALSE, FALSE));
9527   emitcode ("inc", "b");
9528   freeAsmop (right, NULL, ic, TRUE);
9529   aopOp (left, ic, FALSE);
9530   aopOp (result, ic, FALSE);
9531
9532   /* now move the left to the result if they are not the
9533      same */
9534   if (!sameRegs (AOP (left), AOP (result)) &&
9535       AOP_SIZE (result) > 1)
9536     {
9537       size = AOP_SIZE (result);
9538       offset = 0;
9539       while (size--)
9540         {
9541           l = aopGet (left, offset, FALSE, TRUE);
9542           if (*l == '@' && IS_AOP_PREG (result))
9543             {
9544
9545               emitcode ("mov", "a,%s", l);
9546               aopPut (result, "a", offset);
9547             }
9548           else
9549             aopPut (result, l, offset);
9550           offset++;
9551         }
9552     }
9553
9554   tlbl = newiTempLabel (NULL);
9555   tlbl1 = newiTempLabel (NULL);
9556   size = AOP_SIZE (result);
9557   offset = size - 1;
9558
9559   /* if it is only one byte then */
9560   if (size == 1)
9561     {
9562       l = aopGet (left, 0, FALSE, FALSE);
9563       MOVA (l);
9564       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9565       emitLabel (tlbl);
9566       CLRC;
9567       emitcode ("rrc", "a");
9568       emitLabel (tlbl1);
9569       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9570       popB (pushedB);
9571       aopPut (result, "a", 0);
9572       goto release;
9573     }
9574
9575   reAdjustPreg (AOP (result));
9576   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9577   emitLabel (tlbl);
9578   CLRC;
9579   while (size--)
9580     {
9581       l = aopGet (result, offset, FALSE, FALSE);
9582       MOVA (l);
9583       emitcode ("rrc", "a");
9584       aopPut (result, "a", offset--);
9585     }
9586   reAdjustPreg (AOP (result));
9587
9588   emitLabel (tlbl1);
9589   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9590   popB (pushedB);
9591
9592 release:
9593   freeAsmop (result, NULL, ic, TRUE);
9594   freeAsmop (left, NULL, ic, TRUE);
9595 }
9596
9597 /*-----------------------------------------------------------------*/
9598 /* emitPtrByteGet - emits code to get a byte into A through a      */
9599 /*                  pointer register (R0, R1, or DPTR). The        */
9600 /*                  original value of A can be preserved in B.     */
9601 /*-----------------------------------------------------------------*/
9602 static void
9603 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9604 {
9605   switch (p_type)
9606     {
9607     case IPOINTER:
9608     case POINTER:
9609       if (preserveAinB)
9610         emitcode ("mov", "b,a");
9611       emitcode ("mov", "a,@%s", rname);
9612       break;
9613
9614     case PPOINTER:
9615       if (preserveAinB)
9616         emitcode ("mov", "b,a");
9617       emitcode ("movx", "a,@%s", rname);
9618       break;
9619
9620     case FPOINTER:
9621       if (preserveAinB)
9622         emitcode ("mov", "b,a");
9623       emitcode ("movx", "a,@dptr");
9624       break;
9625
9626     case CPOINTER:
9627       if (preserveAinB)
9628         emitcode ("mov", "b,a");
9629       emitcode ("clr", "a");
9630       emitcode ("movc", "a,@a+dptr");
9631       break;
9632
9633     case GPOINTER:
9634       if (preserveAinB)
9635         {
9636           emitcode ("push", "b");
9637           emitcode ("push", "acc");
9638         }
9639       emitcode ("lcall", "__gptrget");
9640       if (preserveAinB)
9641         emitcode ("pop", "b");
9642       break;
9643     }
9644 }
9645
9646 /*-----------------------------------------------------------------*/
9647 /* emitPtrByteSet - emits code to set a byte from src through a    */
9648 /*                  pointer register (R0, R1, or DPTR).            */
9649 /*-----------------------------------------------------------------*/
9650 static void
9651 emitPtrByteSet (char *rname, int p_type, char *src)
9652 {
9653   switch (p_type)
9654     {
9655     case IPOINTER:
9656     case POINTER:
9657       if (*src=='@')
9658         {
9659           MOVA (src);
9660           emitcode ("mov", "@%s,a", rname);
9661         }
9662       else
9663         emitcode ("mov", "@%s,%s", rname, src);
9664       break;
9665
9666     case PPOINTER:
9667       MOVA (src);
9668       emitcode ("movx", "@%s,a", rname);
9669       break;
9670
9671     case FPOINTER:
9672       MOVA (src);
9673       emitcode ("movx", "@dptr,a");
9674       break;
9675
9676     case GPOINTER:
9677       MOVA (src);
9678       emitcode ("lcall", "__gptrput");
9679       break;
9680     }
9681 }
9682
9683 /*-----------------------------------------------------------------*/
9684 /* genUnpackBits - generates code for unpacking bits               */
9685 /*-----------------------------------------------------------------*/
9686 static void
9687 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9688 {
9689   int offset = 0;       /* result byte offset */
9690   int rsize;            /* result size */
9691   int rlen = 0;         /* remaining bitfield length */
9692   sym_link *etype;      /* bitfield type information */
9693   int blen;             /* bitfield length */
9694   int bstr;             /* bitfield starting bit within byte */
9695   char buffer[10];
9696
9697   D(emitcode (";     genUnpackBits",""));
9698
9699   etype = getSpec (operandType (result));
9700   rsize = getSize (operandType (result));
9701   blen = SPEC_BLEN (etype);
9702   bstr = SPEC_BSTR (etype);
9703
9704   if (ifx && blen <= 8)
9705     {
9706       emitPtrByteGet (rname, ptype, FALSE);
9707       if (blen == 1)
9708         {
9709           SNPRINTF (buffer, sizeof(buffer),
9710                     "acc.%d", bstr);
9711           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9712         }
9713       else
9714         {
9715           if (blen < 8)
9716             emitcode ("anl", "a,#0x%02x",
9717                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9718           genIfxJump (ifx, "a", NULL, NULL, NULL);
9719         }
9720       return;
9721     }
9722   wassert (!ifx);
9723
9724   /* If the bitfield length is less than a byte */
9725   if (blen < 8)
9726     {
9727       emitPtrByteGet (rname, ptype, FALSE);
9728       AccRol (8 - bstr);
9729       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9730       if (!SPEC_USIGN (etype))
9731         {
9732           /* signed bitfield */
9733           symbol *tlbl = newiTempLabel (NULL);
9734
9735           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9736           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9737           emitLabel (tlbl);
9738         }
9739       aopPut (result, "a", offset++);
9740       goto finish;
9741     }
9742
9743   /* Bit field did not fit in a byte. Copy all
9744      but the partial byte at the end.  */
9745   for (rlen=blen;rlen>=8;rlen-=8)
9746     {
9747       emitPtrByteGet (rname, ptype, FALSE);
9748       aopPut (result, "a", offset++);
9749       if (rlen>8)
9750         emitcode ("inc", "%s", rname);
9751     }
9752
9753   /* Handle the partial byte at the end */
9754   if (rlen)
9755     {
9756       emitPtrByteGet (rname, ptype, FALSE);
9757       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9758       if (!SPEC_USIGN (etype))
9759         {
9760           /* signed bitfield */
9761           symbol *tlbl = newiTempLabel (NULL);
9762
9763           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9764           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9765           emitLabel (tlbl);
9766         }
9767       aopPut (result, "a", offset++);
9768     }
9769
9770 finish:
9771   if (offset < rsize)
9772     {
9773       char *source;
9774
9775       if (SPEC_USIGN (etype))
9776         source = zero;
9777       else
9778         {
9779           /* signed bitfield: sign extension with 0x00 or 0xff */
9780           emitcode ("rlc", "a");
9781           emitcode ("subb", "a,acc");
9782
9783           source = "a";
9784         }
9785       rsize -= offset;
9786       while (rsize--)
9787         aopPut (result, source, offset++);
9788     }
9789 }
9790
9791
9792 /*-----------------------------------------------------------------*/
9793 /* genDataPointerGet - generates code when ptr offset is known     */
9794 /*-----------------------------------------------------------------*/
9795 static void
9796 genDataPointerGet (operand * left,
9797                    operand * result,
9798                    iCode * ic)
9799 {
9800   char *l;
9801   char buffer[256];
9802   int size, offset = 0;
9803
9804   D (emitcode (";", "genDataPointerGet"));
9805
9806   aopOp (result, ic, TRUE);
9807
9808   /* get the string representation of the name */
9809   l = aopGet (left, 0, FALSE, TRUE);
9810   l++; // remove #
9811   size = AOP_SIZE (result);
9812   while (size--)
9813     {
9814       if (offset)
9815         {
9816           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9817         }
9818       else
9819         {
9820           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9821         }
9822       aopPut (result, buffer, offset++);
9823     }
9824
9825   freeAsmop (result, NULL, ic, TRUE);
9826   freeAsmop (left, NULL, ic, TRUE);
9827 }
9828
9829 /*-----------------------------------------------------------------*/
9830 /* genNearPointerGet - emitcode for near pointer fetch             */
9831 /*-----------------------------------------------------------------*/
9832 static void
9833 genNearPointerGet (operand * left,
9834                    operand * result,
9835                    iCode * ic,
9836                    iCode * pi,
9837                    iCode * ifx)
9838 {
9839   asmop *aop = NULL;
9840   regs *preg = NULL;
9841   char *rname;
9842   sym_link *rtype, *retype;
9843   sym_link *ltype = operandType (left);
9844   char buffer[80];
9845
9846   D (emitcode (";", "genNearPointerGet"));
9847
9848   rtype = operandType (result);
9849   retype = getSpec (rtype);
9850
9851   aopOp (left, ic, FALSE);
9852
9853   /* if left is rematerialisable and
9854      result is not bitfield variable type and
9855      the left is pointer to data space i.e
9856      lower 128 bytes of space */
9857   if (AOP_TYPE (left) == AOP_IMMD &&
9858       !IS_BITFIELD (retype) &&
9859       DCL_TYPE (ltype) == POINTER)
9860     {
9861       genDataPointerGet (left, result, ic);
9862       return;
9863     }
9864
9865  /* if the value is already in a pointer register
9866      then don't need anything more */
9867   if (!AOP_INPREG (AOP (left)))
9868     {
9869       if (IS_AOP_PREG (left))
9870         {
9871           // Aha, it is a pointer, just in disguise.
9872           rname = aopGet (left, 0, FALSE, FALSE);
9873           if (*rname != '@')
9874             {
9875               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9876                       __FILE__, __LINE__);
9877             }
9878           else
9879             {
9880               // Expected case.
9881               emitcode ("mov", "a%s,%s", rname + 1, rname);
9882               rname++;  // skip the '@'.
9883             }
9884         }
9885       else
9886         {
9887           /* otherwise get a free pointer register */
9888           aop = newAsmop (0);
9889           preg = getFreePtr (ic, &aop, FALSE);
9890           emitcode ("mov", "%s,%s",
9891                     preg->name,
9892                     aopGet (left, 0, FALSE, TRUE));
9893           rname = preg->name;
9894         }
9895     }
9896   else
9897     rname = aopGet (left, 0, FALSE, FALSE);
9898
9899   //aopOp (result, ic, FALSE);
9900   aopOp (result, ic, result?TRUE:FALSE);
9901
9902   /* if bitfield then unpack the bits */
9903   if (IS_BITFIELD (retype))
9904     genUnpackBits (result, rname, POINTER, ifx);
9905   else
9906     {
9907       /* we have can just get the values */
9908       int size = AOP_SIZE (result);
9909       int offset = 0;
9910
9911       while (size--)
9912         {
9913           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9914             {
9915
9916               emitcode ("mov", "a,@%s", rname);
9917               if (!ifx)
9918                 aopPut (result, "a", offset);
9919             }
9920           else
9921             {
9922               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9923               aopPut (result, buffer, offset);
9924             }
9925           offset++;
9926           if (size || pi)
9927             emitcode ("inc", "%s", rname);
9928         }
9929     }
9930
9931   /* now some housekeeping stuff */
9932   if (aop)       /* we had to allocate for this iCode */
9933     {
9934       if (pi) { /* post increment present */
9935         aopPut (left, rname, 0);
9936       }
9937       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9938     }
9939   else
9940     {
9941       /* we did not allocate which means left
9942          already in a pointer register, then
9943          if size > 0 && this could be used again
9944          we have to point it back to where it
9945          belongs */
9946       if ((AOP_SIZE (result) > 1 &&
9947            !OP_SYMBOL (left)->remat &&
9948            (OP_SYMBOL (left)->liveTo > ic->seq ||
9949             ic->depth)) &&
9950           !pi)
9951         {
9952           int size = AOP_SIZE (result) - 1;
9953           while (size--)
9954             emitcode ("dec", "%s", rname);
9955         }
9956     }
9957
9958   if (ifx && !ifx->generated)
9959     {
9960       genIfxJump (ifx, "a", left, NULL, result);
9961     }
9962
9963   /* done */
9964   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9965   freeAsmop (left, NULL, ic, TRUE);
9966   if (pi) pi->generated = 1;
9967 }
9968
9969 /*-----------------------------------------------------------------*/
9970 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9971 /*-----------------------------------------------------------------*/
9972 static void
9973 genPagedPointerGet (operand * left,
9974                     operand * result,
9975                     iCode * ic,
9976                     iCode *pi,
9977                     iCode *ifx)
9978 {
9979   asmop *aop = NULL;
9980   regs *preg = NULL;
9981   char *rname;
9982   sym_link *rtype, *retype;
9983
9984   D (emitcode (";", "genPagedPointerGet"));
9985
9986   rtype = operandType (result);
9987   retype = getSpec (rtype);
9988
9989   aopOp (left, ic, FALSE);
9990
9991   /* if the value is already in a pointer register
9992      then don't need anything more */
9993   if (!AOP_INPREG (AOP (left)))
9994     {
9995       /* otherwise get a free pointer register */
9996       aop = newAsmop (0);
9997       preg = getFreePtr (ic, &aop, FALSE);
9998       emitcode ("mov", "%s,%s",
9999                 preg->name,
10000                 aopGet (left, 0, FALSE, TRUE));
10001       rname = preg->name;
10002     }
10003   else
10004     rname = aopGet (left, 0, FALSE, FALSE);
10005
10006   aopOp (result, ic, FALSE);
10007
10008   /* if bitfield then unpack the bits */
10009   if (IS_BITFIELD (retype))
10010     genUnpackBits (result, rname, PPOINTER, ifx);
10011   else
10012     {
10013       /* we have can just get the values */
10014       int size = AOP_SIZE (result);
10015       int offset = 0;
10016
10017       while (size--)
10018         {
10019
10020           emitcode ("movx", "a,@%s", rname);
10021           if (!ifx)
10022             aopPut (result, "a", offset);
10023
10024           offset++;
10025
10026           if (size || pi)
10027             emitcode ("inc", "%s", rname);
10028         }
10029     }
10030
10031   /* now some housekeeping stuff */
10032   if (aop) /* we had to allocate for this iCode */
10033     {
10034       if (pi)
10035         aopPut (left, rname, 0);
10036       freeAsmop (NULL, aop, ic, TRUE);
10037     }
10038   else
10039     {
10040       /* we did not allocate which means left
10041          already in a pointer register, then
10042          if size > 0 && this could be used again
10043          we have to point it back to where it
10044          belongs */
10045       if ((AOP_SIZE (result) > 1 &&
10046            !OP_SYMBOL (left)->remat &&
10047            (OP_SYMBOL (left)->liveTo > ic->seq ||
10048             ic->depth)) &&
10049           !pi)
10050         {
10051           int size = AOP_SIZE (result) - 1;
10052           while (size--)
10053             emitcode ("dec", "%s", rname);
10054         }
10055     }
10056
10057   if (ifx && !ifx->generated)
10058     {
10059       genIfxJump (ifx, "a", left, NULL, result);
10060     }
10061
10062   /* done */
10063   freeAsmop (result, NULL, ic, TRUE);
10064   freeAsmop (left, NULL, ic, TRUE);
10065   if (pi) pi->generated = 1;
10066 }
10067
10068 /*--------------------------------------------------------------------*/
10069 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10070 /*--------------------------------------------------------------------*/
10071 static void
10072 loadDptrFromOperand (operand *op, bool loadBToo)
10073 {
10074   if (AOP_TYPE (op) != AOP_STR)
10075     {
10076       /* if this is rematerializable */
10077       if (AOP_TYPE (op) == AOP_IMMD)
10078         {
10079           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10080           if (loadBToo)
10081             {
10082               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10083                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10084               else
10085                 {
10086                   wassertl(FALSE, "need pointerCode");
10087                   emitcode ("", "; mov b,???");
10088                   /* genPointerGet and genPointerSet originally did different
10089                   ** things for this case. Both seem wrong.
10090                   ** from genPointerGet:
10091                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10092                   ** from genPointerSet:
10093                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10094                   */
10095                 }
10096             }
10097         }
10098       else if (AOP_TYPE (op) == AOP_DPTR)
10099         {
10100           if (loadBToo)
10101             {
10102               MOVA (aopGet (op, 0, FALSE, FALSE));
10103               emitcode ("push", "acc");
10104               MOVA (aopGet (op, 1, FALSE, FALSE));
10105               emitcode ("push", "acc");
10106               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10107               emitcode ("pop", "dph");
10108               emitcode ("pop", "dpl");
10109             }
10110           else
10111             {
10112               MOVA (aopGet (op, 0, FALSE, FALSE));
10113               emitcode ("push", "acc");
10114               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10115               emitcode ("pop", "dpl");
10116             }
10117         }
10118       else
10119         {                       /* we need to get it byte by byte */
10120           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10121           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10122           if (loadBToo)
10123             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10124         }
10125     }
10126 }
10127
10128 /*-----------------------------------------------------------------*/
10129 /* genFarPointerGet - get value from far space                     */
10130 /*-----------------------------------------------------------------*/
10131 static void
10132 genFarPointerGet (operand * left,
10133                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10134 {
10135   int size, offset;
10136   sym_link *retype = getSpec (operandType (result));
10137
10138   D (emitcode (";", "genFarPointerGet"));
10139
10140   aopOp (left, ic, FALSE);
10141   loadDptrFromOperand (left, FALSE);
10142
10143   /* so dptr now contains the address */
10144   aopOp (result, ic, FALSE);
10145
10146   /* if bit then unpack */
10147   if (IS_BITFIELD (retype))
10148     genUnpackBits (result, "dptr", FPOINTER, ifx);
10149   else
10150     {
10151       size = AOP_SIZE (result);
10152       offset = 0;
10153
10154       while (size--)
10155         {
10156           emitcode ("movx", "a,@dptr");
10157           if (!ifx)
10158             aopPut (result, "a", offset++);
10159           if (size || pi)
10160             emitcode ("inc", "dptr");
10161         }
10162     }
10163
10164   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10165     {
10166       aopPut (left, "dpl", 0);
10167       aopPut (left, "dph", 1);
10168       pi->generated = 1;
10169     }
10170
10171   if (ifx && !ifx->generated)
10172     {
10173       genIfxJump (ifx, "a", left, NULL, result);
10174     }
10175
10176   freeAsmop (result, NULL, ic, TRUE);
10177   freeAsmop (left, NULL, ic, TRUE);
10178 }
10179
10180 /*-----------------------------------------------------------------*/
10181 /* genCodePointerGet - get value from code space                   */
10182 /*-----------------------------------------------------------------*/
10183 static void
10184 genCodePointerGet (operand * left,
10185                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10186 {
10187   int size, offset;
10188   sym_link *retype = getSpec (operandType (result));
10189
10190   D (emitcode (";", "genCodePointerGet"));
10191
10192   aopOp (left, ic, FALSE);
10193   loadDptrFromOperand (left, FALSE);
10194
10195   /* so dptr now contains the address */
10196   aopOp (result, ic, FALSE);
10197
10198   /* if bit then unpack */
10199   if (IS_BITFIELD (retype))
10200     genUnpackBits (result, "dptr", CPOINTER, ifx);
10201   else
10202     {
10203       size = AOP_SIZE (result);
10204       offset = 0;
10205
10206       while (size--)
10207         {
10208           emitcode ("clr", "a");
10209           emitcode ("movc", "a,@a+dptr");
10210           if (!ifx)
10211             aopPut (result, "a", offset++);
10212           if (size || pi)
10213             emitcode ("inc", "dptr");
10214         }
10215     }
10216
10217   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10218     {
10219       aopPut (left, "dpl", 0);
10220       aopPut (left, "dph", 1);
10221       pi->generated = 1;
10222     }
10223
10224   if (ifx && !ifx->generated)
10225     {
10226       genIfxJump (ifx, "a", left, NULL, result);
10227     }
10228
10229   freeAsmop (result, NULL, ic, TRUE);
10230   freeAsmop (left, NULL, ic, TRUE);
10231 }
10232
10233 /*-----------------------------------------------------------------*/
10234 /* genGenPointerGet - get value from generic pointer space         */
10235 /*-----------------------------------------------------------------*/
10236 static void
10237 genGenPointerGet (operand * left,
10238                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10239 {
10240   int size, offset;
10241   sym_link *retype = getSpec (operandType (result));
10242
10243   D (emitcode (";", "genGenPointerGet"));
10244
10245   aopOp (left, ic, FALSE);
10246   loadDptrFromOperand (left, TRUE);
10247
10248   /* so dptr now contains the address */
10249   aopOp (result, ic, FALSE);
10250
10251   /* if bit then unpack */
10252   if (IS_BITFIELD (retype))
10253     {
10254       genUnpackBits (result, "dptr", GPOINTER, ifx);
10255     }
10256   else
10257     {
10258       size = AOP_SIZE (result);
10259       offset = 0;
10260
10261       while (size--)
10262         {
10263           emitcode ("lcall", "__gptrget");
10264           if (!ifx)
10265             aopPut (result, "a", offset++);
10266           if (size || pi)
10267             emitcode ("inc", "dptr");
10268         }
10269     }
10270
10271   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10272     {
10273       aopPut (left, "dpl", 0);
10274       aopPut (left, "dph", 1);
10275       pi->generated = 1;
10276     }
10277
10278   if (ifx && !ifx->generated)
10279     {
10280       genIfxJump (ifx, "a", left, NULL, result);
10281     }
10282
10283   freeAsmop (result, NULL, ic, TRUE);
10284   freeAsmop (left, NULL, ic, TRUE);
10285 }
10286
10287 /*-----------------------------------------------------------------*/
10288 /* genPointerGet - generate code for pointer get                   */
10289 /*-----------------------------------------------------------------*/
10290 static void
10291 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10292 {
10293   operand *left, *result;
10294   sym_link *type, *etype;
10295   int p_type;
10296
10297   D (emitcode (";", "genPointerGet"));
10298
10299   left = IC_LEFT (ic);
10300   result = IC_RESULT (ic);
10301
10302   if (getSize (operandType (result))>1)
10303     ifx = NULL;
10304
10305   /* depending on the type of pointer we need to
10306      move it to the correct pointer register */
10307   type = operandType (left);
10308   etype = getSpec (type);
10309   /* if left is of type of pointer then it is simple */
10310   if (IS_PTR (type) && !IS_FUNC (type->next))
10311     p_type = DCL_TYPE (type);
10312   else
10313     {
10314       /* we have to go by the storage class */
10315       p_type = PTR_TYPE (SPEC_OCLS (etype));
10316     }
10317
10318   /* special case when cast remat */
10319   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10320       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10321     {
10322       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10323       type = operandType (left);
10324       p_type = DCL_TYPE (type);
10325     }
10326   /* now that we have the pointer type we assign
10327      the pointer values */
10328   switch (p_type)
10329     {
10330
10331     case POINTER:
10332     case IPOINTER:
10333       genNearPointerGet (left, result, ic, pi, ifx);
10334       break;
10335
10336     case PPOINTER:
10337       genPagedPointerGet (left, result, ic, pi, ifx);
10338       break;
10339
10340     case FPOINTER:
10341       genFarPointerGet (left, result, ic, pi, ifx);
10342       break;
10343
10344     case CPOINTER:
10345       genCodePointerGet (left, result, ic, pi, ifx);
10346       break;
10347
10348     case GPOINTER:
10349       genGenPointerGet (left, result, ic, pi, ifx);
10350       break;
10351     }
10352 }
10353
10354
10355 /*-----------------------------------------------------------------*/
10356 /* genPackBits - generates code for packed bit storage             */
10357 /*-----------------------------------------------------------------*/
10358 static void
10359 genPackBits (sym_link * etype,
10360              operand * right,
10361              char *rname, int p_type)
10362 {
10363   int offset = 0;       /* source byte offset */
10364   int rlen = 0;         /* remaining bitfield length */
10365   int blen;             /* bitfield length */
10366   int bstr;             /* bitfield starting bit within byte */
10367   int litval;           /* source literal value (if AOP_LIT) */
10368   unsigned char mask;   /* bitmask within current byte */
10369
10370   D(emitcode (";     genPackBits",""));
10371
10372   blen = SPEC_BLEN (etype);
10373   bstr = SPEC_BSTR (etype);
10374
10375   /* If the bitfield length is less than a byte */
10376   if (blen < 8)
10377     {
10378       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10379               (unsigned char) (0xFF >> (8 - bstr)));
10380
10381       if (AOP_TYPE (right) == AOP_LIT)
10382         {
10383           /* Case with a bitfield length <8 and literal source
10384           */
10385           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10386           litval <<= bstr;
10387           litval &= (~mask) & 0xff;
10388           emitPtrByteGet (rname, p_type, FALSE);
10389           if ((mask|litval)!=0xff)
10390             emitcode ("anl","a,#0x%02x", mask);
10391           if (litval)
10392             emitcode ("orl","a,#0x%02x", litval);
10393         }
10394       else
10395         {
10396           if ((blen==1) && (p_type!=GPOINTER))
10397             {
10398               /* Case with a bitfield length == 1 and no generic pointer
10399               */
10400               if (AOP_TYPE (right) == AOP_CRY)
10401                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10402               else
10403                 {
10404                   MOVA (aopGet (right, 0, FALSE, FALSE));
10405                   emitcode ("rrc","a");
10406                 }
10407               emitPtrByteGet (rname, p_type, FALSE);
10408               emitcode ("mov","acc.%d,c",bstr);
10409             }
10410           else
10411             {
10412               bool pushedB;
10413               /* Case with a bitfield length < 8 and arbitrary source
10414               */
10415               MOVA (aopGet (right, 0, FALSE, FALSE));
10416               /* shift and mask source value */
10417               AccLsh (bstr);
10418               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10419
10420               pushedB = pushB ();
10421               /* transfer A to B and get next byte */
10422               emitPtrByteGet (rname, p_type, TRUE);
10423
10424               emitcode ("anl", "a,#0x%02x", mask);
10425               emitcode ("orl", "a,b");
10426               if (p_type == GPOINTER)
10427                 emitcode ("pop", "b");
10428
10429               popB (pushedB);
10430            }
10431         }
10432
10433       emitPtrByteSet (rname, p_type, "a");
10434       return;
10435     }
10436
10437   /* Bit length is greater than 7 bits. In this case, copy  */
10438   /* all except the partial byte at the end                 */
10439   for (rlen=blen;rlen>=8;rlen-=8)
10440     {
10441       emitPtrByteSet (rname, p_type,
10442                       aopGet (right, offset++, FALSE, TRUE) );
10443       if (rlen>8)
10444         emitcode ("inc", "%s", rname);
10445     }
10446
10447   /* If there was a partial byte at the end */
10448   if (rlen)
10449     {
10450       mask = (((unsigned char) -1 << rlen) & 0xff);
10451
10452       if (AOP_TYPE (right) == AOP_LIT)
10453         {
10454           /* Case with partial byte and literal source
10455           */
10456           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10457           litval >>= (blen-rlen);
10458           litval &= (~mask) & 0xff;
10459           emitPtrByteGet (rname, p_type, FALSE);
10460           if ((mask|litval)!=0xff)
10461             emitcode ("anl","a,#0x%02x", mask);
10462           if (litval)
10463             emitcode ("orl","a,#0x%02x", litval);
10464         }
10465       else
10466         {
10467           bool pushedB;
10468           /* Case with partial byte and arbitrary source
10469           */
10470           MOVA (aopGet (right, offset++, FALSE, FALSE));
10471           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10472
10473           pushedB = pushB ();
10474           /* transfer A to B and get next byte */
10475           emitPtrByteGet (rname, p_type, TRUE);
10476
10477           emitcode ("anl", "a,#0x%02x", mask);
10478           emitcode ("orl", "a,b");
10479           if (p_type == GPOINTER)
10480             emitcode ("pop", "b");
10481
10482           popB (pushedB);
10483         }
10484       emitPtrByteSet (rname, p_type, "a");
10485     }
10486 }
10487
10488
10489 /*-----------------------------------------------------------------*/
10490 /* genDataPointerSet - remat pointer to data space                 */
10491 /*-----------------------------------------------------------------*/
10492 static void
10493 genDataPointerSet (operand * right,
10494                    operand * result,
10495                    iCode * ic)
10496 {
10497   int size, offset = 0;
10498   char *l, buffer[256];
10499
10500   D (emitcode (";", "genDataPointerSet"));
10501
10502   aopOp (right, ic, FALSE);
10503
10504   l = aopGet (result, 0, FALSE, TRUE);
10505   l++; //remove #
10506   size = AOP_SIZE (right);
10507   while (size--)
10508     {
10509       if (offset)
10510         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10511       else
10512         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10513       emitcode ("mov", "%s,%s", buffer,
10514                 aopGet (right, offset++, FALSE, FALSE));
10515     }
10516
10517   freeAsmop (result, NULL, ic, TRUE);
10518   freeAsmop (right, NULL, ic, TRUE);
10519 }
10520
10521 /*-----------------------------------------------------------------*/
10522 /* genNearPointerSet - emitcode for near pointer put                */
10523 /*-----------------------------------------------------------------*/
10524 static void
10525 genNearPointerSet (operand * right,
10526                    operand * result,
10527                    iCode * ic,
10528                    iCode * pi)
10529 {
10530   asmop *aop = NULL;
10531   regs *preg = NULL;
10532   char *rname, *l;
10533   sym_link *retype, *letype;
10534   sym_link *ptype = operandType (result);
10535
10536   D (emitcode (";", "genNearPointerSet"));
10537
10538   retype = getSpec (operandType (right));
10539   letype = getSpec (ptype);
10540
10541   aopOp (result, ic, FALSE);
10542
10543   /* if the result is rematerializable &
10544      in data space & not a bit variable */
10545   if (AOP_TYPE (result) == AOP_IMMD &&
10546       DCL_TYPE (ptype) == POINTER &&
10547       !IS_BITVAR (retype) &&
10548       !IS_BITVAR (letype))
10549     {
10550       genDataPointerSet (right, result, ic);
10551       return;
10552     }
10553
10554   /* if the value is already in a pointer register
10555      then don't need anything more */
10556   if (!AOP_INPREG (AOP (result)))
10557     {
10558         if (
10559             //AOP_TYPE (result) == AOP_STK
10560             IS_AOP_PREG(result)
10561             )
10562         {
10563             // Aha, it is a pointer, just in disguise.
10564             rname = aopGet (result, 0, FALSE, FALSE);
10565             if (*rname != '@')
10566             {
10567                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10568                         __FILE__, __LINE__);
10569             }
10570             else
10571             {
10572                 // Expected case.
10573                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10574                 rname++;  // skip the '@'.
10575             }
10576         }
10577         else
10578         {
10579             /* otherwise get a free pointer register */
10580             aop = newAsmop (0);
10581             preg = getFreePtr (ic, &aop, FALSE);
10582             emitcode ("mov", "%s,%s",
10583                       preg->name,
10584                       aopGet (result, 0, FALSE, TRUE));
10585             rname = preg->name;
10586         }
10587     }
10588     else
10589     {
10590         rname = aopGet (result, 0, FALSE, FALSE);
10591     }
10592
10593   aopOp (right, ic, FALSE);
10594
10595   /* if bitfield then unpack the bits */
10596   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10597     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10598   else
10599     {
10600       /* we can just get the values */
10601       int size = AOP_SIZE (right);
10602       int offset = 0;
10603
10604       while (size--)
10605         {
10606           l = aopGet (right, offset, FALSE, TRUE);
10607           if ((*l == '@') || (strcmp (l, "acc") == 0))
10608             {
10609               MOVA (l);
10610               emitcode ("mov", "@%s,a", rname);
10611             }
10612           else
10613             emitcode ("mov", "@%s,%s", rname, l);
10614           if (size || pi)
10615             emitcode ("inc", "%s", rname);
10616           offset++;
10617         }
10618     }
10619
10620   /* now some housekeeping stuff */
10621   if (aop) /* we had to allocate for this iCode */
10622     {
10623       if (pi)
10624         aopPut (result, rname, 0);
10625       freeAsmop (NULL, aop, ic, TRUE);
10626     }
10627   else
10628     {
10629       /* we did not allocate which means left
10630          already in a pointer register, then
10631          if size > 0 && this could be used again
10632          we have to point it back to where it
10633          belongs */
10634       if ((AOP_SIZE (right) > 1 &&
10635            !OP_SYMBOL (result)->remat &&
10636            (OP_SYMBOL (result)->liveTo > ic->seq ||
10637             ic->depth)) &&
10638           !pi)
10639         {
10640           int size = AOP_SIZE (right) - 1;
10641           while (size--)
10642             emitcode ("dec", "%s", rname);
10643         }
10644     }
10645
10646   /* done */
10647   if (pi) pi->generated = 1;
10648   freeAsmop (result, NULL, ic, TRUE);
10649   freeAsmop (right, NULL, ic, TRUE);
10650 }
10651
10652 /*-----------------------------------------------------------------*/
10653 /* genPagedPointerSet - emitcode for Paged pointer put             */
10654 /*-----------------------------------------------------------------*/
10655 static void
10656 genPagedPointerSet (operand * right,
10657                     operand * result,
10658                     iCode * ic,
10659                     iCode * pi)
10660 {
10661   asmop *aop = NULL;
10662   regs *preg = NULL;
10663   char *rname, *l;
10664   sym_link *retype, *letype;
10665
10666   D (emitcode (";", "genPagedPointerSet"));
10667
10668   retype = getSpec (operandType (right));
10669   letype = getSpec (operandType (result));
10670
10671   aopOp (result, ic, FALSE);
10672
10673   /* if the value is already in a pointer register
10674      then don't need anything more */
10675   if (!AOP_INPREG (AOP (result)))
10676     {
10677       /* otherwise get a free pointer register */
10678       aop = newAsmop (0);
10679       preg = getFreePtr (ic, &aop, FALSE);
10680       emitcode ("mov", "%s,%s",
10681                 preg->name,
10682                 aopGet (result, 0, FALSE, TRUE));
10683       rname = preg->name;
10684     }
10685   else
10686     rname = aopGet (result, 0, FALSE, FALSE);
10687
10688   aopOp (right, ic, FALSE);
10689
10690   /* if bitfield then unpack the bits */
10691   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10692     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10693   else
10694     {
10695       /* we have can just get the values */
10696       int size = AOP_SIZE (right);
10697       int offset = 0;
10698
10699       while (size--)
10700         {
10701           l = aopGet (right, offset, FALSE, TRUE);
10702           MOVA (l);
10703           emitcode ("movx", "@%s,a", rname);
10704
10705           if (size || pi)
10706             emitcode ("inc", "%s", rname);
10707
10708           offset++;
10709         }
10710     }
10711
10712   /* now some housekeeping stuff */
10713   if (aop) /* we had to allocate for this iCode */
10714     {
10715       if (pi)
10716         aopPut (result, rname, 0);
10717       freeAsmop (NULL, aop, ic, TRUE);
10718     }
10719   else
10720     {
10721       /* we did not allocate which means left
10722          already in a pointer register, then
10723          if size > 0 && this could be used again
10724          we have to point it back to where it
10725          belongs */
10726       if (AOP_SIZE (right) > 1 &&
10727           !OP_SYMBOL (result)->remat &&
10728           (OP_SYMBOL (result)->liveTo > ic->seq ||
10729            ic->depth))
10730         {
10731           int size = AOP_SIZE (right) - 1;
10732           while (size--)
10733             emitcode ("dec", "%s", rname);
10734         }
10735     }
10736
10737   /* done */
10738   if (pi) pi->generated = 1;
10739   freeAsmop (result, NULL, ic, TRUE);
10740   freeAsmop (right, NULL, ic, TRUE);
10741 }
10742
10743 /*-----------------------------------------------------------------*/
10744 /* genFarPointerSet - set value from far space                     */
10745 /*-----------------------------------------------------------------*/
10746 static void
10747 genFarPointerSet (operand * right,
10748                   operand * result, iCode * ic, iCode * pi)
10749 {
10750   int size, offset;
10751   sym_link *retype = getSpec (operandType (right));
10752   sym_link *letype = getSpec (operandType (result));
10753
10754   D(emitcode (";     genFarPointerSet",""));
10755
10756   aopOp (result, ic, FALSE);
10757   loadDptrFromOperand (result, FALSE);
10758
10759   /* so dptr now contains the address */
10760   aopOp (right, ic, FALSE);
10761
10762   /* if bit then unpack */
10763   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10764     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10765   else
10766     {
10767       size = AOP_SIZE (right);
10768       offset = 0;
10769
10770       while (size--)
10771         {
10772           char *l = aopGet (right, offset++, FALSE, FALSE);
10773           MOVA (l);
10774           emitcode ("movx", "@dptr,a");
10775           if (size || pi)
10776             emitcode ("inc", "dptr");
10777         }
10778     }
10779   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10780     aopPut (result, "dpl", 0);
10781     aopPut (result, "dph", 1);
10782     pi->generated=1;
10783   }
10784   freeAsmop (result, NULL, ic, TRUE);
10785   freeAsmop (right, NULL, ic, TRUE);
10786 }
10787
10788 /*-----------------------------------------------------------------*/
10789 /* genGenPointerSet - set value from generic pointer space         */
10790 /*-----------------------------------------------------------------*/
10791 static void
10792 genGenPointerSet (operand * right,
10793                   operand * result, iCode * ic, iCode * pi)
10794 {
10795   int size, offset;
10796   sym_link *retype = getSpec (operandType (right));
10797   sym_link *letype = getSpec (operandType (result));
10798
10799   D (emitcode (";", "genGenPointerSet"));
10800
10801   aopOp (result, ic, FALSE);
10802   loadDptrFromOperand (result, TRUE);
10803
10804   /* so dptr now contains the address */
10805   aopOp (right, ic, FALSE);
10806
10807   /* if bit then unpack */
10808   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10809     {
10810       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10811     }
10812   else
10813     {
10814       size = AOP_SIZE (right);
10815       offset = 0;
10816
10817       while (size--)
10818         {
10819           char *l = aopGet (right, offset++, FALSE, FALSE);
10820           MOVA (l);
10821           emitcode ("lcall", "__gptrput");
10822           if (size || pi)
10823             emitcode ("inc", "dptr");
10824         }
10825     }
10826
10827   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10828     aopPut (result, "dpl", 0);
10829     aopPut (result, "dph", 1);
10830     pi->generated=1;
10831   }
10832   freeAsmop (result, NULL, ic, TRUE);
10833   freeAsmop (right, NULL, ic, TRUE);
10834 }
10835
10836 /*-----------------------------------------------------------------*/
10837 /* genPointerSet - stores the value into a pointer location        */
10838 /*-----------------------------------------------------------------*/
10839 static void
10840 genPointerSet (iCode * ic, iCode *pi)
10841 {
10842   operand *right, *result;
10843   sym_link *type, *etype;
10844   int p_type;
10845
10846   D (emitcode (";", "genPointerSet"));
10847
10848   right = IC_RIGHT (ic);
10849   result = IC_RESULT (ic);
10850
10851   /* depending on the type of pointer we need to
10852      move it to the correct pointer register */
10853   type = operandType (result);
10854   etype = getSpec (type);
10855   /* if left is of type of pointer then it is simple */
10856   if (IS_PTR (type) && !IS_FUNC (type->next))
10857     {
10858       p_type = DCL_TYPE (type);
10859     }
10860   else
10861     {
10862       /* we have to go by the storage class */
10863       p_type = PTR_TYPE (SPEC_OCLS (etype));
10864     }
10865
10866   /* special case when cast remat */
10867   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10868       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10869           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10870           type = operandType (result);
10871           p_type = DCL_TYPE (type);
10872   }
10873
10874   /* now that we have the pointer type we assign
10875      the pointer values */
10876   switch (p_type)
10877     {
10878
10879     case POINTER:
10880     case IPOINTER:
10881       genNearPointerSet (right, result, ic, pi);
10882       break;
10883
10884     case PPOINTER:
10885       genPagedPointerSet (right, result, ic, pi);
10886       break;
10887
10888     case FPOINTER:
10889       genFarPointerSet (right, result, ic, pi);
10890       break;
10891
10892     case GPOINTER:
10893       genGenPointerSet (right, result, ic, pi);
10894       break;
10895
10896     default:
10897       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10898               "genPointerSet: illegal pointer type");
10899     }
10900 }
10901
10902 /*-----------------------------------------------------------------*/
10903 /* genIfx - generate code for Ifx statement                        */
10904 /*-----------------------------------------------------------------*/
10905 static void
10906 genIfx (iCode * ic, iCode * popIc)
10907 {
10908   operand *cond = IC_COND (ic);
10909   int isbit = 0;
10910   char *dup = NULL;
10911
10912   D (emitcode (";", "genIfx"));
10913
10914   aopOp (cond, ic, FALSE);
10915
10916   /* get the value into acc */
10917   if (AOP_TYPE (cond) != AOP_CRY)
10918     {
10919       toBoolean (cond);
10920     }
10921   else
10922     {
10923       isbit = 1;
10924       if (AOP(cond)->aopu.aop_dir)
10925         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10926     }
10927
10928   /* the result is now in the accumulator or a directly addressable bit */
10929   freeAsmop (cond, NULL, ic, TRUE);
10930
10931   /* if there was something to be popped then do it */
10932   if (popIc)
10933     genIpop (popIc);
10934
10935   /* if the condition is a bit variable */
10936   if (isbit && dup)
10937     genIfxJump(ic, dup, NULL, NULL, NULL);
10938   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10939     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10940   else if (isbit && !IS_ITEMP (cond))
10941     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10942   else
10943     genIfxJump (ic, "a", NULL, NULL, NULL);
10944
10945   ic->generated = 1;
10946 }
10947
10948 /*-----------------------------------------------------------------*/
10949 /* genAddrOf - generates code for address of                       */
10950 /*-----------------------------------------------------------------*/
10951 static void
10952 genAddrOf (iCode * ic)
10953 {
10954   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10955   int size, offset;
10956
10957   D (emitcode (";", "genAddrOf"));
10958
10959   aopOp (IC_RESULT (ic), ic, FALSE);
10960
10961   /* if the operand is on the stack then we
10962      need to get the stack offset of this
10963      variable */
10964   if (sym->onStack)
10965     {
10966       /* if it has an offset then we need to compute it */
10967       if (sym->stack)
10968         {
10969           int stack_offset = ((sym->stack < 0) ?
10970                               ((char) (sym->stack - _G.nRegsSaved)) :
10971                               ((char) sym->stack)) & 0xff;
10972           if ((abs(stack_offset) == 1) &&
10973               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10974               !isOperandVolatile (IC_RESULT (ic), FALSE))
10975             {
10976               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10977               if (stack_offset > 0)
10978                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10979               else
10980                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10981             }
10982           else
10983             {
10984               emitcode ("mov", "a,%s", SYM_BP (sym));
10985               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
10986               aopPut (IC_RESULT (ic), "a", 0);
10987             }
10988         }
10989       else
10990         {
10991           /* we can just move _bp */
10992           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10993         }
10994       /* fill the result with zero */
10995       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10996
10997       offset = 1;
10998       while (size--)
10999         {
11000           aopPut (IC_RESULT (ic), zero, offset++);
11001         }
11002       goto release;
11003     }
11004
11005   /* object not on stack then we need the name */
11006   size = AOP_SIZE (IC_RESULT (ic));
11007   offset = 0;
11008
11009   while (size--)
11010     {
11011       char s[SDCC_NAME_MAX];
11012       if (offset)
11013         sprintf (s, "#(%s >> %d)",
11014                  sym->rname,
11015                  offset * 8);
11016       else
11017         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11018       aopPut (IC_RESULT (ic), s, offset++);
11019     }
11020
11021 release:
11022   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11023
11024 }
11025
11026 /*-----------------------------------------------------------------*/
11027 /* genFarFarAssign - assignment when both are in far space         */
11028 /*-----------------------------------------------------------------*/
11029 static void
11030 genFarFarAssign (operand * result, operand * right, iCode * ic)
11031 {
11032   int size = AOP_SIZE (right);
11033   int offset = 0;
11034   char *l;
11035
11036   D (emitcode (";", "genFarFarAssign"));
11037
11038   /* first push the right side on to the stack */
11039   while (size--)
11040     {
11041       l = aopGet (right, offset++, FALSE, FALSE);
11042       MOVA (l);
11043       emitcode ("push", "acc");
11044     }
11045
11046   freeAsmop (right, NULL, ic, FALSE);
11047   /* now assign DPTR to result */
11048   aopOp (result, ic, FALSE);
11049   size = AOP_SIZE (result);
11050   while (size--)
11051     {
11052       emitcode ("pop", "acc");
11053       aopPut (result, "a", --offset);
11054     }
11055   freeAsmop (result, NULL, ic, FALSE);
11056 }
11057
11058 /*-----------------------------------------------------------------*/
11059 /* genAssign - generate code for assignment                        */
11060 /*-----------------------------------------------------------------*/
11061 static void
11062 genAssign (iCode * ic)
11063 {
11064   operand *result, *right;
11065   int size, offset;
11066   unsigned long lit = 0L;
11067
11068   D (emitcode (";", "genAssign"));
11069
11070   result = IC_RESULT (ic);
11071   right = IC_RIGHT (ic);
11072
11073   /* if they are the same */
11074   if (operandsEqu (result, right) &&
11075       !isOperandVolatile (result, FALSE) &&
11076       !isOperandVolatile (right, FALSE))
11077     return;
11078
11079   aopOp (right, ic, FALSE);
11080
11081   /* special case both in far space */
11082   if (AOP_TYPE (right) == AOP_DPTR &&
11083       IS_TRUE_SYMOP (result) &&
11084       isOperandInFarSpace (result))
11085     {
11086       genFarFarAssign (result, right, ic);
11087       return;
11088     }
11089
11090   aopOp (result, ic, TRUE);
11091
11092   /* if they are the same registers */
11093   if (sameRegs (AOP (right), AOP (result)) &&
11094       !isOperandVolatile (result, FALSE) &&
11095       !isOperandVolatile (right, FALSE))
11096     goto release;
11097
11098   /* if the result is a bit */
11099   if (AOP_TYPE (result) == AOP_CRY)
11100     {
11101       assignBit (result, right);
11102       goto release;
11103     }
11104
11105   /* bit variables done */
11106   /* general case */
11107   size = AOP_SIZE (result);
11108   offset = 0;
11109   if (AOP_TYPE (right) == AOP_LIT)
11110     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11111
11112   if ((size > 1) &&
11113       (AOP_TYPE (result) != AOP_REG) &&
11114       (AOP_TYPE (right) == AOP_LIT) &&
11115       !IS_FLOAT (operandType (right)) &&
11116       (lit < 256L))
11117     {
11118       while ((size) && (lit))
11119         {
11120           aopPut (result,
11121                   aopGet (right, offset, FALSE, FALSE),
11122                   offset);
11123           lit >>= 8;
11124           offset++;
11125           size--;
11126         }
11127       /* And now fill the rest with zeros. */
11128       if (size)
11129         {
11130           emitcode ("clr", "a");
11131         }
11132       while (size--)
11133         {
11134           aopPut (result, "a", offset);
11135           offset++;
11136         }
11137     }
11138   else
11139     {
11140       while (size--)
11141         {
11142           aopPut (result,
11143                   aopGet (right, offset, FALSE, FALSE),
11144                   offset);
11145           offset++;
11146         }
11147     }
11148
11149 release:
11150   freeAsmop (result, NULL, ic, TRUE);
11151   freeAsmop (right, NULL, ic, TRUE);
11152 }
11153
11154 /*-----------------------------------------------------------------*/
11155 /* genJumpTab - generates code for jump table                      */
11156 /*-----------------------------------------------------------------*/
11157 static void
11158 genJumpTab (iCode * ic)
11159 {
11160   symbol *jtab,*jtablo,*jtabhi;
11161   char *l;
11162   unsigned int count;
11163
11164   D (emitcode (";", "genJumpTab"));
11165
11166   count = elementsInSet( IC_JTLABELS (ic) );
11167
11168   if( count <= 16 )
11169     {
11170       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11171          if the switch argument is in a register.
11172          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11173       /* Peephole may not convert ljmp to sjmp or ret
11174          labelIsReturnOnly & labelInRange must check
11175          currPl->ic->op != JUMPTABLE */
11176       aopOp (IC_JTCOND (ic), ic, FALSE);
11177       /* get the condition into accumulator */
11178       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11179       MOVA (l);
11180       /* multiply by three */
11181       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11182         {
11183           emitcode ("mov", "b,#3");
11184           emitcode ("mul", "ab");
11185         }
11186       else
11187         {
11188           emitcode ("add", "a,acc");
11189           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11190         }
11191       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11192
11193       jtab = newiTempLabel (NULL);
11194       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11195       emitcode ("jmp", "@a+dptr");
11196       emitLabel (jtab);
11197       /* now generate the jump labels */
11198       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11199            jtab = setNextItem (IC_JTLABELS (ic)))
11200         emitcode ("ljmp", "%05d$", jtab->key + 100);
11201     }
11202   else
11203     {
11204       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11205          if the switch argument is in a register.
11206          For n>6 this algorithm may be more compact */
11207       jtablo = newiTempLabel (NULL);
11208       jtabhi = newiTempLabel (NULL);
11209
11210       /* get the condition into accumulator.
11211          Using b as temporary storage, if register push/pop is needed */
11212       aopOp (IC_JTCOND (ic), ic, FALSE);
11213       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11214       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11215           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11216         {
11217           // (MB) what if B is in use???
11218           wassertl(!BINUSE, "B was in use");
11219           emitcode ("mov", "b,%s", l);
11220           l = "b";
11221         }
11222       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11223       MOVA (l);
11224       if( count <= 112 )
11225         {
11226           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11227           emitcode ("movc", "a,@a+pc");
11228           emitcode ("push", "acc");
11229
11230           MOVA (l);
11231           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11232           emitcode ("movc", "a,@a+pc");
11233           emitcode ("push", "acc");
11234         }
11235       else
11236         {
11237           /* this scales up to n<=255, but needs two more bytes
11238              and changes dptr */
11239           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11240           emitcode ("movc", "a,@a+dptr");
11241           emitcode ("push", "acc");
11242
11243           MOVA (l);
11244           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11245           emitcode ("movc", "a,@a+dptr");
11246           emitcode ("push", "acc");
11247         }
11248
11249       emitcode ("ret", "");
11250
11251       /* now generate jump table, LSB */
11252       emitLabel (jtablo);
11253       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11254            jtab = setNextItem (IC_JTLABELS (ic)))
11255         emitcode (".db", "%05d$", jtab->key + 100);
11256
11257       /* now generate jump table, MSB */
11258       emitLabel (jtabhi);
11259       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11260            jtab = setNextItem (IC_JTLABELS (ic)))
11261          emitcode (".db", "%05d$>>8", jtab->key + 100);
11262     }
11263 }
11264
11265 /*-----------------------------------------------------------------*/
11266 /* genCast - gen code for casting                                  */
11267 /*-----------------------------------------------------------------*/
11268 static void
11269 genCast (iCode * ic)
11270 {
11271   operand *result = IC_RESULT (ic);
11272   sym_link *ctype = operandType (IC_LEFT (ic));
11273   sym_link *rtype = operandType (IC_RIGHT (ic));
11274   operand *right = IC_RIGHT (ic);
11275   int size, offset;
11276
11277   D (emitcode (";", "genCast"));
11278
11279   /* if they are equivalent then do nothing */
11280   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11281     return;
11282
11283   aopOp (right, ic, FALSE);
11284   aopOp (result, ic, FALSE);
11285
11286   /* if the result is a bit (and not a bitfield) */
11287   if (IS_BIT (OP_SYMBOL (result)->type))
11288     {
11289       assignBit (result, right);
11290       goto release;
11291     }
11292
11293   /* if they are the same size : or less */
11294   if (AOP_SIZE (result) <= AOP_SIZE (right))
11295     {
11296
11297       /* if they are in the same place */
11298       if (sameRegs (AOP (right), AOP (result)))
11299         goto release;
11300
11301       /* if they in different places then copy */
11302       size = AOP_SIZE (result);
11303       offset = 0;
11304       while (size--)
11305         {
11306           aopPut (result,
11307                   aopGet (right, offset, FALSE, FALSE),
11308                   offset);
11309           offset++;
11310         }
11311       goto release;
11312     }
11313
11314   /* if the result is of type pointer */
11315   if (IS_PTR (ctype))
11316     {
11317
11318       int p_type;
11319       sym_link *type = operandType (right);
11320       sym_link *etype = getSpec (type);
11321
11322       /* pointer to generic pointer */
11323       if (IS_GENPTR (ctype))
11324         {
11325           if (IS_PTR (type))
11326             {
11327               p_type = DCL_TYPE (type);
11328             }
11329           else
11330             {
11331               if (SPEC_SCLS(etype)==S_REGISTER) {
11332                 // let's assume it is a generic pointer
11333                 p_type=GPOINTER;
11334               } else {
11335                 /* we have to go by the storage class */
11336                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11337               }
11338             }
11339
11340           /* the first two bytes are known */
11341           size = GPTRSIZE - 1;
11342           offset = 0;
11343           while (size--)
11344             {
11345               aopPut (result,
11346                       aopGet (right, offset, FALSE, FALSE),
11347                       offset);
11348               offset++;
11349             }
11350           /* the last byte depending on type */
11351             {
11352                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11353                 char gpValStr[10];
11354
11355                 if (gpVal == -1)
11356                 {
11357                     // pointerTypeToGPByte will have bitched.
11358                     exit(1);
11359                 }
11360
11361                 sprintf(gpValStr, "#0x%x", gpVal);
11362                 aopPut (result, gpValStr, GPTRSIZE - 1);
11363             }
11364           goto release;
11365         }
11366
11367       /* just copy the pointers */
11368       size = AOP_SIZE (result);
11369       offset = 0;
11370       while (size--)
11371         {
11372           aopPut (result,
11373                   aopGet (right, offset, FALSE, FALSE),
11374                   offset);
11375           offset++;
11376         }
11377       goto release;
11378     }
11379
11380   /* so we now know that the size of destination is greater
11381      than the size of the source */
11382   /* we move to result for the size of source */
11383   size = AOP_SIZE (right);
11384   offset = 0;
11385   while (size--)
11386     {
11387       aopPut (result,
11388               aopGet (right, offset, FALSE, FALSE),
11389               offset);
11390       offset++;
11391     }
11392
11393   /* now depending on the sign of the source && destination */
11394   size = AOP_SIZE (result) - AOP_SIZE (right);
11395   /* if unsigned or not an integral type */
11396   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11397     {
11398       while (size--)
11399         aopPut (result, zero, offset++);
11400     }
11401   else
11402     {
11403       /* we need to extend the sign :{ */
11404       char *l = aopGet (right, AOP_SIZE (right) - 1,
11405                         FALSE, FALSE);
11406       MOVA (l);
11407       emitcode ("rlc", "a");
11408       emitcode ("subb", "a,acc");
11409       while (size--)
11410         aopPut (result, "a", offset++);
11411     }
11412
11413   /* we are done hurray !!!! */
11414
11415 release:
11416   freeAsmop (result, NULL, ic, TRUE);
11417   freeAsmop (right, NULL, ic, TRUE);
11418 }
11419
11420 /*-----------------------------------------------------------------*/
11421 /* genDjnz - generate decrement & jump if not zero instrucion      */
11422 /*-----------------------------------------------------------------*/
11423 static int
11424 genDjnz (iCode * ic, iCode * ifx)
11425 {
11426   symbol *lbl, *lbl1;
11427   if (!ifx)
11428     return 0;
11429
11430   /* if the if condition has a false label
11431      then we cannot save */
11432   if (IC_FALSE (ifx))
11433     return 0;
11434
11435   /* if the minus is not of the form a = a - 1 */
11436   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11437       !IS_OP_LITERAL (IC_RIGHT (ic)))
11438     return 0;
11439
11440   if (operandLitValue (IC_RIGHT (ic)) != 1)
11441     return 0;
11442
11443   /* if the size of this greater than one then no
11444      saving */
11445   if (getSize (operandType (IC_RESULT (ic))) > 1)
11446     return 0;
11447
11448   /* otherwise we can save BIG */
11449
11450   D (emitcode (";", "genDjnz"));
11451
11452   lbl = newiTempLabel (NULL);
11453   lbl1 = newiTempLabel (NULL);
11454
11455   aopOp (IC_RESULT (ic), ic, FALSE);
11456
11457   if (AOP_NEEDSACC(IC_RESULT(ic)))
11458   {
11459       /* If the result is accessed indirectly via
11460        * the accumulator, we must explicitly write
11461        * it back after the decrement.
11462        */
11463       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11464
11465       if (strcmp(rByte, "a"))
11466       {
11467            /* Something is hopelessly wrong */
11468            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11469                    __FILE__, __LINE__);
11470            /* We can just give up; the generated code will be inefficient,
11471             * but what the hey.
11472             */
11473            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11474            return 0;
11475       }
11476       emitcode ("dec", "%s", rByte);
11477       aopPut (IC_RESULT (ic), rByte, 0);
11478       emitcode ("jnz", "%05d$", lbl->key + 100);
11479   }
11480   else if (IS_AOP_PREG (IC_RESULT (ic)))
11481     {
11482       emitcode ("dec", "%s",
11483                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11484       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11485       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11486       ifx->generated = 1;
11487       emitcode ("jnz", "%05d$", lbl->key + 100);
11488     }
11489   else
11490     {
11491       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11492                 lbl->key + 100);
11493     }
11494   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11495   emitLabel (lbl);
11496   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11497   emitLabel (lbl1);
11498
11499   if (!ifx->generated)
11500       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11501   ifx->generated = 1;
11502   return 1;
11503 }
11504
11505 /*-----------------------------------------------------------------*/
11506 /* genReceive - generate code for a receive iCode                  */
11507 /*-----------------------------------------------------------------*/
11508 static void
11509 genReceive (iCode * ic)
11510 {
11511   int size = getSize (operandType (IC_RESULT (ic)));
11512   int offset = 0;
11513
11514   D (emitcode (";", "genReceive"));
11515
11516   if (ic->argreg == 1)
11517     { /* first parameter */
11518       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11519            isOperandInPagedSpace (IC_RESULT (ic))) &&
11520           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11521            IS_TRUE_SYMOP (IC_RESULT (ic))))
11522         {
11523           regs *tempRegs[4];
11524           int receivingA = 0;
11525           int roffset = 0;
11526
11527           for (offset = 0; offset<size; offset++)
11528             if (!strcmp (fReturn[offset], "a"))
11529               receivingA = 1;
11530
11531           if (!receivingA)
11532             {
11533               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11534                 {
11535                   for (offset = size-1; offset>0; offset--)
11536                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11537                   emitcode("mov","a,%s", fReturn[0]);
11538                   _G.accInUse++;
11539                   aopOp (IC_RESULT (ic), ic, FALSE);
11540                   _G.accInUse--;
11541                   aopPut (IC_RESULT (ic), "a", offset);
11542                   for (offset = 1; offset<size; offset++)
11543                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11544                   goto release;
11545                 }
11546             }
11547           else
11548             {
11549               if (getTempRegs(tempRegs, size, ic))
11550                 {
11551                   for (offset = 0; offset<size; offset++)
11552                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11553                   aopOp (IC_RESULT (ic), ic, FALSE);
11554                   for (offset = 0; offset<size; offset++)
11555                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11556                   goto release;
11557                 }
11558             }
11559
11560           offset = fReturnSizeMCS51 - size;
11561           while (size--)
11562             {
11563               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11564                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11565               offset++;
11566             }
11567           aopOp (IC_RESULT (ic), ic, FALSE);
11568           size = AOP_SIZE (IC_RESULT (ic));
11569           offset = 0;
11570           while (size--)
11571             {
11572               emitcode ("pop", "acc");
11573               aopPut (IC_RESULT (ic), "a", offset++);
11574             }
11575         }
11576       else
11577         {
11578           _G.accInUse++;
11579           aopOp (IC_RESULT (ic), ic, FALSE);
11580           _G.accInUse--;
11581           assignResultValue (IC_RESULT (ic), NULL);
11582         }
11583     }
11584   else if (ic->argreg > 12)
11585     { /* bit parameters */
11586       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11587         {
11588           aopOp (IC_RESULT (ic), ic, FALSE);
11589           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11590           outBitC(IC_RESULT (ic));
11591         }
11592     }
11593   else
11594     { /* other parameters */
11595       int rb1off ;
11596       aopOp (IC_RESULT (ic), ic, FALSE);
11597       rb1off = ic->argreg;
11598       while (size--)
11599         {
11600           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11601         }
11602     }
11603
11604 release:
11605   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11606 }
11607
11608 /*-----------------------------------------------------------------*/
11609 /* genDummyRead - generate code for dummy read of volatiles        */
11610 /*-----------------------------------------------------------------*/
11611 static void
11612 genDummyRead (iCode * ic)
11613 {
11614   operand *op;
11615   int size, offset;
11616
11617   D (emitcode(";", "genDummyRead"));
11618
11619   op = IC_RIGHT (ic);
11620   if (op && IS_SYMOP (op))
11621     {
11622       aopOp (op, ic, FALSE);
11623
11624       /* if the result is a bit */
11625       if (AOP_TYPE (op) == AOP_CRY)
11626         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11627       else
11628         {
11629           /* bit variables done */
11630           /* general case */
11631           size = AOP_SIZE (op);
11632           offset = 0;
11633           while (size--)
11634           {
11635             MOVA (aopGet (op, offset, FALSE, FALSE));
11636             offset++;
11637           }
11638         }
11639
11640       freeAsmop (op, NULL, ic, TRUE);
11641     }
11642
11643   op = IC_LEFT (ic);
11644   if (op && IS_SYMOP (op))
11645     {
11646       aopOp (op, ic, FALSE);
11647
11648       /* if the result is a bit */
11649       if (AOP_TYPE (op) == AOP_CRY)
11650         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11651       else
11652         {
11653           /* bit variables done */
11654           /* general case */
11655           size = AOP_SIZE (op);
11656           offset = 0;
11657           while (size--)
11658           {
11659             MOVA (aopGet (op, offset, FALSE, FALSE));
11660             offset++;
11661           }
11662         }
11663
11664       freeAsmop (op, NULL, ic, TRUE);
11665     }
11666 }
11667
11668 /*-----------------------------------------------------------------*/
11669 /* genCritical - generate code for start of a critical sequence    */
11670 /*-----------------------------------------------------------------*/
11671 static void
11672 genCritical (iCode *ic)
11673 {
11674   symbol *tlbl = newiTempLabel (NULL);
11675
11676   D (emitcode(";", "genCritical"));
11677
11678   if (IC_RESULT (ic))
11679     {
11680       aopOp (IC_RESULT (ic), ic, TRUE);
11681       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11682       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11683       aopPut (IC_RESULT (ic), zero, 0);
11684       emitLabel (tlbl);
11685       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11686     }
11687   else
11688     {
11689       emitcode ("setb", "c");
11690       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11691       emitcode ("clr", "c");
11692       emitLabel (tlbl);
11693       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11694     }
11695 }
11696
11697 /*-----------------------------------------------------------------*/
11698 /* genEndCritical - generate code for end of a critical sequence   */
11699 /*-----------------------------------------------------------------*/
11700 static void
11701 genEndCritical (iCode *ic)
11702 {
11703   D(emitcode(";     genEndCritical",""));
11704
11705   if (IC_RIGHT (ic))
11706     {
11707       aopOp (IC_RIGHT (ic), ic, FALSE);
11708       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11709         {
11710           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11711           emitcode ("mov", "ea,c");
11712         }
11713       else
11714         {
11715           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11716             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11717           emitcode ("rrc", "a");
11718           emitcode ("mov", "ea,c");
11719         }
11720       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11721     }
11722   else
11723     {
11724       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11725       emitcode ("mov", "ea,c");
11726     }
11727 }
11728
11729 /*-----------------------------------------------------------------*/
11730 /* gen51Code - generate code for 8051 based controllers            */
11731 /*-----------------------------------------------------------------*/
11732 void
11733 gen51Code (iCode * lic)
11734 {
11735   iCode *ic;
11736   int cln = 0;
11737   /* int cseq = 0; */
11738
11739   _G.currentFunc = NULL;
11740   lineHead = lineCurr = NULL;
11741
11742   /* print the allocation information */
11743   if (allocInfo && currFunc)
11744     printAllocInfo (currFunc, codeOutBuf);
11745   /* if debug information required */
11746   if (options.debug && currFunc)
11747     {
11748       debugFile->writeFunction (currFunc, lic);
11749     }
11750   /* stack pointer name */
11751   if (options.useXstack)
11752     spname = "_spx";
11753   else
11754     spname = "sp";
11755
11756
11757   for (ic = lic; ic; ic = ic->next)
11758     {
11759       _G.current_iCode = ic;
11760
11761       if (ic->lineno && cln != ic->lineno)
11762         {
11763           if (options.debug)
11764             {
11765               debugFile->writeCLine (ic);
11766             }
11767           if (!options.noCcodeInAsm) {
11768             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
11769                       printCLine(ic->filename, ic->lineno));
11770           }
11771           cln = ic->lineno;
11772         }
11773       #if 0
11774       if (ic->seqPoint && ic->seqPoint != cseq)
11775         {
11776           emitcode ("", "; sequence point %d", ic->seqPoint);
11777           cseq = ic->seqPoint;
11778         }
11779       #endif
11780       if (options.iCodeInAsm) {
11781         char regsInUse[80];
11782         int i;
11783         char *iLine;
11784
11785         #if 0
11786         for (i=0; i<8; i++) {
11787           sprintf (&regsInUse[i],
11788                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11789         regsInUse[i]=0;
11790         #else
11791         strcpy (regsInUse, "--------");
11792         for (i=0; i < 8; i++) {
11793           if (bitVectBitValue (ic->rMask, i))
11794             {
11795               int offset = regs8051[i].offset;
11796               regsInUse[offset] = offset + '0'; /* show rMask */
11797             }
11798         #endif
11799         }
11800         iLine = printILine(ic);
11801         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11802         dbuf_free(iLine);
11803       }
11804       /* if the result is marked as
11805          spilt and rematerializable or code for
11806          this has already been generated then
11807          do nothing */
11808       if (resultRemat (ic) || ic->generated)
11809         continue;
11810
11811       /* depending on the operation */
11812       switch (ic->op)
11813         {
11814         case '!':
11815           genNot (ic);
11816           break;
11817
11818         case '~':
11819           genCpl (ic);
11820           break;
11821
11822         case UNARYMINUS:
11823           genUminus (ic);
11824           break;
11825
11826         case IPUSH:
11827           genIpush (ic);
11828           break;
11829
11830         case IPOP:
11831           /* IPOP happens only when trying to restore a
11832              spilt live range, if there is an ifx statement
11833              following this pop then the if statement might
11834              be using some of the registers being popped which
11835              would destory the contents of the register so
11836              we need to check for this condition and handle it */
11837           if (ic->next &&
11838               ic->next->op == IFX &&
11839               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11840             genIfx (ic->next, ic);
11841           else
11842             genIpop (ic);
11843           break;
11844
11845         case CALL:
11846           genCall (ic);
11847           break;
11848
11849         case PCALL:
11850           genPcall (ic);
11851           break;
11852
11853         case FUNCTION:
11854           genFunction (ic);
11855           break;
11856
11857         case ENDFUNCTION:
11858           genEndFunction (ic);
11859           break;
11860
11861         case RETURN:
11862           genRet (ic);
11863           break;
11864
11865         case LABEL:
11866           genLabel (ic);
11867           break;
11868
11869         case GOTO:
11870           genGoto (ic);
11871           break;
11872
11873         case '+':
11874           genPlus (ic);
11875           break;
11876
11877         case '-':
11878           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11879             genMinus (ic);
11880           break;
11881
11882         case '*':
11883           genMult (ic);
11884           break;
11885
11886         case '/':
11887           genDiv (ic);
11888           break;
11889
11890         case '%':
11891           genMod (ic);
11892           break;
11893
11894         case '>':
11895           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11896           break;
11897
11898         case '<':
11899           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11900           break;
11901
11902         case LE_OP:
11903         case GE_OP:
11904         case NE_OP:
11905
11906           /* note these two are xlated by algebraic equivalence
11907              in decorateType() in SDCCast.c */
11908           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11909                   "got '>=' or '<=' shouldn't have come here");
11910           break;
11911
11912         case EQ_OP:
11913           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11914           break;
11915
11916         case AND_OP:
11917           genAndOp (ic);
11918           break;
11919
11920         case OR_OP:
11921           genOrOp (ic);
11922           break;
11923
11924         case '^':
11925           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11926           break;
11927
11928         case '|':
11929           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11930           break;
11931
11932         case BITWISEAND:
11933           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11934           break;
11935
11936         case INLINEASM:
11937           genInline (ic);
11938           break;
11939
11940         case RRC:
11941           genRRC (ic);
11942           break;
11943
11944         case RLC:
11945           genRLC (ic);
11946           break;
11947
11948         case GETHBIT:
11949           genGetHbit (ic);
11950           break;
11951
11952         case GETABIT:
11953           genGetAbit (ic);
11954           break;
11955
11956         case GETBYTE:
11957           genGetByte (ic);
11958           break;
11959
11960         case GETWORD:
11961           genGetWord (ic);
11962           break;
11963
11964         case LEFT_OP:
11965           genLeftShift (ic);
11966           break;
11967
11968         case RIGHT_OP:
11969           genRightShift (ic);
11970           break;
11971
11972         case GET_VALUE_AT_ADDRESS:
11973           genPointerGet (ic,
11974                          hasInc (IC_LEFT (ic), ic,
11975                                  getSize (operandType (IC_RESULT (ic)))),
11976                          ifxForOp (IC_RESULT (ic), ic) );
11977           break;
11978
11979         case '=':
11980           if (POINTER_SET (ic))
11981             genPointerSet (ic,
11982                            hasInc (IC_RESULT (ic), ic,
11983                                    getSize (operandType (IC_RIGHT (ic)))));
11984           else
11985             genAssign (ic);
11986           break;
11987
11988         case IFX:
11989           genIfx (ic, NULL);
11990           break;
11991
11992         case ADDRESS_OF:
11993           genAddrOf (ic);
11994           break;
11995
11996         case JUMPTABLE:
11997           genJumpTab (ic);
11998           break;
11999
12000         case CAST:
12001           genCast (ic);
12002           break;
12003
12004         case RECEIVE:
12005           genReceive (ic);
12006           break;
12007
12008         case SEND:
12009           addSet (&_G.sendSet, ic);
12010           break;
12011
12012         case DUMMY_READ_VOLATILE:
12013           genDummyRead (ic);
12014           break;
12015
12016         case CRITICAL:
12017           genCritical (ic);
12018           break;
12019
12020         case ENDCRITICAL:
12021           genEndCritical (ic);
12022           break;
12023
12024         case SWAP:
12025           genSwap (ic);
12026           break;
12027
12028         default:
12029           ic = ic;
12030         }
12031     }
12032
12033   _G.current_iCode = NULL;
12034
12035   /* now we are ready to call the
12036      peep hole optimizer */
12037   if (!options.nopeep)
12038     peepHole (&lineHead);
12039
12040   /* now do the actual printing */
12041   printLine (lineHead, codeOutBuf);
12042   return;
12043 }