6539d048ec5f3d0bcd822a10ec810402b804e3fd
[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)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "rtrack.h"
45 #include "gen.h"
46 #include "dbuf_string.h"
47
48 char *aopLiteral (value * val, int offset);
49 char *aopLiteralLong (value * val, int offset, int size);
50 extern int allocInfo;
51
52 /* this is the down and dirty file with all kinds of
53    kludgy & hacky stuff. This is what it is all about
54    CODE GENERATION for a specific MCU . some of the
55    routines may be reusable, will have to see */
56
57 static char *zero = "#0x00";
58 static char *one = "#0x01";
59 static char *spname;
60
61 char *fReturn8051[] =
62 {"dpl", "dph", "b", "a"};
63 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
64 char **fReturn = fReturn8051;
65 static char *accUse[] =
66 {"a", "b"};
67
68 static unsigned short rbank = -1;
69
70 #define REG_WITH_INDEX   mcs51_regWithIdx
71
72 #define AOP(op) op->aop
73 #define AOP_TYPE(op) AOP(op)->type
74 #define AOP_SIZE(op) AOP(op)->size
75 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
76                         AOP_TYPE(x) == AOP_R0))
77
78 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
79                          AOP_TYPE(x) == AOP_DPTR || \
80                          AOP(x)->paged))
81
82 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
83                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
84                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
85
86 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
87
88 #define R0INB   _G.bu.bs.r0InB
89 #define R1INB   _G.bu.bs.r1InB
90 #define OPINB   _G.bu.bs.OpInB
91 #define BINUSE  _G.bu.BInUse
92
93 static struct
94   {
95     short r0Pushed;
96     short r1Pushed;
97     union
98       {
99         struct
100           {
101             short r0InB : 2;//2 so we can see it overflow
102             short r1InB : 2;//2 so we can see it overflow
103             short OpInB : 2;//2 so we can see it overflow
104           } bs;
105         short BInUse;
106       } bu;
107     short accInUse;
108     short inLine;
109     short debugLine;
110     short nRegsSaved;
111     set *sendSet;
112     iCode *current_iCode;
113     symbol *currentFunc;
114   }
115 _G;
116
117 static char *rb1regs[] = {
118     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
119     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
120 };
121
122 extern struct dbuf_s *codeOutBuf;
123 static void saveRBank (int, iCode *, bool);
124
125 #define RESULTONSTACK(x) \
126                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
127                          IC_RESULT(x)->aop->type == AOP_STK )
128
129 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
130 #define MOVB(x)  movb(x)
131
132 #define CLRC     emitcode("clr","c")
133 #define SETC     emitcode("setb","c")
134
135 static lineNode *lineHead = NULL;
136 static lineNode *lineCurr = NULL;
137
138 static unsigned char SLMask[] =
139 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
140  0xE0, 0xC0, 0x80, 0x00};
141 static unsigned char SRMask[] =
142 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
143  0x07, 0x03, 0x01, 0x00};
144
145 #define LSB     0
146 #define MSB16   1
147 #define MSB24   2
148 #define MSB32   3
149
150 /*-----------------------------------------------------------------*/
151 /* emitcode - writes the code into a file : for now it is simple    */
152 /*-----------------------------------------------------------------*/
153 void
154 emitcode (const char *inst, const char *fmt,...)
155 {
156   va_list ap;
157   struct dbuf_s dbuf;
158   const char *lbp, *lb;
159
160   dbuf_init (&dbuf, INITIAL_INLINEASM);
161
162   va_start (ap, fmt);
163
164   if (inst && *inst)
165     {
166       dbuf_append_str (&dbuf, inst);
167
168       if (fmt && *fmt)
169         {
170           dbuf_append_char (&dbuf, '\t');
171           dbuf_tvprintf (&dbuf, fmt, ap);
172         }
173     }
174   else
175     {
176       dbuf_tvprintf (&dbuf, fmt, ap);
177     }
178
179   lbp = lb = dbuf_c_str(&dbuf);
180
181   while (isspace ((unsigned char)*lbp))
182     {
183       lbp++;
184     }
185
186   if (lbp && *lbp)
187     {
188       rtrackUpdate (lbp);
189
190       lineCurr = (lineCurr ?
191                   connectLine (lineCurr, newLineNode (lb)) :
192                   (lineHead = newLineNode (lb)));
193     }
194
195   lineCurr->isInline = _G.inLine;
196   lineCurr->isDebug = _G.debugLine;
197   lineCurr->ic = _G.current_iCode;
198   lineCurr->isComment = (*lbp==';');
199   va_end (ap);
200
201   dbuf_destroy(&dbuf);
202 }
203
204 static void
205 emitLabel (symbol *tlbl)
206 {
207   emitcode ("", "%05d$:", tlbl->key + 100);
208   lineCurr->isLabel = 1;
209 }
210
211 /*-----------------------------------------------------------------*/
212 /* mcs51_emitDebuggerSymbol - associate the current code location  */
213 /*   with a debugger symbol                                        */
214 /*-----------------------------------------------------------------*/
215 void
216 mcs51_emitDebuggerSymbol (char * debugSym)
217 {
218   _G.debugLine = 1;
219   emitcode ("", "%s ==.", debugSym);
220   _G.debugLine = 0;
221 }
222
223 /*-----------------------------------------------------------------*/
224 /* mova - moves specified value into accumulator                   */
225 /*-----------------------------------------------------------------*/
226 static void
227 mova (const char *x)
228 {
229   /* do some early peephole optimization */
230   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
231     return;
232
233   /* if it is a literal mov try to get it cheaper */
234   if (*x == '#' &&
235       rtrackMoveALit(x))
236     return;
237
238   emitcode("mov", "a,%s", x);
239 }
240
241 /*-----------------------------------------------------------------*/
242 /* movb - moves specified value into register b                    */
243 /*-----------------------------------------------------------------*/
244 static void
245 movb (const char *x)
246 {
247   /* do some early peephole optimization */
248   if (!strncmp(x, "b", 2))
249     return;
250
251   /* if it is a literal mov try to get it cheaper */
252   if (*x == '#')
253     {
254       emitcode("mov","b,%s", rtrackGetLit(x));
255       return;
256     }
257
258   emitcode("mov","b,%s", x);
259 }
260
261 /*-----------------------------------------------------------------*/
262 /* pushB - saves register B if necessary                           */
263 /*-----------------------------------------------------------------*/
264 static bool
265 pushB (void)
266 {
267   bool pushedB = FALSE;
268
269   if (BINUSE)
270     {
271       emitcode ("push", "b");
272 //    printf("B was in use !\n");
273       pushedB = TRUE;
274     }
275   else
276     {
277       OPINB++;
278     }
279   return pushedB;
280 }
281
282 /*-----------------------------------------------------------------*/
283 /* popB - restores value of register B if necessary                */
284 /*-----------------------------------------------------------------*/
285 static void
286 popB (bool pushedB)
287 {
288   if (pushedB)
289     {
290       emitcode ("pop", "b");
291     }
292   else
293     {
294       OPINB--;
295     }
296 }
297
298 /*-----------------------------------------------------------------*/
299 /* pushReg - saves register                                        */
300 /*-----------------------------------------------------------------*/
301 static bool
302 pushReg (int index, bool bits_pushed)
303 {
304   regs * reg = REG_WITH_INDEX (index);
305   if (reg->type == REG_BIT)
306     {
307       if (!bits_pushed)
308         emitcode ("push", "%s", reg->base);
309       return TRUE;
310     }
311   else
312     emitcode ("push", "%s", reg->dname);
313   return bits_pushed;
314 }
315
316 /*-----------------------------------------------------------------*/
317 /* popReg - restores register                                      */
318 /*-----------------------------------------------------------------*/
319 static bool
320 popReg (int index, bool bits_popped)
321 {
322   regs * reg = REG_WITH_INDEX (index);
323   if (reg->type == REG_BIT)
324     {
325       if (!bits_popped)
326         emitcode ("pop", "%s", reg->base);
327       return TRUE;
328     }
329   else
330     emitcode ("pop", "%s", reg->dname);
331   return bits_popped;
332 }
333
334 /*-----------------------------------------------------------------*/
335 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
336 /*-----------------------------------------------------------------*/
337 static regs *
338 getFreePtr (iCode * ic, asmop ** aopp, bool result)
339 {
340   bool r0iu, r1iu;
341   bool r0ou, r1ou;
342
343   /* the logic: if r0 & r1 used in the instruction
344      then we are in trouble otherwise */
345
346   /* first check if r0 & r1 are used by this
347      instruction, in which case we are in trouble */
348   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
349   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
350   if (r0iu && r1iu) {
351       goto endOfWorld;
352     }
353
354   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
355   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
356
357   /* if no usage of r0 then return it */
358   if (!r0iu && !r0ou)
359     {
360       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
361       (*aopp)->type = AOP_R0;
362
363       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
364     }
365
366   /* if no usage of r1 then return it */
367   if (!r1iu && !r1ou)
368     {
369       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
370       (*aopp)->type = AOP_R1;
371
372       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
373     }
374
375   /* now we know they both have usage */
376   /* if r0 not used in this instruction */
377   if (!r0iu)
378     {
379       /* push it if not already pushed */
380       if (ic->op == IPUSH)
381         {
382           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
383           R0INB++;
384         }
385       else if (!_G.r0Pushed)
386         {
387           emitcode ("push", "%s",
388                     REG_WITH_INDEX (R0_IDX)->dname);
389           _G.r0Pushed++;
390         }
391
392       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
393       (*aopp)->type = AOP_R0;
394
395       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
396     }
397
398   /* if r1 not used then */
399
400   if (!r1iu)
401     {
402       /* push it if not already pushed */
403       if (ic->op == IPUSH)
404         {
405           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
406           R1INB++;
407         }
408       else if (!_G.r1Pushed)
409         {
410           emitcode ("push", "%s",
411                     REG_WITH_INDEX (R1_IDX)->dname);
412           _G.r1Pushed++;
413         }
414
415       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
416       (*aopp)->type = AOP_R1;
417       return REG_WITH_INDEX (R1_IDX);
418     }
419
420 endOfWorld:
421   /* I said end of world, but not quite end of world yet */
422   /* if this is a result then we can push it on the stack */
423   if (result)
424     {
425       (*aopp)->type = AOP_STK;
426       return NULL;
427     }
428   /* in the case that result AND left AND right needs a pointer reg
429      we can safely use the result's */
430   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
431     {
432       (*aopp)->type = AOP_R0;
433       return REG_WITH_INDEX (R0_IDX);
434     }
435   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
436     {
437       (*aopp)->type = AOP_R1;
438       return REG_WITH_INDEX (R1_IDX);
439     }
440
441   /* now this is REALLY the end of the world */
442   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
443           "getFreePtr should never reach here");
444   exit (1);
445 }
446
447
448 /*-----------------------------------------------------------------*/
449 /* getTempRegs - initialize an array of pointers to GPR registers */
450 /*               that are not in use. Returns 1 if the requested   */
451 /*               number of registers were available, 0 otherwise.  */
452 /*-----------------------------------------------------------------*/
453 int
454 getTempRegs(regs **tempRegs, int size, iCode *ic)
455 {
456   bitVect * freeRegs;
457   int i;
458   int offset;
459
460   if (!ic)
461     ic = _G.current_iCode;
462   if (!ic)
463     return 0;
464   if (!_G.currentFunc)
465     return 0;
466
467   freeRegs = newBitVect(8);
468   bitVectSetBit (freeRegs, R2_IDX);
469   bitVectSetBit (freeRegs, R3_IDX);
470   bitVectSetBit (freeRegs, R4_IDX);
471   bitVectSetBit (freeRegs, R5_IDX);
472   bitVectSetBit (freeRegs, R6_IDX);
473   bitVectSetBit (freeRegs, R7_IDX);
474
475   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
476     {
477       bitVect * newfreeRegs;
478       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
479       freeBitVect(freeRegs);
480       freeRegs = newfreeRegs;
481     }
482   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
483
484   offset = 0;
485   for (i=0; i<freeRegs->size; i++)
486     {
487       if (bitVectBitValue(freeRegs,i))
488         tempRegs[offset++] = REG_WITH_INDEX(i);
489       if (offset>=size)
490         {
491           freeBitVect(freeRegs);
492           return 1;
493         }
494     }
495
496   freeBitVect(freeRegs);
497   return 0;
498 }
499
500
501 /*-----------------------------------------------------------------*/
502 /* newAsmop - creates a new asmOp                                  */
503 /*-----------------------------------------------------------------*/
504 static asmop *
505 newAsmop (short type)
506 {
507   asmop *aop;
508
509   aop = Safe_calloc (1, sizeof (asmop));
510   aop->type = type;
511   aop->allocated = 1;
512   return aop;
513 }
514
515 /*-----------------------------------------------------------------*/
516 /* pointerCode - returns the code for a pointer type               */
517 /*-----------------------------------------------------------------*/
518 static int
519 pointerCode (sym_link * etype)
520 {
521
522   return PTR_TYPE (SPEC_OCLS (etype));
523
524 }
525
526 /*-----------------------------------------------------------------*/
527 /* leftRightUseAcc - returns size of accumulator use by operands   */
528 /*-----------------------------------------------------------------*/
529 static int
530 leftRightUseAcc(iCode *ic)
531 {
532   operand *op;
533   int size;
534   int accuseSize = 0;
535   int accuse = 0;
536
537   if (!ic)
538     {
539       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
540               "null iCode pointer");
541       return 0;
542     }
543
544   if (ic->op == IFX)
545     {
546       op = IC_COND (ic);
547       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
548         {
549           accuse = 1;
550           size = getSize (OP_SYMBOL (op)->type);
551           if (size>accuseSize)
552             accuseSize = size;
553         }
554     }
555   else if (ic->op == JUMPTABLE)
556     {
557       op = IC_JTCOND (ic);
558       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
559         {
560           accuse = 1;
561           size = getSize (OP_SYMBOL (op)->type);
562           if (size>accuseSize)
563             accuseSize = size;
564         }
565     }
566   else
567     {
568       op = IC_LEFT (ic);
569       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
570         {
571           accuse = 1;
572           size = getSize (OP_SYMBOL (op)->type);
573           if (size>accuseSize)
574             accuseSize = size;
575         }
576       op = IC_RIGHT (ic);
577       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
578         {
579           accuse = 1;
580           size = getSize (OP_SYMBOL (op)->type);
581           if (size>accuseSize)
582             accuseSize = size;
583         }
584     }
585
586   if (accuseSize)
587     return accuseSize;
588   else
589     return accuse;
590 }
591
592 /*-----------------------------------------------------------------*/
593 /* aopForSym - for a true symbol                                   */
594 /*-----------------------------------------------------------------*/
595 static asmop *
596 aopForSym (iCode * ic, symbol * sym, bool result)
597 {
598   asmop *aop;
599   memmap *space;
600   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
601
602   wassertl (ic != NULL, "Got a null iCode");
603   wassertl (sym != NULL, "Got a null symbol");
604
605   space = SPEC_OCLS (sym->etype);
606
607   /* if already has one */
608   if (sym->aop)
609     {
610       sym->aop->allocated++;
611       return sym->aop;
612     }
613
614   /* assign depending on the storage class */
615   /* if it is on the stack or indirectly addressable */
616   /* space we need to assign either r0 or r1 to it   */
617   if (sym->onStack || sym->iaccess)
618     {
619       sym->aop = aop = newAsmop (0);
620       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
621       aop->size = getSize (sym->type);
622
623       /* now assign the address of the variable to
624          the pointer register */
625       if (aop->type != AOP_STK)
626         {
627           if (sym->onStack)
628             {
629               signed char offset = ((sym->stack < 0) ?
630                          ((signed char) (sym->stack - _G.nRegsSaved)) :
631                          ((signed char) sym->stack)) & 0xff;
632
633               if ((abs(offset) <= 3) ||
634                   (accuse && (abs(offset) <= 7)))
635                 {
636                   emitcode ("mov", "%s,%s",
637                             aop->aopu.aop_ptr->name, SYM_BP (sym));
638                   while (offset < 0)
639                     {
640                       emitcode ("dec", aop->aopu.aop_ptr->name);
641                       offset++;
642                     }
643                   while (offset > 0)
644                     {
645                       emitcode ("inc", aop->aopu.aop_ptr->name);
646                       offset--;
647                     }
648                 }
649               else
650                 {
651                   if (accuse)
652                     emitcode ("push", "acc");
653                   emitcode ("mov", "a,%s", SYM_BP (sym));
654                   emitcode ("add", "a,#0x%02x", offset & 0xff);
655                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
656                   if (accuse)
657                     emitcode ("pop", "acc");
658                 }
659             }
660           else
661             {
662               emitcode ("mov", "%s,#%s",
663                         aop->aopu.aop_ptr->name,
664                         sym->rname);
665             }
666           aop->paged = space->paged;
667         }
668       else
669         aop->aopu.aop_stk = sym->stack;
670       return aop;
671     }
672
673   /* if in bit space */
674   if (IN_BITSPACE (space))
675     {
676       sym->aop = aop = newAsmop (AOP_CRY);
677       aop->aopu.aop_dir = sym->rname;
678       aop->size = getSize (sym->type);
679       return aop;
680     }
681   /* if it is in direct space */
682   if (IN_DIRSPACE (space))
683     {
684       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
685       //printTypeChainRaw(sym->type, NULL);
686       //printf("space = %s\n", space ? space->sname : "NULL");
687       sym->aop = aop = newAsmop (AOP_DIR);
688       aop->aopu.aop_dir = sym->rname;
689       aop->size = getSize (sym->type);
690       return aop;
691     }
692
693   /* special case for a function */
694   if (IS_FUNC (sym->type))
695     {
696       sym->aop = aop = newAsmop (AOP_IMMD);
697       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
698       aop->size = getSize (sym->type);
699       return aop;
700     }
701
702   /* only remaining is far space */
703   /* in which case DPTR gets the address */
704   sym->aop = aop = newAsmop (AOP_DPTR);
705   emitcode ("mov", "dptr,#%s", sym->rname);
706   aop->size = getSize (sym->type);
707
708   /* if it is in code space */
709   if (IN_CODESPACE (space))
710     aop->code = 1;
711
712   return aop;
713 }
714
715 /*-----------------------------------------------------------------*/
716 /* aopForRemat - rematerialzes an object                           */
717 /*-----------------------------------------------------------------*/
718 static asmop *
719 aopForRemat (symbol * sym)
720 {
721   iCode *ic = sym->rematiCode;
722   asmop *aop = newAsmop (AOP_IMMD);
723   int ptr_type = 0;
724   int val = 0;
725
726   for (;;)
727     {
728       if (ic->op == '+')
729         val += (int) operandLitValue (IC_RIGHT (ic));
730       else if (ic->op == '-')
731         val -= (int) operandLitValue (IC_RIGHT (ic));
732       else if (IS_CAST_ICODE(ic)) {
733               sym_link *from_type = operandType(IC_RIGHT(ic));
734               aop->aopu.aop_immd.from_cast_remat = 1;
735               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
736               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
737               continue;
738       } else break;
739
740       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
741     }
742
743   if (val)
744     {
745       SNPRINTF (buffer, sizeof(buffer),
746                 "(%s %c 0x%04x)",
747                 OP_SYMBOL (IC_LEFT (ic))->rname,
748                 val >= 0 ? '+' : '-',
749                 abs (val) & 0xffff);
750     }
751   else
752     {
753       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
754     }
755
756   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
757   /* set immd2 field if required */
758   if (aop->aopu.aop_immd.from_cast_remat)
759     {
760       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
761       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
762     }
763
764   return aop;
765 }
766
767 /*-----------------------------------------------------------------*/
768 /* regsInCommon - two operands have some registers in common       */
769 /*-----------------------------------------------------------------*/
770 static bool
771 regsInCommon (operand * op1, operand * op2)
772 {
773   symbol *sym1, *sym2;
774   int i;
775
776   /* if they have registers in common */
777   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
778     return FALSE;
779
780   sym1 = OP_SYMBOL (op1);
781   sym2 = OP_SYMBOL (op2);
782
783   if (sym1->nRegs == 0 || sym2->nRegs == 0)
784     return FALSE;
785
786   for (i = 0; i < sym1->nRegs; i++)
787     {
788       int j;
789       if (!sym1->regs[i])
790         continue;
791
792       for (j = 0; j < sym2->nRegs; j++)
793         {
794           if (!sym2->regs[j])
795             continue;
796
797           if (sym2->regs[j] == sym1->regs[i])
798             return TRUE;
799         }
800     }
801
802   return FALSE;
803 }
804
805 /*-----------------------------------------------------------------*/
806 /* operandsEqu - equivalent                                        */
807 /*-----------------------------------------------------------------*/
808 static bool
809 operandsEqu (operand * op1, operand * op2)
810 {
811   symbol *sym1, *sym2;
812
813   /* if they're not symbols */
814   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
815     return FALSE;
816
817   sym1 = OP_SYMBOL (op1);
818   sym2 = OP_SYMBOL (op2);
819
820   /* if both are itemps & one is spilt
821      and the other is not then false */
822   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
823       sym1->isspilt != sym2->isspilt)
824     return FALSE;
825
826   /* if they are the same */
827   if (sym1 == sym2)
828     return TRUE;
829
830   /* if they have the same rname */
831   if (sym1->rname[0] && sym2->rname[0] &&
832       strcmp (sym1->rname, sym2->rname) == 0 &&
833       !(IS_PARM (op2) && IS_ITEMP (op1)))
834     return TRUE;
835
836   /* if left is a tmp & right is not */
837   if (IS_ITEMP (op1) &&
838       !IS_ITEMP (op2) &&
839       sym1->isspilt &&
840       (sym1->usl.spillLoc == sym2))
841     return TRUE;
842
843   if (IS_ITEMP (op2) &&
844       !IS_ITEMP (op1) &&
845       sym2->isspilt &&
846       sym1->level > 0 &&
847       (sym2->usl.spillLoc == sym1))
848     return TRUE;
849
850   return FALSE;
851 }
852
853 /*-----------------------------------------------------------------*/
854 /* sameByte - two asmops have the same address at given offsets    */
855 /*-----------------------------------------------------------------*/
856 static bool
857 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
858 {
859   if (aop1 == aop2 && off1 == off2)
860     return TRUE;
861
862   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
863     return FALSE;
864
865   if (aop1->type != aop2->type)
866     return FALSE;
867
868   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
869     return FALSE;
870
871   return TRUE;
872 }
873
874 /*-----------------------------------------------------------------*/
875 /* sameRegs - two asmops have the same registers                   */
876 /*-----------------------------------------------------------------*/
877 static bool
878 sameRegs (asmop * aop1, asmop * aop2)
879 {
880   int i;
881
882   if (aop1 == aop2)
883     return TRUE;
884
885   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
886     return FALSE;
887
888   if (aop1->type != aop2->type)
889     return FALSE;
890
891   if (aop1->size != aop2->size)
892     return FALSE;
893
894   for (i = 0; i < aop1->size; i++)
895     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
896       return FALSE;
897
898   return TRUE;
899 }
900
901 /*-----------------------------------------------------------------*/
902 /* aopOp - allocates an asmop for an operand  :                    */
903 /*-----------------------------------------------------------------*/
904 static void
905 aopOp (operand * op, iCode * ic, bool result)
906 {
907   asmop *aop;
908   symbol *sym;
909   int i;
910
911   if (!op)
912     return;
913
914   /* if this a literal */
915   if (IS_OP_LITERAL (op))
916     {
917       op->aop = aop = newAsmop (AOP_LIT);
918       aop->aopu.aop_lit = op->operand.valOperand;
919       aop->size = getSize (operandType (op));
920       return;
921     }
922
923   /* if already has a asmop then continue */
924   if (op->aop)
925     {
926       op->aop->allocated++;
927       return;
928     }
929
930   /* if the underlying symbol has a aop */
931   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
932     {
933       op->aop = OP_SYMBOL (op)->aop;
934       op->aop->allocated++;
935       return;
936     }
937
938   /* if this is a true symbol */
939   if (IS_TRUE_SYMOP (op))
940     {
941       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
942       return;
943     }
944
945   /* this is a temporary : this has
946      only five choices :
947      a) register
948      b) spillocation
949      c) rematerialize
950      d) conditional
951      e) can be a return use only */
952
953   sym = OP_SYMBOL (op);
954
955   /* if the type is a conditional */
956   if (sym->regType == REG_CND)
957     {
958       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
959       aop->size = 0;
960       return;
961     }
962
963   /* if it is spilt then two situations
964      a) is rematerialize
965      b) has a spill location */
966   if (sym->isspilt || sym->nRegs == 0)
967     {
968
969       /* rematerialize it NOW */
970       if (sym->remat)
971         {
972           sym->aop = op->aop = aop = aopForRemat (sym);
973           aop->size = getSize (sym->type);
974           return;
975         }
976
977       if (sym->accuse)
978         {
979           int i;
980           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
981           aop->size = getSize (sym->type);
982           for (i = 0; i < 2; i++)
983             aop->aopu.aop_str[i] = accUse[i];
984           return;
985         }
986
987       if (sym->ruonly)
988         {
989           unsigned i;
990
991           aop = op->aop = sym->aop = newAsmop (AOP_STR);
992           aop->size = getSize (sym->type);
993           for (i = 0; i < fReturnSizeMCS51; i++)
994             aop->aopu.aop_str[i] = fReturn[i];
995           return;
996         }
997
998       if (sym->usl.spillLoc)
999         {
1000           asmop *oldAsmOp = NULL;
1001
1002           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1003             {
1004               /* force a new aop if sizes differ */
1005               oldAsmOp = sym->usl.spillLoc->aop;
1006               sym->usl.spillLoc->aop = NULL;
1007             }
1008           sym->aop = op->aop = aop =
1009                      aopForSym (ic, sym->usl.spillLoc, result);
1010           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1011             {
1012               /* Don't reuse the new aop, go with the last one */
1013               sym->usl.spillLoc->aop = oldAsmOp;
1014             }
1015           aop->size = getSize (sym->type);
1016           return;
1017         }
1018
1019       /* else must be a dummy iTemp */
1020       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1021       aop->size = getSize (sym->type);
1022       return;
1023     }
1024
1025   /* if the type is a bit register */
1026   if (sym->regType == REG_BIT)
1027     {
1028       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1029       aop->size = sym->nRegs;//1???
1030       aop->aopu.aop_reg[0] = sym->regs[0];
1031       aop->aopu.aop_dir = sym->regs[0]->name;
1032       return;
1033     }
1034
1035   /* must be in a register */
1036   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1037   aop->size = sym->nRegs;
1038   for (i = 0; i < sym->nRegs; i++)
1039     aop->aopu.aop_reg[i] = sym->regs[i];
1040 }
1041
1042 /*-----------------------------------------------------------------*/
1043 /* freeAsmop - free up the asmop given to an operand               */
1044 /*----------------------------------------------------------------*/
1045 static void
1046 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1047 {
1048   asmop *aop;
1049
1050   if (!op)
1051     aop = aaop;
1052   else
1053     aop = op->aop;
1054
1055   if (!aop)
1056     return;
1057
1058   aop->allocated--;
1059
1060   if (aop->allocated)
1061     goto dealloc;
1062
1063   /* depending on the asmop type only three cases need work
1064      AOP_R0, AOP_R1 & AOP_STK */
1065   switch (aop->type)
1066     {
1067     case AOP_R0:
1068       if (R0INB)
1069         {
1070           emitcode ("mov", "r0,b");
1071           R0INB--;
1072         }
1073       else if (_G.r0Pushed)
1074         {
1075           if (pop)
1076             {
1077               emitcode ("pop", "ar0");
1078               _G.r0Pushed--;
1079             }
1080         }
1081       bitVectUnSetBit (ic->rUsed, R0_IDX);
1082       break;
1083
1084     case AOP_R1:
1085       if (R1INB)
1086         {
1087           emitcode ("mov", "r1,b");
1088           R1INB--;
1089         }
1090       else if (_G.r1Pushed)
1091         {
1092           if (pop)
1093             {
1094               emitcode ("pop", "ar1");
1095               _G.r1Pushed--;
1096             }
1097         }
1098       bitVectUnSetBit (ic->rUsed, R1_IDX);
1099       break;
1100
1101     case AOP_STK:
1102       {
1103         int sz = aop->size;
1104         int stk = aop->aopu.aop_stk + aop->size - 1;
1105         bitVectUnSetBit (ic->rUsed, R0_IDX);
1106         bitVectUnSetBit (ic->rUsed, R1_IDX);
1107
1108         getFreePtr (ic, &aop, FALSE);
1109
1110         if (stk)
1111           {
1112             emitcode ("mov", "a,_bp");
1113             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1114             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1115           }
1116         else
1117           {
1118             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1119           }
1120
1121         while (sz--)
1122           {
1123             emitcode ("pop", "acc");
1124             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1125             if (!sz)
1126               break;
1127             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1128           }
1129         op->aop = aop;
1130         freeAsmop (op, NULL, ic, TRUE);
1131         if (_G.r1Pushed)
1132           {
1133             emitcode ("pop", "ar1");
1134             _G.r1Pushed--;
1135           }
1136         if (_G.r0Pushed)
1137           {
1138             emitcode ("pop", "ar0");
1139             _G.r0Pushed--;
1140           }
1141       }
1142       break;
1143     }
1144
1145 dealloc:
1146   /* all other cases just dealloc */
1147   if (op)
1148     {
1149       op->aop = NULL;
1150       if (IS_SYMOP (op))
1151         {
1152           OP_SYMBOL (op)->aop = NULL;
1153           /* if the symbol has a spill */
1154           if (SPIL_LOC (op))
1155             SPIL_LOC (op)->aop = NULL;
1156         }
1157     }
1158 }
1159
1160 /*------------------------------------------------------------------*/
1161 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1162 /*                      pop r0 or r1 off stack if pushed            */
1163 /*------------------------------------------------------------------*/
1164 static void
1165 freeForBranchAsmop (operand * op)
1166 {
1167   asmop *aop;
1168
1169   if (!op)
1170     return;
1171
1172   aop = op->aop;
1173
1174   if (!aop)
1175     return;
1176
1177   if (!aop->allocated)
1178     return;
1179
1180   switch (aop->type)
1181     {
1182     case AOP_R0:
1183       if (R0INB)
1184         {
1185           emitcode ("mov", "r0,b");
1186         }
1187       else if (_G.r0Pushed)
1188         {
1189           emitcode ("pop", "ar0");
1190         }
1191       break;
1192
1193     case AOP_R1:
1194       if (R1INB)
1195         {
1196           emitcode ("mov", "r1,b");
1197         }
1198       else if (_G.r1Pushed)
1199         {
1200           emitcode ("pop", "ar1");
1201         }
1202       break;
1203
1204     case AOP_STK:
1205       {
1206         int sz = aop->size;
1207         int stk = aop->aopu.aop_stk + aop->size - 1;
1208
1209         emitcode ("mov", "b,r0");
1210         if (stk)
1211           {
1212             emitcode ("mov", "a,_bp");
1213             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1214             emitcode ("mov", "r0,a");
1215           }
1216         else
1217           {
1218             emitcode ("mov", "r0,_bp");
1219           }
1220
1221         while (sz--)
1222           {
1223             emitcode ("pop", "acc");
1224             emitcode ("mov", "@r0,a");
1225             if (!sz)
1226               break;
1227             emitcode ("dec", "r0");
1228           }
1229         emitcode ("mov", "r0,b");
1230       }
1231     }
1232
1233 }
1234
1235 /*-----------------------------------------------------------------*/
1236 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1237 /*                 clobber the accumulator                         */
1238 /*-----------------------------------------------------------------*/
1239 static bool
1240 aopGetUsesAcc (operand * oper, int offset)
1241 {
1242   asmop * aop = AOP (oper);
1243
1244   if (offset > (aop->size - 1))
1245     return FALSE;
1246
1247   switch (aop->type)
1248     {
1249
1250     case AOP_R0:
1251     case AOP_R1:
1252       if (aop->paged)
1253         return TRUE;
1254       return FALSE;
1255     case AOP_DPTR:
1256       return TRUE;
1257     case AOP_IMMD:
1258       return FALSE;
1259     case AOP_DIR:
1260       return FALSE;
1261     case AOP_REG:
1262       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1263       return FALSE;
1264     case AOP_CRY:
1265       return TRUE;
1266     case AOP_ACC:
1267       if (offset)
1268         return FALSE;
1269       return TRUE;
1270     case AOP_LIT:
1271       return FALSE;
1272     case AOP_STR:
1273       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1274         return TRUE;
1275       return FALSE;
1276     case AOP_DUMMY:
1277       return FALSE;
1278     default:
1279       /* Error case --- will have been caught already */
1280       wassert(0);
1281       return FALSE;
1282     }
1283 }
1284
1285 /*-------------------------------------------------------------------*/
1286 /* aopGet - for fetching value of the aop                            */
1287 /*-------------------------------------------------------------------*/
1288 static char *
1289 aopGet (operand * oper, int offset, bool bit16, bool dname)
1290 {
1291   asmop * aop = AOP (oper);
1292
1293   /* offset is greater than
1294      size then zero */
1295   if (offset > (aop->size - 1) &&
1296       aop->type != AOP_LIT)
1297     return zero;
1298
1299   /* depending on type */
1300   switch (aop->type)
1301     {
1302     case AOP_DUMMY:
1303       return zero;
1304
1305     case AOP_R0:
1306     case AOP_R1:
1307       /* if we need to increment it */
1308       while (offset > aop->coff)
1309         {
1310           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1311           aop->coff++;
1312         }
1313
1314       while (offset < aop->coff)
1315         {
1316           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1317           aop->coff--;
1318         }
1319
1320       aop->coff = offset;
1321       if (aop->paged)
1322         {
1323           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1324           return (dname ? "acc" : "a");
1325         }
1326       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1327       return Safe_strdup(buffer);
1328
1329     case AOP_DPTR:
1330       if (aop->code && aop->coff==0 && offset>=1) {
1331         emitcode ("mov", "a,#0x%02x", offset);
1332         emitcode ("movc", "a,@a+dptr");
1333         return (dname ? "acc" : "a");
1334       }
1335
1336       while (offset > aop->coff)
1337         {
1338           emitcode ("inc", "dptr");
1339           aop->coff++;
1340         }
1341
1342       while (offset < aop->coff)
1343         {
1344           emitcode ("lcall", "__decdptr");
1345           aop->coff--;
1346         }
1347
1348       aop->coff = offset;
1349       if (aop->code)
1350         {
1351           emitcode ("clr", "a");
1352           emitcode ("movc", "a,@a+dptr");
1353         }
1354       else
1355         {
1356           emitcode ("movx", "a,@dptr");
1357         }
1358       return (dname ? "acc" : "a");
1359
1360     case AOP_IMMD:
1361       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1362         {
1363           SNPRINTF(buffer, sizeof(buffer),
1364                    "%s",aop->aopu.aop_immd.aop_immd2);
1365         }
1366       else if (bit16)
1367         {
1368           SNPRINTF(buffer, sizeof(buffer),
1369                    "#%s", aop->aopu.aop_immd.aop_immd1);
1370         }
1371       else if (offset)
1372         {
1373           SNPRINTF (buffer, sizeof(buffer),
1374                     "#(%s >> %d)",
1375                     aop->aopu.aop_immd.aop_immd1,
1376                     offset * 8);
1377         }
1378       else
1379         {
1380           SNPRINTF (buffer, sizeof(buffer),
1381                     "#%s",
1382                     aop->aopu.aop_immd.aop_immd1);
1383         }
1384       return Safe_strdup(buffer);
1385
1386     case AOP_DIR:
1387       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1388         {
1389           SNPRINTF (buffer, sizeof(buffer),
1390                     "(%s >> %d)",
1391                     aop->aopu.aop_dir, offset * 8);
1392         }
1393       else if (offset)
1394         {
1395           SNPRINTF (buffer, sizeof(buffer),
1396                     "(%s + %d)",
1397                     aop->aopu.aop_dir,
1398                     offset);
1399         }
1400       else
1401         {
1402           SNPRINTF (buffer, sizeof(buffer),
1403                     "%s",
1404                     aop->aopu.aop_dir);
1405         }
1406
1407       return Safe_strdup(buffer);
1408
1409     case AOP_REG:
1410       if (dname)
1411         return aop->aopu.aop_reg[offset]->dname;
1412       else
1413         return aop->aopu.aop_reg[offset]->name;
1414
1415     case AOP_CRY:
1416       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1417       emitcode ("clr", "a");
1418       emitcode ("rlc", "a");
1419       return (dname ? "acc" : "a");
1420
1421     case AOP_ACC:
1422       if (!offset && dname)
1423         return "acc";
1424       return aop->aopu.aop_str[offset];
1425
1426     case AOP_LIT:
1427       return aopLiteral (aop->aopu.aop_lit, offset);
1428
1429     case AOP_STR:
1430       aop->coff = offset;
1431       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1432           dname)
1433         return "acc";
1434
1435       return aop->aopu.aop_str[offset];
1436
1437     }
1438
1439   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1440           "aopget got unsupported aop->type");
1441   exit (1);
1442 }
1443
1444 /*-----------------------------------------------------------------*/
1445 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1446 /*                 clobber the accumulator                         */
1447 /*-----------------------------------------------------------------*/
1448 static bool
1449 aopPutUsesAcc (operand * oper, const char *s, int offset)
1450 {
1451   asmop * aop = AOP (oper);
1452
1453   if (offset > (aop->size - 1))
1454     return FALSE;
1455
1456   switch (aop->type)
1457     {
1458     case AOP_DUMMY:
1459       return TRUE;
1460     case AOP_DIR:
1461       return FALSE;
1462     case AOP_REG:
1463       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1464       return FALSE;
1465     case AOP_DPTR:
1466       return TRUE;
1467     case AOP_R0:
1468     case AOP_R1:
1469       return ((aop->paged) || (*s == '@'));
1470     case AOP_STK:
1471       return (*s == '@');
1472     case AOP_CRY:
1473       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1474     case AOP_STR:
1475       return FALSE;
1476     case AOP_IMMD:
1477       return FALSE;
1478     case AOP_ACC:
1479       return FALSE;
1480     default:
1481       /* Error case --- will have been caught already */
1482       wassert(0);
1483       return FALSE;
1484     }
1485 }
1486
1487 /*-----------------------------------------------------------------*/
1488 /* aopPut - puts a string for a aop and indicates if acc is in use */
1489 /*-----------------------------------------------------------------*/
1490 static bool
1491 aopPut (operand * result, const char *s, int offset)
1492 {
1493   bool bvolatile = isOperandVolatile (result, FALSE);
1494   bool accuse = FALSE;
1495   asmop * aop = AOP (result);
1496
1497   if (aop->size && offset > (aop->size - 1))
1498     {
1499       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500               "aopPut got offset > aop->size");
1501       exit (1);
1502     }
1503
1504   /* will assign value to value */
1505   /* depending on where it is ofcourse */
1506   switch (aop->type)
1507     {
1508     case AOP_DUMMY:
1509       MOVA (s);         /* read s in case it was volatile */
1510       accuse = TRUE;
1511       break;
1512
1513     case AOP_DIR:
1514       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1515         {
1516           SNPRINTF (buffer, sizeof(buffer),
1517                     "(%s >> %d)",
1518                     aop->aopu.aop_dir, offset * 8);
1519         }
1520       else if (offset)
1521         {
1522           SNPRINTF (buffer, sizeof(buffer),
1523                     "(%s + %d)",
1524                     aop->aopu.aop_dir, offset);
1525         }
1526       else
1527         {
1528           SNPRINTF (buffer, sizeof(buffer),
1529                     "%s",
1530                     aop->aopu.aop_dir);
1531         }
1532
1533       if (strcmp (buffer, s) || bvolatile)
1534         {
1535           emitcode ("mov", "%s,%s", buffer, s);
1536         }
1537       if (!strcmp (buffer, "acc"))
1538         {
1539           accuse = TRUE;
1540         }
1541       break;
1542
1543     case AOP_REG:
1544       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1545           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1546         {
1547           if (*s == '@' ||
1548               strcmp (s, "r0") == 0 ||
1549               strcmp (s, "r1") == 0 ||
1550               strcmp (s, "r2") == 0 ||
1551               strcmp (s, "r3") == 0 ||
1552               strcmp (s, "r4") == 0 ||
1553               strcmp (s, "r5") == 0 ||
1554               strcmp (s, "r6") == 0 ||
1555               strcmp (s, "r7") == 0)
1556             {
1557               emitcode ("mov", "%s,%s",
1558                         aop->aopu.aop_reg[offset]->dname, s);
1559             }
1560           else
1561             {
1562               emitcode ("mov", "%s,%s",
1563                         aop->aopu.aop_reg[offset]->name, s);
1564             }
1565         }
1566       break;
1567
1568     case AOP_DPTR:
1569       if (aop->code)
1570         {
1571           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1572                   "aopPut writing to code space");
1573           exit (1);
1574         }
1575
1576       while (offset > aop->coff)
1577         {
1578           aop->coff++;
1579           emitcode ("inc", "dptr");
1580         }
1581
1582       while (offset < aop->coff)
1583         {
1584           aop->coff--;
1585           emitcode ("lcall", "__decdptr");
1586         }
1587
1588       aop->coff = offset;
1589
1590       /* if not in accumulator */
1591       MOVA (s);
1592
1593       emitcode ("movx", "@dptr,a");
1594       break;
1595
1596     case AOP_R0:
1597     case AOP_R1:
1598       while (offset > aop->coff)
1599         {
1600           aop->coff++;
1601           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1602         }
1603       while (offset < aop->coff)
1604         {
1605           aop->coff--;
1606           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1607         }
1608       aop->coff = offset;
1609
1610       if (aop->paged)
1611         {
1612           MOVA (s);
1613           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1614         }
1615       else if (*s == '@')
1616         {
1617           MOVA (s);
1618           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1619         }
1620       else if (strcmp (s, "r0") == 0 ||
1621                strcmp (s, "r1") == 0 ||
1622                strcmp (s, "r2") == 0 ||
1623                strcmp (s, "r3") == 0 ||
1624                strcmp (s, "r4") == 0 ||
1625                strcmp (s, "r5") == 0 ||
1626                strcmp (s, "r6") == 0 ||
1627                strcmp (s, "r7") == 0)
1628         {
1629           char buffer[10];
1630           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1631           emitcode ("mov", "@%s,%s",
1632                     aop->aopu.aop_ptr->name, buffer);
1633         }
1634       else
1635         {
1636           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1637         }
1638       break;
1639
1640     case AOP_STK:
1641       if (strcmp (s, "a") == 0)
1642         {
1643           emitcode ("push", "acc");
1644         }
1645       else if (*s=='@')
1646         {
1647           MOVA(s);
1648           emitcode ("push", "acc");
1649         }
1650       else if (strcmp (s, "r0") == 0 ||
1651                strcmp (s, "r1") == 0 ||
1652                strcmp (s, "r2") == 0 ||
1653                strcmp (s, "r3") == 0 ||
1654                strcmp (s, "r4") == 0 ||
1655                strcmp (s, "r5") == 0 ||
1656                strcmp (s, "r6") == 0 ||
1657                strcmp (s, "r7") == 0)
1658         {
1659           char buffer[10];
1660           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1661           emitcode ("push", buffer);
1662         }
1663       else
1664         {
1665           emitcode ("push", s);
1666         }
1667
1668       break;
1669
1670     case AOP_CRY:
1671       /* if result no bit variable */
1672       if (!aop->aopu.aop_dir)
1673         {
1674           assert (!strcmp (s, "c"));
1675           /* inefficient: move carry into A and use jz/jnz */
1676           emitcode ("clr", "a");
1677           emitcode ("rlc", "a");
1678           accuse = TRUE;
1679         }
1680       else if (s == zero)
1681           emitcode ("clr", "%s", aop->aopu.aop_dir);
1682       else if (s == one)
1683           emitcode ("setb", "%s", aop->aopu.aop_dir);
1684       else if (!strcmp (s, "c"))
1685           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1686       else if (strcmp (s, aop->aopu.aop_dir))
1687         {
1688           MOVA (s);
1689           /* set C, if a >= 1 */
1690           emitcode ("add", "a,#0xff");
1691           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1692         }
1693       break;
1694
1695     case AOP_STR:
1696       aop->coff = offset;
1697       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1698         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1699       break;
1700
1701     case AOP_ACC:
1702       accuse = TRUE;
1703       aop->coff = offset;
1704       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1705         break;
1706
1707       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1708         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1709       break;
1710
1711     default:
1712       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1713               "aopPut got unsupported aop->type");
1714       exit (1);
1715     }
1716
1717     return accuse;
1718 }
1719
1720
1721 #if 0
1722 /*-----------------------------------------------------------------*/
1723 /* pointToEnd :- points to the last byte of the operand            */
1724 /*-----------------------------------------------------------------*/
1725 static void
1726 pointToEnd (asmop * aop)
1727 {
1728   int count;
1729   if (!aop)
1730     return;
1731
1732   aop->coff = count = (aop->size - 1);
1733   switch (aop->type)
1734     {
1735     case AOP_R0:
1736     case AOP_R1:
1737       while (count--)
1738         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1739       break;
1740     case AOP_DPTR:
1741       while (count--)
1742         emitcode ("inc", "dptr");
1743       break;
1744     }
1745
1746 }
1747 #endif
1748
1749 /*-----------------------------------------------------------------*/
1750 /* reAdjustPreg - points a register back to where it should        */
1751 /*-----------------------------------------------------------------*/
1752 static void
1753 reAdjustPreg (asmop * aop)
1754 {
1755   if ((aop->coff==0) || (aop->size <= 1))
1756     return;
1757
1758   switch (aop->type)
1759     {
1760     case AOP_R0:
1761     case AOP_R1:
1762       while (aop->coff--)
1763         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1764       break;
1765     case AOP_DPTR:
1766       while (aop->coff--)
1767         {
1768           emitcode ("lcall", "__decdptr");
1769         }
1770       break;
1771     }
1772   aop->coff = 0;
1773 }
1774
1775 /*-----------------------------------------------------------------*/
1776 /* opIsGptr: returns non-zero if the passed operand is       */
1777 /* a generic pointer type.             */
1778 /*-----------------------------------------------------------------*/
1779 static int
1780 opIsGptr (operand * op)
1781 {
1782   sym_link *type = operandType (op);
1783
1784   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1785     {
1786       return 1;
1787     }
1788   return 0;
1789 }
1790
1791 /*-----------------------------------------------------------------*/
1792 /* getDataSize - get the operand data size                         */
1793 /*-----------------------------------------------------------------*/
1794 static int
1795 getDataSize (operand * op)
1796 {
1797   int size;
1798   size = AOP_SIZE (op);
1799   if (size == GPTRSIZE)
1800     {
1801       sym_link *type = operandType (op);
1802       if (IS_GENPTR (type))
1803         {
1804           /* generic pointer; arithmetic operations
1805            * should ignore the high byte (pointer type).
1806            */
1807           size--;
1808         }
1809     }
1810   return size;
1811 }
1812
1813 /*-----------------------------------------------------------------*/
1814 /* outAcc - output Acc                                             */
1815 /*-----------------------------------------------------------------*/
1816 static void
1817 outAcc (operand * result)
1818 {
1819   int size, offset;
1820   size = getDataSize (result);
1821   if (size)
1822     {
1823       aopPut (result, "a", 0);
1824       size--;
1825       offset = 1;
1826       /* unsigned or positive */
1827       while (size--)
1828         {
1829           aopPut (result, zero, offset++);
1830         }
1831     }
1832 }
1833
1834 /*-----------------------------------------------------------------*/
1835 /* outBitC - output a bit C                                        */
1836 /*-----------------------------------------------------------------*/
1837 static void
1838 outBitC (operand * result)
1839 {
1840   /* if the result is bit */
1841   if (AOP_TYPE (result) == AOP_CRY)
1842     {
1843       aopPut (result, "c", 0);
1844     }
1845   else
1846     {
1847       emitcode ("clr", "a");
1848       emitcode ("rlc", "a");
1849       outAcc (result);
1850     }
1851 }
1852
1853 /*-----------------------------------------------------------------*/
1854 /* toBoolean - emit code for orl a,operator(sizeop)                */
1855 /*-----------------------------------------------------------------*/
1856 static void
1857 toBoolean (operand * oper)
1858 {
1859   int size = AOP_SIZE (oper) - 1;
1860   int offset = 1;
1861   bool AccUsed = FALSE;
1862   bool pushedB;
1863
1864   while (!AccUsed && size--)
1865     {
1866       AccUsed |= aopGetUsesAcc(oper, offset++);
1867     }
1868
1869   size = AOP_SIZE (oper) - 1;
1870   offset = 1;
1871   MOVA (aopGet (oper, 0, FALSE, FALSE));
1872   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1873     {
1874       pushedB = pushB ();
1875       emitcode("mov", "b,a");
1876       while (--size)
1877         {
1878           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1879           emitcode ("orl", "b,a");
1880         }
1881       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1882       emitcode ("orl", "a,b");
1883       popB (pushedB);
1884     }
1885   else
1886     {
1887       while (size--)
1888         {
1889           emitcode ("orl", "a,%s",
1890                     aopGet (oper, offset++, FALSE, FALSE));
1891         }
1892     }
1893 }
1894
1895 /*-----------------------------------------------------------------*/
1896 /* toCarry - make boolean and move into carry                      */
1897 /*-----------------------------------------------------------------*/
1898 static void
1899 toCarry (operand * oper)
1900 {
1901   /* if the operand is a literal then
1902      we know what the value is */
1903   if (AOP_TYPE (oper) == AOP_LIT)
1904     {
1905       if ((int) operandLitValue (oper))
1906         SETC;
1907       else
1908         CLRC;
1909     }
1910   else if (AOP_TYPE (oper) == AOP_CRY)
1911     {
1912       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1913     }
1914   else
1915     {
1916       /* or the operand into a */
1917       toBoolean (oper);
1918       /* set C, if a >= 1 */
1919       emitcode ("add", "a,#0xff");
1920     }
1921 }
1922
1923 /*-----------------------------------------------------------------*/
1924 /* assignBit - assign operand to bit operand                       */
1925 /*-----------------------------------------------------------------*/
1926 static void
1927 assignBit (operand * result, operand * right)
1928 {
1929   /* if the right side is a literal then
1930      we know what the value is */
1931   if (AOP_TYPE (right) == AOP_LIT)
1932     {
1933       if ((int) operandLitValue (right))
1934         aopPut (result, one, 0);
1935       else
1936         aopPut (result, zero, 0);
1937     }
1938   else
1939     {
1940       toCarry (right);
1941       aopPut (result, "c", 0);
1942     }
1943 }
1944
1945
1946 /*-------------------------------------------------------------------*/
1947 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1948 /*-------------------------------------------------------------------*/
1949 static char *
1950 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1951 {
1952   char * l;
1953
1954   if (aopGetUsesAcc (oper, offset))
1955     {
1956       emitcode("mov", "b,a");
1957       MOVA (aopGet (oper, offset, bit16, dname));
1958       emitcode("xch", "a,b");
1959       aopPut (oper, "a", offset);
1960       emitcode("xch", "a,b");
1961       l = "b";
1962     }
1963   else
1964     {
1965       l = aopGet (oper, offset, bit16, dname);
1966       emitcode("xch", "a,%s", l);
1967     }
1968   return l;
1969 }
1970
1971
1972 /*-----------------------------------------------------------------*/
1973 /* genNot - generate code for ! operation                          */
1974 /*-----------------------------------------------------------------*/
1975 static void
1976 genNot (iCode * ic)
1977 {
1978   symbol *tlbl;
1979
1980   D (emitcode (";", "genNot"));
1981
1982   /* assign asmOps to operand & result */
1983   aopOp (IC_LEFT (ic), ic, FALSE);
1984   aopOp (IC_RESULT (ic), ic, TRUE);
1985
1986   /* if in bit space then a special case */
1987   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1988     {
1989       /* if left==result then cpl bit */
1990       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1991         {
1992           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1993         }
1994       else
1995         {
1996           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1997           emitcode ("cpl", "c");
1998           outBitC (IC_RESULT (ic));
1999         }
2000       goto release;
2001     }
2002
2003   toBoolean (IC_LEFT (ic));
2004
2005   /* set C, if a == 0 */
2006   tlbl = newiTempLabel (NULL);
2007   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2008   emitLabel (tlbl);
2009   outBitC (IC_RESULT (ic));
2010
2011 release:
2012   /* release the aops */
2013   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2014   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2015 }
2016
2017
2018 /*-----------------------------------------------------------------*/
2019 /* genCpl - generate code for complement                           */
2020 /*-----------------------------------------------------------------*/
2021 static void
2022 genCpl (iCode * ic)
2023 {
2024   int offset = 0;
2025   int size;
2026   symbol *tlbl;
2027   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2028
2029   D(emitcode (";", "genCpl"));
2030
2031   /* assign asmOps to operand & result */
2032   aopOp (IC_LEFT (ic), ic, FALSE);
2033   aopOp (IC_RESULT (ic), ic, TRUE);
2034
2035   /* special case if in bit space */
2036   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2037     {
2038       char *l;
2039
2040       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2041           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2042         {
2043           /* promotion rules are responsible for this strange result:
2044              bit -> int -> ~int -> bit
2045              uchar -> int -> ~int -> bit
2046           */
2047           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2048           goto release;
2049         }
2050
2051       tlbl=newiTempLabel(NULL);
2052       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2053       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2054           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2055           IS_AOP_PREG (IC_LEFT (ic)))
2056         {
2057           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2058         }
2059       else
2060         {
2061           MOVA (l);
2062           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2063         }
2064       emitLabel (tlbl);
2065       outBitC (IC_RESULT(ic));
2066       goto release;
2067     }
2068
2069   size = AOP_SIZE (IC_RESULT (ic));
2070   while (size--)
2071     {
2072       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2073       MOVA (l);
2074       emitcode ("cpl", "a");
2075       aopPut (IC_RESULT (ic), "a", offset++);
2076     }
2077
2078
2079 release:
2080   /* release the aops */
2081   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2082   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2083 }
2084
2085 /*-----------------------------------------------------------------*/
2086 /* genUminusFloat - unary minus for floating points                */
2087 /*-----------------------------------------------------------------*/
2088 static void
2089 genUminusFloat (operand * op, operand * result)
2090 {
2091   int size, offset = 0;
2092   char *l;
2093
2094   D (emitcode (";", "genUminusFloat"));
2095
2096   /* for this we just copy and then flip the bit */
2097
2098   size = AOP_SIZE (op) - 1;
2099
2100   while (size--)
2101     {
2102       aopPut (result,
2103               aopGet (op, offset, FALSE, FALSE),
2104               offset);
2105       offset++;
2106     }
2107
2108   l = aopGet (op, offset, FALSE, FALSE);
2109   MOVA (l);
2110
2111   emitcode ("cpl", "acc.7");
2112   aopPut (result, "a", offset);
2113 }
2114
2115 /*-----------------------------------------------------------------*/
2116 /* genUminus - unary minus code generation                         */
2117 /*-----------------------------------------------------------------*/
2118 static void
2119 genUminus (iCode * ic)
2120 {
2121   int offset, size;
2122   sym_link *optype;
2123
2124   D (emitcode (";", "genUminus"));
2125
2126   /* assign asmops */
2127   aopOp (IC_LEFT (ic), ic, FALSE);
2128   aopOp (IC_RESULT (ic), ic, TRUE);
2129
2130   /* if both in bit space then special
2131      case */
2132   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2133       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2134     {
2135
2136       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2137       emitcode ("cpl", "c");
2138       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2139       goto release;
2140     }
2141
2142   optype = operandType (IC_LEFT (ic));
2143
2144   /* if float then do float stuff */
2145   if (IS_FLOAT (optype))
2146     {
2147       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2148       goto release;
2149     }
2150
2151   /* otherwise subtract from zero */
2152   size = AOP_SIZE (IC_LEFT (ic));
2153   offset = 0;
2154   while (size--)
2155     {
2156       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2157       if (!strcmp (l, "a"))
2158         {
2159           if (offset == 0)
2160             SETC;
2161           emitcode ("cpl", "a");
2162           emitcode ("addc", "a,#0");
2163         }
2164       else
2165         {
2166           if (offset == 0)
2167             CLRC;
2168           emitcode ("clr", "a");
2169           emitcode ("subb", "a,%s", l);
2170         }
2171       aopPut (IC_RESULT (ic), "a", offset++);
2172     }
2173
2174   /* if any remaining bytes in the result */
2175   /* we just need to propagate the sign   */
2176   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2177     {
2178       emitcode ("rlc", "a");
2179       emitcode ("subb", "a,acc");
2180       while (size--)
2181         aopPut (IC_RESULT (ic), "a", offset++);
2182     }
2183
2184 release:
2185   /* release the aops */
2186   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2187   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2188 }
2189
2190 /*-----------------------------------------------------------------*/
2191 /* saveRegisters - will look for a call and save the registers     */
2192 /*-----------------------------------------------------------------*/
2193 static void
2194 saveRegisters (iCode * lic)
2195 {
2196   int i;
2197   iCode *ic;
2198   bitVect *rsave;
2199
2200   /* look for call */
2201   for (ic = lic; ic; ic = ic->next)
2202     if (ic->op == CALL || ic->op == PCALL)
2203       break;
2204
2205   if (!ic)
2206     {
2207       fprintf (stderr, "found parameter push with no function call\n");
2208       return;
2209     }
2210
2211   /* if the registers have been saved already or don't need to be then
2212      do nothing */
2213   if (ic->regsSaved)
2214     return;
2215   if (IS_SYMOP(IC_LEFT(ic)) &&
2216       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2217        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2218     return;
2219
2220   /* save the registers in use at this time but skip the
2221      ones for the result */
2222   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2223                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2224
2225   ic->regsSaved = 1;
2226   if (options.useXstack)
2227     {
2228       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2229       int nBits = bitVectnBitsOn (rsavebits);
2230       int count = bitVectnBitsOn (rsave);
2231
2232       if (nBits != 0)
2233         {
2234           count = count - nBits + 1;
2235           /* remove all but the first bits as they are pushed all at once */
2236           rsave = bitVectCplAnd (rsave, rsavebits);
2237           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2238         }
2239
2240       if (count == 1)
2241         {
2242           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2243           if (reg->type == REG_BIT)
2244             {
2245               emitcode ("mov", "a,%s", reg->base);
2246             }
2247           else
2248             {
2249               emitcode ("mov", "a,%s", reg->name);
2250             }
2251           emitcode ("mov", "r0,%s", spname);
2252           emitcode ("inc", "%s", spname);// allocate before use
2253           emitcode ("movx", "@r0,a");
2254           if (bitVectBitValue (rsave, R0_IDX))
2255             emitcode ("mov", "r0,a");
2256         }
2257       else if (count != 0)
2258         {
2259           if (bitVectBitValue (rsave, R0_IDX))
2260             {
2261               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2262             }
2263           emitcode ("mov", "r0,%s", spname);
2264           MOVA ("r0");
2265           emitcode ("add", "a,#%d", count);
2266           emitcode ("mov", "%s,a", spname);
2267           for (i = 0; i < mcs51_nRegs; i++)
2268             {
2269               if (bitVectBitValue (rsave, i))
2270                 {
2271                   regs * reg = REG_WITH_INDEX (i);
2272                   if (i == R0_IDX)
2273                     {
2274                       emitcode ("pop", "acc");
2275                       emitcode ("push", "acc");
2276                     }
2277                   else if (reg->type == REG_BIT)
2278                     {
2279                       emitcode ("mov", "a,%s", reg->base);
2280                     }
2281                   else
2282                     {
2283                       emitcode ("mov", "a,%s", reg->name);
2284                     }
2285                   emitcode ("movx", "@r0,a");
2286                   if (--count)
2287                     {
2288                       emitcode ("inc", "r0");
2289                     }
2290                 }
2291             }
2292           if (bitVectBitValue (rsave, R0_IDX))
2293             {
2294               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2295             }
2296         }
2297     }
2298   else
2299     {
2300       bool bits_pushed = FALSE;
2301       for (i = 0; i < mcs51_nRegs; i++)
2302         {
2303           if (bitVectBitValue (rsave, i))
2304             {
2305               bits_pushed = pushReg (i, bits_pushed);
2306             }
2307         }
2308     }
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
2339       if (count == 1)
2340         {
2341           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2342           emitcode ("mov", "r0,%s", spname);
2343           emitcode ("dec", "r0");
2344           emitcode ("movx", "a,@r0");
2345           if (reg->type == REG_BIT)
2346             {
2347               emitcode ("mov", "%s,a", reg->base);
2348             }
2349           else
2350             {
2351               emitcode ("mov", "%s,a", reg->name);
2352             }
2353           emitcode ("dec", "%s", spname);
2354         }
2355       else if (count != 0)
2356         {
2357           emitcode ("mov", "r0,%s", spname);
2358           for (i = mcs51_nRegs; i >= 0; i--)
2359             {
2360               if (bitVectBitValue (rsave, i))
2361                 {
2362                   regs * reg = REG_WITH_INDEX (i);
2363                   emitcode ("dec", "r0");
2364                   emitcode ("movx", "a,@r0");
2365                   if (i == R0_IDX)
2366                     {
2367                       emitcode ("push", "acc");
2368                     }
2369                   else if (reg->type == REG_BIT)
2370                     {
2371                       emitcode ("mov", "%s,a", reg->base);
2372                     }
2373                   else
2374                     {
2375                       emitcode ("mov", "%s,a", reg->name);
2376                     }
2377                 }
2378             }
2379           emitcode ("mov", "%s,r0", spname);
2380           if (bitVectBitValue (rsave, R0_IDX))
2381             {
2382               emitcode ("pop", "ar0");
2383             }
2384         }
2385     }
2386   else
2387     {
2388       bool bits_popped = FALSE;
2389       for (i = mcs51_nRegs; i >= 0; i--)
2390         {
2391           if (bitVectBitValue (rsave, i))
2392             {
2393               bits_popped = popReg (i, bits_popped);
2394             }
2395         }
2396     }
2397 }
2398
2399
2400 /*-----------------------------------------------------------------*/
2401 /* pushSide -                                                      */
2402 /*-----------------------------------------------------------------*/
2403 static void
2404 pushSide (operand * oper, int size)
2405 {
2406   int offset = 0;
2407   while (size--)
2408     {
2409       char *l = aopGet (oper, offset++, FALSE, TRUE);
2410       if (AOP_TYPE (oper) != AOP_REG &&
2411           AOP_TYPE (oper) != AOP_DIR &&
2412           strcmp (l, "a"))
2413         {
2414           MOVA (l);
2415           emitcode ("push", "acc");
2416         }
2417       else
2418         {
2419           emitcode ("push", "%s", l);
2420         }
2421     }
2422 }
2423
2424 /*-----------------------------------------------------------------*/
2425 /* assignResultValue - also indicates if acc is in use afterwards  */
2426 /*-----------------------------------------------------------------*/
2427 static bool
2428 assignResultValue (operand * oper, operand * func)
2429 {
2430   int offset = 0;
2431   int size = AOP_SIZE (oper);
2432   bool accuse = FALSE;
2433   bool pushedA = FALSE;
2434
2435   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2436     {
2437       outBitC (oper);
2438       return FALSE;
2439     }
2440
2441   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2442     {
2443       emitcode ("push", "acc");
2444       pushedA = TRUE;
2445     }
2446   while (size--)
2447     {
2448       if ((offset == 3) && pushedA)
2449         emitcode ("pop", "acc");
2450       accuse |= aopPut (oper, fReturn[offset], offset);
2451       offset++;
2452     }
2453   return accuse;
2454 }
2455
2456
2457 /*-----------------------------------------------------------------*/
2458 /* genXpush - pushes onto the external stack                       */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 genXpush (iCode * ic)
2462 {
2463   asmop *aop = newAsmop (0);
2464   regs *r;
2465   int size, offset = 0;
2466
2467   D (emitcode (";", "genXpush"));
2468
2469   aopOp (IC_LEFT (ic), ic, FALSE);
2470   r = getFreePtr (ic, &aop, FALSE);
2471
2472   size = AOP_SIZE (IC_LEFT (ic));
2473
2474   if (size == 1)
2475     {
2476       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2477       emitcode ("mov", "%s,%s", r->name, spname);
2478       emitcode ("inc", "%s", spname); // allocate space first
2479       emitcode ("movx", "@%s,a", r->name);
2480     }
2481   else
2482     {
2483       // allocate space first
2484       emitcode ("mov", "%s,%s", r->name, spname);
2485       MOVA (r->name);
2486       emitcode ("add", "a,#%d", size);
2487       emitcode ("mov", "%s,a", spname);
2488
2489       while (size--)
2490         {
2491           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2492           emitcode ("movx", "@%s,a", r->name);
2493           emitcode ("inc", "%s", r->name);
2494         }
2495     }
2496
2497   freeAsmop (NULL, aop, ic, TRUE);
2498   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2499 }
2500
2501 /*-----------------------------------------------------------------*/
2502 /* genIpush - generate code for pushing this gets a little complex */
2503 /*-----------------------------------------------------------------*/
2504 static void
2505 genIpush (iCode * ic)
2506 {
2507   int size, offset = 0;
2508   char *l;
2509   char *prev = "";
2510
2511   D (emitcode (";", "genIpush"));
2512
2513   /* if this is not a parm push : ie. it is spill push
2514      and spill push is always done on the local stack */
2515   if (!ic->parmPush)
2516     {
2517
2518       /* and the item is spilt then do nothing */
2519       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2520         return;
2521
2522       aopOp (IC_LEFT (ic), ic, FALSE);
2523       size = AOP_SIZE (IC_LEFT (ic));
2524       /* push it on the stack */
2525       while (size--)
2526         {
2527           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2528           if (*l == '#')
2529             {
2530               MOVA (l);
2531               l = "acc";
2532             }
2533           emitcode ("push", "%s", l);
2534         }
2535       return;
2536     }
2537
2538   /* this is a parameter push: in this case we call
2539      the routine to find the call and save those
2540      registers that need to be saved */
2541   saveRegisters (ic);
2542
2543   /* if use external stack then call the external
2544      stack pushing routine */
2545   if (options.useXstack)
2546     {
2547       genXpush (ic);
2548       return;
2549     }
2550
2551   /* then do the push */
2552   aopOp (IC_LEFT (ic), ic, FALSE);
2553
2554   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2555   size = AOP_SIZE (IC_LEFT (ic));
2556
2557   while (size--)
2558     {
2559       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2560       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2561           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2562         {
2563           if (strcmp (l, prev) || *l == '@')
2564             MOVA (l);
2565           emitcode ("push", "acc");
2566         }
2567       else
2568         {
2569           emitcode ("push", "%s", l);
2570         }
2571       prev = l;
2572     }
2573
2574   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2575 }
2576
2577 /*-----------------------------------------------------------------*/
2578 /* genIpop - recover the registers: can happen only for spilling   */
2579 /*-----------------------------------------------------------------*/
2580 static void
2581 genIpop (iCode * ic)
2582 {
2583   int size, offset;
2584
2585   D (emitcode (";", "genIpop"));
2586
2587   /* if the temp was not pushed then */
2588   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2589     return;
2590
2591   aopOp (IC_LEFT (ic), ic, FALSE);
2592   size = AOP_SIZE (IC_LEFT (ic));
2593   offset = (size - 1);
2594   while (size--)
2595     {
2596       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2597                                      FALSE, TRUE));
2598     }
2599
2600   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2601 }
2602
2603 /*-----------------------------------------------------------------*/
2604 /* saveRBank - saves an entire register bank on the stack          */
2605 /*-----------------------------------------------------------------*/
2606 static void
2607 saveRBank (int bank, iCode * ic, bool pushPsw)
2608 {
2609   int i;
2610   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2611   asmop *aop = NULL;
2612   regs *r = NULL;
2613
2614   if (options.useXstack)
2615     {
2616       if (!ic)
2617         {
2618           /* Assume r0 is available for use. */
2619           r = REG_WITH_INDEX (R0_IDX);;
2620         }
2621       else
2622         {
2623           aop = newAsmop (0);
2624           r = getFreePtr (ic, &aop, FALSE);
2625         }
2626       // allocate space first
2627       emitcode ("mov", "%s,%s", r->name, spname);
2628       MOVA (r->name);
2629       emitcode ("add", "a,#%d", count);
2630       emitcode ("mov", "%s,a", spname);
2631     }
2632
2633   for (i = 0; i < 8; i++)
2634     {
2635       if (options.useXstack)
2636         {
2637           emitcode ("mov", "a,(%s+%d)",
2638                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2639           emitcode ("movx", "@%s,a", r->name);
2640           if (--count)
2641             emitcode ("inc", "%s", r->name);
2642         }
2643       else
2644         emitcode ("push", "(%s+%d)",
2645                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2646     }
2647
2648   if (mcs51_nRegs > 8)
2649     {
2650       if (options.useXstack)
2651         {
2652           emitcode ("mov", "a,bits");
2653           emitcode ("movx", "@%s,a", r->name);
2654           if (--count)
2655             emitcode ("inc", "%s", r->name);
2656         }
2657       else
2658         {
2659           emitcode ("push", "bits");
2660         }
2661       BitBankUsed = 1;
2662     }
2663
2664   if (pushPsw)
2665     {
2666       if (options.useXstack)
2667         {
2668           emitcode ("mov", "a,psw");
2669           emitcode ("movx", "@%s,a", r->name);
2670         }
2671       else
2672         {
2673           emitcode ("push", "psw");
2674         }
2675
2676       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2677     }
2678
2679   if (aop)
2680     {
2681       freeAsmop (NULL, aop, ic, TRUE);
2682     }
2683
2684   if (ic)
2685   {
2686     ic->bankSaved = 1;
2687   }
2688 }
2689
2690 /*-----------------------------------------------------------------*/
2691 /* unsaveRBank - restores the register bank from stack             */
2692 /*-----------------------------------------------------------------*/
2693 static void
2694 unsaveRBank (int bank, iCode * ic, bool popPsw)
2695 {
2696   int i;
2697   asmop *aop = NULL;
2698   regs *r = NULL;
2699
2700   if (options.useXstack)
2701     {
2702       if (!ic)
2703         {
2704           /* Assume r0 is available for use. */
2705           r = REG_WITH_INDEX (R0_IDX);;
2706         }
2707       else
2708         {
2709           aop = newAsmop (0);
2710           r = getFreePtr (ic, &aop, FALSE);
2711         }
2712       emitcode ("mov", "%s,%s", r->name, spname);
2713     }
2714
2715   if (popPsw)
2716     {
2717       if (options.useXstack)
2718         {
2719           emitcode ("dec", "%s", r->name);
2720           emitcode ("movx", "a,@%s", r->name);
2721           emitcode ("mov", "psw,a");
2722         }
2723       else
2724         {
2725           emitcode ("pop", "psw");
2726         }
2727     }
2728
2729   if (mcs51_nRegs > 8)
2730     {
2731       if (options.useXstack)
2732         {
2733           emitcode ("dec", "%s", r->name);
2734           emitcode ("movx", "a,@%s", r->name);
2735           emitcode ("mov", "bits,a");
2736         }
2737       else
2738         {
2739           emitcode ("pop", "bits");
2740         }
2741     }
2742
2743   for (i = 7; i >= 0; i--)
2744     {
2745       if (options.useXstack)
2746         {
2747           emitcode ("dec", "%s", r->name);
2748           emitcode ("movx", "a,@%s", r->name);
2749           emitcode ("mov", "(%s+%d),a",
2750                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2751         }
2752       else
2753         {
2754           emitcode ("pop", "(%s+%d)",
2755                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2756         }
2757     }
2758
2759   if (options.useXstack)
2760     {
2761       emitcode ("mov", "%s,%s", spname, r->name);
2762     }
2763
2764   if (aop)
2765     {
2766       freeAsmop (NULL, aop, ic, TRUE);
2767     }
2768 }
2769
2770 /*-----------------------------------------------------------------*/
2771 /* genSend - gen code for SEND                                     */
2772 /*-----------------------------------------------------------------*/
2773 static void genSend(set *sendSet)
2774 {
2775   iCode *sic;
2776   int bit_count = 0;
2777
2778   /* first we do all bit parameters */
2779   for (sic = setFirstItem (sendSet); sic;
2780        sic = setNextItem (sendSet))
2781     {
2782       if (sic->argreg > 12)
2783         {
2784           int bit = sic->argreg-13;
2785
2786           aopOp (IC_LEFT (sic), sic, FALSE);
2787
2788           /* if left is a literal then
2789              we know what the value is */
2790           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2791             {
2792               if (((int) operandLitValue (IC_LEFT (sic))))
2793                   emitcode ("setb", "b[%d]", bit);
2794               else
2795                   emitcode ("clr", "b[%d]", bit);
2796             }
2797           else
2798             {
2799               /* we need to or */
2800               toCarry (IC_LEFT (sic));
2801               emitcode ("mov", "b[%d],c", bit);
2802             }
2803           bit_count++;
2804           BitBankUsed = 1;
2805
2806           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2807         }
2808     }
2809
2810   if (bit_count)
2811     {
2812       saveRegisters (setFirstItem (sendSet));
2813       emitcode ("mov", "bits,b");
2814     }
2815
2816   /* then we do all other parameters */
2817   for (sic = setFirstItem (sendSet); sic;
2818        sic = setNextItem (sendSet))
2819     {
2820       if (sic->argreg <= 12)
2821         {
2822           int size, offset = 0;
2823           aopOp (IC_LEFT (sic), sic, FALSE);
2824           size = AOP_SIZE (IC_LEFT (sic));
2825
2826           if (sic->argreg == 1)
2827             {
2828               while (size--)
2829                 {
2830                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2831                   if (strcmp (l, fReturn[offset]))
2832                     {
2833                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2834                     }
2835                   offset++;
2836                 }
2837             }
2838           else
2839             {
2840               while (size--)
2841                 {
2842                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2843                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2844                   offset++;
2845                 }
2846             }
2847           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2848         }
2849     }
2850 }
2851
2852 /*-----------------------------------------------------------------*/
2853 /* selectRegBank - emit code to select the register bank           */
2854 /*-----------------------------------------------------------------*/
2855 static void
2856 selectRegBank (short bank, bool keepFlags)
2857 {
2858   /* if f.e. result is in carry */
2859   if (keepFlags)
2860     {
2861       emitcode ("anl", "psw,#0xE7");
2862       if (bank)
2863         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2864     }
2865   else
2866     {
2867       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2868     }
2869 }
2870
2871 /*-----------------------------------------------------------------*/
2872 /* genCall - generates a call statement                            */
2873 /*-----------------------------------------------------------------*/
2874 static void
2875 genCall (iCode * ic)
2876 {
2877   sym_link *dtype;
2878   sym_link *etype;
2879 //  bool restoreBank = FALSE;
2880   bool swapBanks = FALSE;
2881   bool accuse = FALSE;
2882   bool accPushed = FALSE;
2883   bool resultInF0 = FALSE;
2884   bool assignResultGenerated = FALSE;
2885
2886   D (emitcode (";", "genCall"));
2887
2888   dtype = operandType (IC_LEFT (ic));
2889   etype = getSpec(dtype);
2890   /* if send set is not empty then assign */
2891   if (_G.sendSet)
2892     {
2893         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2894             genSend(reverseSet(_G.sendSet));
2895         } else {
2896             genSend(_G.sendSet);
2897         }
2898       _G.sendSet = NULL;
2899     }
2900
2901   /* if we are calling a not _naked function that is not using
2902      the same register bank then we need to save the
2903      destination registers on the stack */
2904   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2905       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2906        !IFFUNC_ISISR (dtype))
2907     {
2908       swapBanks = TRUE;
2909     }
2910
2911   /* if caller saves & we have not saved then */
2912   if (!ic->regsSaved)
2913       saveRegisters (ic);
2914
2915   if (swapBanks)
2916     {
2917         emitcode ("mov", "psw,#0x%02x",
2918            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2919     }
2920
2921   /* make the call */
2922   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2923     {
2924       if (IFFUNC_CALLEESAVES(dtype))
2925         {
2926           werror (E_BANKED_WITH_CALLEESAVES);
2927         }
2928       else
2929         {
2930           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2931                      OP_SYMBOL (IC_LEFT (ic))->rname :
2932                      OP_SYMBOL (IC_LEFT (ic))->name);
2933
2934           emitcode ("mov", "r0,#%s", l);
2935           emitcode ("mov", "r1,#(%s >> 8)", l);
2936           emitcode ("mov", "r2,#(%s >> 16)", l);
2937           emitcode ("lcall", "__sdcc_banked_call");
2938         }
2939     }
2940   else
2941     {
2942       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2943                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2944                                 OP_SYMBOL (IC_LEFT (ic))->name));
2945     }
2946
2947   if (swapBanks)
2948     {
2949       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2950     }
2951
2952   /* if we need assign a result value */
2953   if ((IS_ITEMP (IC_RESULT (ic)) &&
2954        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2955        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2956         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2957         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2958       IS_TRUE_SYMOP (IC_RESULT (ic)))
2959     {
2960
2961       _G.accInUse++;
2962       aopOp (IC_RESULT (ic), ic, FALSE);
2963       _G.accInUse--;
2964
2965       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2966       assignResultGenerated = TRUE;
2967
2968       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2969     }
2970
2971   /* adjust the stack for parameters if required */
2972   if (ic->parmBytes)
2973     {
2974       int i;
2975       if (ic->parmBytes > 3)
2976         {
2977           if (accuse)
2978             {
2979               emitcode ("push", "acc");
2980               accPushed = TRUE;
2981             }
2982           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2983               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2984               !assignResultGenerated)
2985             {
2986               emitcode ("mov", "F0,c");
2987               resultInF0 = TRUE;
2988             }
2989
2990           emitcode ("mov", "a,%s", spname);
2991           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2992           emitcode ("mov", "%s,a", spname);
2993
2994           /* unsaveRegisters from xstack needs acc, but */
2995           /* unsaveRegisters from stack needs this popped */
2996           if (accPushed && !options.useXstack)
2997             {
2998               emitcode ("pop", "acc");
2999               accPushed = FALSE;
3000             }
3001         }
3002       else
3003         for (i = 0; i < ic->parmBytes; i++)
3004           emitcode ("dec", "%s", spname);
3005     }
3006
3007   /* if we had saved some registers then unsave them */
3008   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3009     {
3010       if (accuse && !accPushed && options.useXstack)
3011         {
3012           /* xstack needs acc, but doesn't touch normal stack */
3013           emitcode ("push", "acc");
3014           accPushed = TRUE;
3015         }
3016       unsaveRegisters (ic);
3017     }
3018
3019 //  /* if register bank was saved then pop them */
3020 //  if (restoreBank)
3021 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3022
3023   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3024     {
3025       if (resultInF0)
3026           emitcode ("mov", "c,F0");
3027
3028       aopOp (IC_RESULT (ic), ic, FALSE);
3029       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3030       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3031     }
3032
3033   if (accPushed)
3034     emitcode ("pop", "acc");
3035 }
3036
3037 /*-----------------------------------------------------------------*/
3038 /* genPcall - generates a call by pointer statement                */
3039 /*-----------------------------------------------------------------*/
3040 static void
3041 genPcall (iCode * ic)
3042 {
3043   sym_link *dtype;
3044   sym_link *etype;
3045   symbol *rlbl = newiTempLabel (NULL);
3046 //  bool restoreBank=FALSE;
3047   bool swapBanks = FALSE;
3048   bool resultInF0 = FALSE;
3049
3050   D (emitcode (";", "genPcall"));
3051
3052   dtype = operandType (IC_LEFT (ic))->next;
3053   etype = getSpec(dtype);
3054   /* if caller saves & we have not saved then */
3055   if (!ic->regsSaved)
3056     saveRegisters (ic);
3057
3058   /* if we are calling a not _naked function that is not using
3059      the same register bank then we need to save the
3060      destination registers on the stack */
3061   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
3062       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3063       !IFFUNC_ISISR (dtype))
3064     {
3065 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3066 //    restoreBank=TRUE;
3067       swapBanks = TRUE;
3068       // need caution message to user here
3069     }
3070
3071   if (IS_LITERAL (etype))
3072     {
3073       /* if send set is not empty then assign */
3074       if (_G.sendSet)
3075         {
3076           genSend(reverseSet(_G.sendSet));
3077           _G.sendSet = NULL;
3078         }
3079
3080       if (swapBanks)
3081         {
3082           emitcode ("mov", "psw,#0x%02x",
3083            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3084         }
3085
3086       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3087         {
3088           if (IFFUNC_CALLEESAVES(dtype))
3089             {
3090               werror (E_BANKED_WITH_CALLEESAVES);
3091             }
3092           else
3093             {
3094               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3095
3096               emitcode ("mov", "r0,#%s", l);
3097               emitcode ("mov", "r1,#(%s >> 8)", l);
3098               emitcode ("mov", "r2,#(%s >> 16)", l);
3099               emitcode ("lcall", "__sdcc_banked_call");
3100             }
3101         }
3102       else
3103         {
3104           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3105         }
3106     }
3107   else
3108     {
3109       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3110         {
3111           if (IFFUNC_CALLEESAVES(dtype))
3112             {
3113               werror (E_BANKED_WITH_CALLEESAVES);
3114             }
3115           else
3116             {
3117               aopOp (IC_LEFT (ic), ic, FALSE);
3118
3119               if (!swapBanks)
3120                 {
3121                   /* what if aopGet needs r0 or r1 ??? */
3122                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3123                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3124                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3125                 }
3126               else
3127                 {
3128                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3129                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3130                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3131                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3132                 }
3133
3134               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3135
3136               /* if send set is not empty then assign */
3137               if (_G.sendSet)
3138                 {
3139                   genSend(reverseSet(_G.sendSet));
3140                   _G.sendSet = NULL;
3141                 }
3142
3143               if (swapBanks)
3144                 {
3145                   emitcode ("mov", "psw,#0x%02x",
3146                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3147                 }
3148
3149               /* make the call */
3150               emitcode ("lcall", "__sdcc_banked_call");
3151             }
3152         }
3153       else if (_G.sendSet)
3154         {
3155           /* push the return address on to the stack */
3156           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3157           emitcode ("push", "acc");
3158           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3159           emitcode ("push", "acc");
3160
3161           /* now push the calling address */
3162           aopOp (IC_LEFT (ic), ic, FALSE);
3163
3164           pushSide (IC_LEFT (ic), FPTRSIZE);
3165
3166           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3167
3168           /* if send set is not empty the assign */
3169           if (_G.sendSet)
3170             {
3171               genSend(reverseSet(_G.sendSet));
3172               _G.sendSet = NULL;
3173             }
3174
3175           if (swapBanks)
3176             {
3177               emitcode ("mov", "psw,#0x%02x",
3178                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3179             }
3180
3181           /* make the call */
3182           emitcode ("ret", "");
3183           emitLabel (rlbl);
3184         }
3185       else /* the send set is empty */
3186         {
3187           char *l;
3188           /* now get the calling address into dptr */
3189           aopOp (IC_LEFT (ic), ic, FALSE);
3190
3191           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3192           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3193             {
3194               emitcode ("mov", "r0,%s", l);
3195               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3196               emitcode ("mov", "dph,%s", l);
3197               emitcode ("mov", "dpl,r0");
3198             }
3199           else
3200             {
3201               emitcode ("mov", "dpl,%s", l);
3202               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3203               emitcode ("mov", "dph,%s", l);
3204             }
3205
3206           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3207
3208           if (swapBanks)
3209             {
3210               emitcode ("mov", "psw,#0x%02x",
3211                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3212             }
3213
3214           /* make the call */
3215           emitcode ("lcall", "__sdcc_call_dptr");
3216         }
3217     }
3218   if (swapBanks)
3219     {
3220       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3221     }
3222
3223   /* if we need assign a result value */
3224   if ((IS_ITEMP (IC_RESULT (ic)) &&
3225        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3226        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3227         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3228       IS_TRUE_SYMOP (IC_RESULT (ic)))
3229     {
3230
3231       _G.accInUse++;
3232       aopOp (IC_RESULT (ic), ic, FALSE);
3233       _G.accInUse--;
3234
3235       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3236
3237       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3238     }
3239
3240   /* adjust the stack for parameters if required */
3241   if (ic->parmBytes)
3242     {
3243       int i;
3244       if (ic->parmBytes > 3)
3245         {
3246           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3247               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3248             {
3249               emitcode ("mov", "F0,c");
3250               resultInF0 = TRUE;
3251             }
3252
3253           emitcode ("mov", "a,%s", spname);
3254           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3255           emitcode ("mov", "%s,a", spname);
3256         }
3257       else
3258         for (i = 0; i < ic->parmBytes; i++)
3259           emitcode ("dec", "%s", spname);
3260     }
3261
3262 //  /* if register bank was saved then unsave them */
3263 //  if (restoreBank)
3264 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3265
3266   /* if we had saved some registers then unsave them */
3267   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3268     unsaveRegisters (ic);
3269
3270   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3271     {
3272       if (resultInF0)
3273           emitcode ("mov", "c,F0");
3274
3275       aopOp (IC_RESULT (ic), ic, FALSE);
3276       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3277       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3278     }
3279 }
3280
3281 /*-----------------------------------------------------------------*/
3282 /* resultRemat - result  is rematerializable                       */
3283 /*-----------------------------------------------------------------*/
3284 static int
3285 resultRemat (iCode * ic)
3286 {
3287   if (SKIP_IC (ic) || ic->op == IFX)
3288     return 0;
3289
3290   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3291     {
3292       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3293       if (sym->remat && !POINTER_SET (ic))
3294         return 1;
3295     }
3296
3297   return 0;
3298 }
3299
3300 /*-----------------------------------------------------------------*/
3301 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3302 /*-----------------------------------------------------------------*/
3303 static int
3304 regsCmp(void *p1, void *p2)
3305 {
3306   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3307 }
3308
3309 static bool
3310 inExcludeList (char *s)
3311 {
3312   const char *p = setFirstItem(options.excludeRegsSet);
3313
3314   if (p == NULL || STRCASECMP(p, "none") == 0)
3315     return FALSE;
3316
3317
3318   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3319 }
3320
3321 /*-----------------------------------------------------------------*/
3322 /* genFunction - generated code for function entry                 */
3323 /*-----------------------------------------------------------------*/
3324 static void
3325 genFunction (iCode * ic)
3326 {
3327   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3328   sym_link *ftype;
3329   bool     switchedPSW = FALSE;
3330   int      calleesaves_saved_register = -1;
3331   int      stackAdjust = sym->stack;
3332   int      accIsFree = sym->recvSize < 4;
3333   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3334   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3335
3336   _G.nRegsSaved = 0;
3337   /* create the function header */
3338   emitcode (";", "-----------------------------------------");
3339   emitcode (";", " function %s", sym->name);
3340   emitcode (";", "-----------------------------------------");
3341
3342   emitcode ("", "%s:", sym->rname);
3343   lineCurr->isLabel = 1;
3344   ftype = operandType (IC_LEFT (ic));
3345   _G.currentFunc = sym;
3346
3347   if (IFFUNC_ISNAKED(ftype))
3348   {
3349       emitcode(";", "naked function: no prologue.");
3350       return;
3351   }
3352
3353   /* here we need to generate the equates for the
3354      register bank if required */
3355   if (FUNC_REGBANK (ftype) != rbank)
3356     {
3357       int i;
3358
3359       rbank = FUNC_REGBANK (ftype);
3360       for (i = 0; i < mcs51_nRegs; i++)
3361         {
3362           if (regs8051[i].type != REG_BIT)
3363             {
3364               if (strcmp (regs8051[i].base, "0") == 0)
3365                 emitcode ("", "%s = 0x%02x",
3366                           regs8051[i].dname,
3367                           8 * rbank + regs8051[i].offset);
3368               else
3369                 emitcode ("", "%s = %s + 0x%02x",
3370                           regs8051[i].dname,
3371                           regs8051[i].base,
3372                           8 * rbank + regs8051[i].offset);
3373             }
3374         }
3375     }
3376
3377   /* if this is an interrupt service routine then
3378      save acc, b, dpl, dph  */
3379   if (IFFUNC_ISISR (sym->type))
3380     {
3381       if (!inExcludeList ("acc"))
3382         emitcode ("push", "acc");
3383       if (!inExcludeList ("b"))
3384         emitcode ("push", "b");
3385       if (!inExcludeList ("dpl"))
3386         emitcode ("push", "dpl");
3387       if (!inExcludeList ("dph"))
3388         emitcode ("push", "dph");
3389       /* if this isr has no bank i.e. is going to
3390          run with bank 0 , then we need to save more
3391          registers :-) */
3392       if (!FUNC_REGBANK (sym->type))
3393         {
3394           int i;
3395
3396           /* if this function does not call any other
3397              function then we can be economical and
3398              save only those registers that are used */
3399           if (!IFFUNC_HASFCALL(sym->type))
3400             {
3401               /* if any registers used */
3402               if (sym->regsUsed)
3403                 {
3404                   bool bits_pushed = FALSE;
3405                   /* save the registers used */
3406                   for (i = 0; i < sym->regsUsed->size; i++)
3407                     {
3408                       if (bitVectBitValue (sym->regsUsed, i))
3409                         bits_pushed = pushReg (i, bits_pushed);
3410                     }
3411                 }
3412             }
3413           else
3414             {
3415               /* this function has a function call. We cannot
3416                  determine register usage so we will have to push the
3417                  entire bank */
3418                 saveRBank (0, ic, FALSE);
3419                 if (options.parms_in_bank1) {
3420                     for (i=0; i < 8 ; i++ ) {
3421                         emitcode ("push","%s",rb1regs[i]);
3422                     }
3423                 }
3424             }
3425         }
3426         else
3427         {
3428             /* This ISR uses a non-zero bank.
3429              *
3430              * We assume that the bank is available for our
3431              * exclusive use.
3432              *
3433              * However, if this ISR calls a function which uses some
3434              * other bank, we must save that bank entirely.
3435              */
3436             unsigned long banksToSave = 0;
3437
3438             if (IFFUNC_HASFCALL(sym->type))
3439             {
3440
3441 #define MAX_REGISTER_BANKS 4
3442
3443                 iCode *i;
3444                 int ix;
3445
3446                 for (i = ic; i; i = i->next)
3447                 {
3448                     if (i->op == ENDFUNCTION)
3449                     {
3450                         /* we got to the end OK. */
3451                         break;
3452                     }
3453
3454                     if (i->op == CALL)
3455                     {
3456                         sym_link *dtype;
3457
3458                         dtype = operandType (IC_LEFT(i));
3459                         if (dtype
3460                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3461                         {
3462                              /* Mark this bank for saving. */
3463                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3464                              {
3465                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3466                              }
3467                              else
3468                              {
3469                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3470                              }
3471
3472                              /* And note that we don't need to do it in
3473                               * genCall.
3474                               */
3475                              i->bankSaved = 1;
3476                         }
3477                     }
3478                     if (i->op == PCALL)
3479                     {
3480                         /* This is a mess; we have no idea what
3481                          * register bank the called function might
3482                          * use.
3483                          *
3484                          * The only thing I can think of to do is
3485                          * throw a warning and hope.
3486                          */
3487                         werror(W_FUNCPTR_IN_USING_ISR);
3488                     }
3489                 }
3490
3491                 if (banksToSave && options.useXstack)
3492                 {
3493                     /* Since we aren't passing it an ic,
3494                      * saveRBank will assume r0 is available to abuse.
3495                      *
3496                      * So switch to our (trashable) bank now, so
3497                      * the caller's R0 isn't trashed.
3498                      */
3499                     emitcode ("push", "psw");
3500                     emitcode ("mov", "psw,#0x%02x",
3501                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3502                     switchedPSW = TRUE;
3503                 }
3504
3505                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3506                 {
3507                      if (banksToSave & (1 << ix))
3508                      {
3509                          saveRBank(ix, NULL, FALSE);
3510                      }
3511                 }
3512             }
3513             // TODO: this needs a closer look
3514             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3515         }
3516
3517       /* Set the register bank to the desired value if nothing else */
3518       /* has done so yet. */
3519       if (!switchedPSW)
3520         {
3521           emitcode ("push", "psw");
3522           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3523         }
3524     }
3525   else
3526     {
3527       /* This is a non-ISR function. The caller has already switched register */
3528       /* banks, if necessary, so just handle the callee-saves option. */
3529
3530       /* if callee-save to be used for this function
3531          then save the registers being used in this function */
3532       if (IFFUNC_CALLEESAVES(sym->type))
3533         {
3534           int i;
3535
3536           /* if any registers used */
3537           if (sym->regsUsed)
3538             {
3539               bool bits_pushed = FALSE;
3540               /* save the registers used */
3541               for (i = 0; i < sym->regsUsed->size; i++)
3542                 {
3543                   if (bitVectBitValue (sym->regsUsed, i))
3544                     {
3545                       /* remember one saved register for later usage */
3546                       if (calleesaves_saved_register < 0)
3547                         calleesaves_saved_register = i;
3548                       bits_pushed = pushReg (i, bits_pushed);
3549                       _G.nRegsSaved++;
3550                     }
3551                 }
3552             }
3553         }
3554     }
3555
3556   if (fReentrant)
3557     {
3558       if (options.useXstack)
3559         {
3560           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3561             {
3562               emitcode ("mov", "r0,%s", spname);
3563               emitcode ("inc", "%s", spname);
3564               emitcode ("xch", "a,_bpx");
3565               emitcode ("movx", "@r0,a");
3566               emitcode ("inc", "r0");
3567               emitcode ("mov", "a,r0");
3568               emitcode ("xch", "a,_bpx");
3569             }
3570           if (sym->stack)
3571             {
3572               emitcode ("push", "_bp");     /* save the callers stack  */
3573               emitcode ("mov", "_bp,sp");
3574             }
3575         }
3576       else
3577         {
3578           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3579             {
3580               /* set up the stack */
3581               emitcode ("push", "_bp");     /* save the callers stack  */
3582               emitcode ("mov", "_bp,sp");
3583             }
3584         }
3585     }
3586
3587   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3588   /* before setting up the stack frame completely. */
3589   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3590     {
3591       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3592
3593       if (rsym->isitmp)
3594         {
3595           if (rsym && rsym->regType == REG_CND)
3596             rsym = NULL;
3597           if (rsym && (rsym->accuse || rsym->ruonly))
3598             rsym = NULL;
3599           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3600             rsym = rsym->usl.spillLoc;
3601         }
3602
3603       /* If the RECEIVE operand immediately spills to the first entry on the */
3604       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3605       /* rather than the usual @r0/r1 machinations. */
3606       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3607         {
3608           int ofs;
3609
3610           _G.current_iCode = ric;
3611           D(emitcode (";     genReceive",""));
3612           for (ofs=0; ofs < sym->recvSize; ofs++)
3613             {
3614               if (!strcmp (fReturn[ofs], "a"))
3615                 emitcode ("push", "acc");
3616               else
3617                 emitcode ("push", fReturn[ofs]);
3618             }
3619           stackAdjust -= sym->recvSize;
3620           if (stackAdjust<0)
3621             {
3622               assert (stackAdjust>=0);
3623               stackAdjust = 0;
3624             }
3625           _G.current_iCode = ic;
3626           ric->generated = 1;
3627           accIsFree = 1;
3628         }
3629       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3630       /* to free up the accumulator. */
3631       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3632         {
3633           int ofs;
3634
3635           _G.current_iCode = ric;
3636           D(emitcode (";     genReceive",""));
3637           for (ofs=0; ofs < sym->recvSize; ofs++)
3638             {
3639               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3640             }
3641           _G.current_iCode = ic;
3642           ric->generated = 1;
3643           accIsFree = 1;
3644         }
3645     }
3646
3647   /* adjust the stack for the function */
3648   if (stackAdjust)
3649     {
3650       int i = stackAdjust;
3651       if (i > 256)
3652         werror (W_STACK_OVERFLOW, sym->name);
3653
3654       if (i > 3 && accIsFree)
3655         {
3656           emitcode ("mov", "a,sp");
3657           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3658           emitcode ("mov", "sp,a");
3659         }
3660       else if (i > 5)
3661         {
3662           /* The accumulator is not free, so we will need another register */
3663           /* to clobber. No need to worry about a possible conflict with */
3664           /* the above early RECEIVE optimizations since they would have */
3665           /* freed the accumulator if they were generated. */
3666
3667           if (IFFUNC_CALLEESAVES(sym->type))
3668             {
3669               /* if it's a callee-saves function we need a saved register */
3670               if (calleesaves_saved_register >= 0)
3671                 {
3672                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3673                   emitcode ("mov", "a,sp");
3674                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3675                   emitcode ("mov", "sp,a");
3676                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3677                 }
3678               else
3679                 /* do it the hard way */
3680                 while (i--)
3681                   emitcode ("inc", "sp");
3682             }
3683           else
3684             {
3685               /* not callee-saves, we can clobber r0 */
3686               emitcode ("mov", "r0,a");
3687               emitcode ("mov", "a,sp");
3688               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3689               emitcode ("mov", "sp,a");
3690               emitcode ("mov", "a,r0");
3691             }
3692         }
3693       else
3694         while (i--)
3695           emitcode ("inc", "sp");
3696     }
3697
3698   if (sym->xstack)
3699     {
3700       char i = ((char) sym->xstack & 0xff);
3701
3702       if (i > 3 && accIsFree)
3703         {
3704           emitcode ("mov", "a,_spx");
3705           emitcode ("add", "a,#0x%02x", i & 0xff);
3706           emitcode ("mov", "_spx,a");
3707         }
3708       else if (i > 5)
3709         {
3710           emitcode ("push", "acc");
3711           emitcode ("mov", "a,_spx");
3712           emitcode ("add", "a,#0x%02x", i & 0xff);
3713           emitcode ("mov", "_spx,a");
3714           emitcode ("pop", "acc");
3715         }
3716       else
3717         {
3718           while (i--)
3719             emitcode ("inc", "_spx");
3720         }
3721     }
3722
3723   /* if critical function then turn interrupts off */
3724   if (IFFUNC_ISCRITICAL (ftype))
3725     {
3726       symbol *tlbl = newiTempLabel (NULL);
3727       emitcode ("setb", "c");
3728       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3729       emitcode ("clr", "c");
3730       emitLabel (tlbl);
3731       emitcode ("push", "psw"); /* save old ea via c in psw */
3732     }
3733 }
3734
3735 /*-----------------------------------------------------------------*/
3736 /* genEndFunction - generates epilogue for functions               */
3737 /*-----------------------------------------------------------------*/
3738 static void
3739 genEndFunction (iCode * ic)
3740 {
3741   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3742   lineNode *lnp = lineCurr;
3743   bitVect  *regsUsed;
3744   bitVect  *regsUsedPrologue;
3745   bitVect  *regsUnneeded;
3746   int      idx;
3747
3748   _G.currentFunc = NULL;
3749   if (IFFUNC_ISNAKED(sym->type))
3750   {
3751       emitcode(";", "naked function: no epilogue.");
3752       if (options.debug && currFunc)
3753         debugFile->writeEndFunction (currFunc, ic, 0);
3754       return;
3755   }
3756
3757   if (IFFUNC_ISCRITICAL (sym->type))
3758     {
3759       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3760         {
3761           emitcode ("rlc", "a");   /* save c in a */
3762           emitcode ("pop", "psw"); /* restore ea via c in psw */
3763           emitcode ("mov", "ea,c");
3764           emitcode ("rrc", "a");   /* restore c from a */
3765         }
3766       else
3767         {
3768           emitcode ("pop", "psw"); /* restore ea via c in psw */
3769           emitcode ("mov", "ea,c");
3770         }
3771     }
3772
3773   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3774     {
3775       if (options.useXstack)
3776         {
3777           if (sym->stack)
3778             {
3779               emitcode ("mov", "sp,_bp");
3780               emitcode ("pop", "_bp");
3781             }
3782           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3783             {
3784               emitcode ("xch", "a,_bpx");
3785               emitcode ("mov", "r0,a");
3786               emitcode ("dec", "r0");
3787               emitcode ("movx", "a,@r0");
3788               emitcode ("xch", "a,_bpx");
3789               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3790             }
3791         }
3792       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3793         {
3794           if (sym->stack)
3795             emitcode ("mov", "sp,_bp");
3796           emitcode ("pop", "_bp");
3797         }
3798     }
3799
3800   /* restore the register bank  */
3801   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3802   {
3803     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3804      || !options.useXstack)
3805     {
3806         /* Special case of ISR using non-zero bank with useXstack
3807          * is handled below.
3808          */
3809         emitcode ("pop", "psw");
3810     }
3811   }
3812
3813   if (IFFUNC_ISISR (sym->type))
3814     {
3815
3816       /* now we need to restore the registers */
3817       /* if this isr has no bank i.e. is going to
3818          run with bank 0 , then we need to save more
3819          registers :-) */
3820       if (!FUNC_REGBANK (sym->type))
3821         {
3822           int i;
3823           /* if this function does not call any other
3824              function then we can be economical and
3825              save only those registers that are used */
3826           if (!IFFUNC_HASFCALL(sym->type))
3827             {
3828               /* if any registers used */
3829               if (sym->regsUsed)
3830                 {
3831                   bool bits_popped = FALSE;
3832                   /* save the registers used */
3833                   for (i = sym->regsUsed->size; i >= 0; i--)
3834                     {
3835                       if (bitVectBitValue (sym->regsUsed, i))
3836                         bits_popped = popReg (i, bits_popped);
3837                     }
3838                 }
3839             }
3840           else
3841             {
3842               if (options.parms_in_bank1) {
3843                   for (i = 7 ; i >= 0 ; i-- ) {
3844                       emitcode ("pop","%s",rb1regs[i]);
3845                   }
3846               }
3847               /* this function has  a function call cannot
3848                  determines register usage so we will have to pop the
3849                  entire bank */
3850               unsaveRBank (0, ic, FALSE);
3851             }
3852         }
3853         else
3854         {
3855             /* This ISR uses a non-zero bank.
3856              *
3857              * Restore any register banks saved by genFunction
3858              * in reverse order.
3859              */
3860             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3861             int ix;
3862
3863             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3864             {
3865                 if (savedBanks & (1 << ix))
3866                 {
3867                     unsaveRBank(ix, NULL, FALSE);
3868                 }
3869             }
3870
3871             if (options.useXstack)
3872             {
3873                 /* Restore bank AFTER calling unsaveRBank,
3874                  * since it can trash r0.
3875                  */
3876                 emitcode ("pop", "psw");
3877             }
3878         }
3879
3880       if (!inExcludeList ("dph"))
3881         emitcode ("pop", "dph");
3882       if (!inExcludeList ("dpl"))
3883         emitcode ("pop", "dpl");
3884       if (!inExcludeList ("b"))
3885         emitcode ("pop", "b");
3886       if (!inExcludeList ("acc"))
3887         emitcode ("pop", "acc");
3888
3889       /* if debug then send end of function */
3890       if (options.debug && currFunc)
3891         {
3892           debugFile->writeEndFunction (currFunc, ic, 1);
3893         }
3894
3895       emitcode ("reti", "");
3896     }
3897   else
3898     {
3899       if (IFFUNC_CALLEESAVES(sym->type))
3900         {
3901           int i;
3902
3903           /* if any registers used */
3904           if (sym->regsUsed)
3905             {
3906               /* save the registers used */
3907               for (i = sym->regsUsed->size; i >= 0; i--)
3908                 {
3909                   if (bitVectBitValue (sym->regsUsed, i) ||
3910                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3911                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3912                 }
3913             }
3914           else if (mcs51_ptrRegReq)
3915             {
3916               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3917               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3918             }
3919
3920         }
3921
3922       /* if debug then send end of function */
3923       if (options.debug && currFunc)
3924         {
3925           debugFile->writeEndFunction (currFunc, ic, 1);
3926         }
3927
3928       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3929         {
3930           emitcode ("ljmp", "__sdcc_banked_ret");
3931         }
3932       else
3933         {
3934           emitcode ("ret", "");
3935         }
3936     }
3937
3938   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3939     return;
3940
3941   /* If this was an interrupt handler using bank 0 that called another */
3942   /* function, then all registers must be saved; nothing to optimized. */
3943   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3944       && !FUNC_REGBANK(sym->type))
3945     return;
3946
3947   /* There are no push/pops to optimize if not callee-saves or ISR */
3948   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3949     return;
3950
3951   /* If there were stack parameters, we cannot optimize without also    */
3952   /* fixing all of the stack offsets; this is too dificult to consider. */
3953   if (FUNC_HASSTACKPARM(sym->type))
3954     return;
3955
3956   /* Compute the registers actually used */
3957   regsUsed = newBitVect (mcs51_nRegs);
3958   regsUsedPrologue = newBitVect (mcs51_nRegs);
3959   while (lnp)
3960     {
3961       if (lnp->ic && lnp->ic->op == FUNCTION)
3962         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3963       else
3964         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3965
3966       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3967           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3968         break;
3969       if (!lnp->prev)
3970         break;
3971       lnp = lnp->prev;
3972     }
3973
3974   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3975       && !bitVectBitValue (regsUsed, CND_IDX))
3976     {
3977       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3978       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3979           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3980         bitVectUnSetBit (regsUsed, CND_IDX);
3981     }
3982   else
3983     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3984
3985   /* If this was an interrupt handler that called another function */
3986   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3987   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3988     {
3989       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3990       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3994     }
3995
3996   /* Remove the unneeded push/pops */
3997   regsUnneeded = newBitVect (mcs51_nRegs);
3998   while (lnp)
3999     {
4000       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4001         {
4002           if (!strncmp(lnp->line, "push", 4))
4003             {
4004               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4005               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4006                 {
4007                   connectLine (lnp->prev, lnp->next);
4008                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4009                 }
4010             }
4011           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4012             {
4013               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4014               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4015                 {
4016                   connectLine (lnp->prev, lnp->next);
4017                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4018                 }
4019             }
4020         }
4021       lnp = lnp->next;
4022     }
4023
4024   for (idx = 0; idx < regsUnneeded->size; idx++)
4025     if (bitVectBitValue (regsUnneeded, idx))
4026       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4027
4028   freeBitVect (regsUnneeded);
4029   freeBitVect (regsUsed);
4030   freeBitVect (regsUsedPrologue);
4031 }
4032
4033 /*-----------------------------------------------------------------*/
4034 /* genRet - generate code for return statement                     */
4035 /*-----------------------------------------------------------------*/
4036 static void
4037 genRet (iCode * ic)
4038 {
4039   int size, offset = 0, pushed = 0;
4040
4041   D (emitcode (";", "genRet"));
4042
4043   /* if we have no return value then
4044      just generate the "ret" */
4045   if (!IC_LEFT (ic))
4046     goto jumpret;
4047
4048   /* we have something to return then
4049      move the return value into place */
4050   aopOp (IC_LEFT (ic), ic, FALSE);
4051   size = AOP_SIZE (IC_LEFT (ic));
4052
4053   if (IS_BIT(_G.currentFunc->etype))
4054     {
4055       toCarry (IC_LEFT (ic));
4056     }
4057   else
4058     {
4059       while (size--)
4060         {
4061           char *l;
4062           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4063             {
4064               /* #NOCHANGE */
4065               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4066               emitcode ("push", "%s", l);
4067               pushed++;
4068             }
4069           else
4070             {
4071               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4072               if (strcmp (fReturn[offset], l))
4073                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4074             }
4075         }
4076
4077       while (pushed)
4078         {
4079           pushed--;
4080           if (strcmp (fReturn[pushed], "a"))
4081             emitcode ("pop", fReturn[pushed]);
4082           else
4083             emitcode ("pop", "acc");
4084         }
4085     }
4086   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4087
4088 jumpret:
4089   /* generate a jump to the return label
4090      if the next is not the return statement */
4091   if (!(ic->next && ic->next->op == LABEL &&
4092         IC_LABEL (ic->next) == returnLabel))
4093
4094     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4095
4096 }
4097
4098 /*-----------------------------------------------------------------*/
4099 /* genLabel - generates a label                                    */
4100 /*-----------------------------------------------------------------*/
4101 static void
4102 genLabel (iCode * ic)
4103 {
4104   /* special case never generate */
4105   if (IC_LABEL (ic) == entryLabel)
4106     return;
4107
4108   emitLabel (IC_LABEL (ic));
4109 }
4110
4111 /*-----------------------------------------------------------------*/
4112 /* genGoto - generates a ljmp                                      */
4113 /*-----------------------------------------------------------------*/
4114 static void
4115 genGoto (iCode * ic)
4116 {
4117   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4118 }
4119
4120 /*-----------------------------------------------------------------*/
4121 /* findLabelBackwards: walks back through the iCode chain looking  */
4122 /* for the given label. Returns number of iCode instructions     */
4123 /* between that label and given ic.          */
4124 /* Returns zero if label not found.          */
4125 /*-----------------------------------------------------------------*/
4126 static int
4127 findLabelBackwards (iCode * ic, int key)
4128 {
4129   int count = 0;
4130
4131   while (ic->prev)
4132     {
4133       ic = ic->prev;
4134       count++;
4135
4136       /* If we have any pushes or pops, we cannot predict the distance.
4137          I don't like this at all, this should be dealt with in the
4138          back-end */
4139       if (ic->op == IPUSH || ic->op == IPOP) {
4140         return 0;
4141       }
4142
4143       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4144         {
4145           return count;
4146         }
4147     }
4148
4149   return 0;
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genPlusIncr :- does addition with increment if possible         */
4154 /*-----------------------------------------------------------------*/
4155 static bool
4156 genPlusIncr (iCode * ic)
4157 {
4158   unsigned int icount;
4159   unsigned int size = getDataSize (IC_RESULT (ic));
4160
4161   /* will try to generate an increment */
4162   /* if the right side is not a literal
4163      we cannot */
4164   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4165     return FALSE;
4166
4167   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4168
4169   D(emitcode (";","genPlusIncr"));
4170
4171   /* if increment >=16 bits in register or direct space */
4172   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4173         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4174         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4175       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4176       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4177       (size > 1) &&
4178       (icount == 1))
4179     {
4180       symbol *tlbl;
4181       int emitTlbl;
4182       int labelRange;
4183
4184       /* If the next instruction is a goto and the goto target
4185        * is < 10 instructions previous to this, we can generate
4186        * jumps straight to that target.
4187        */
4188       if (ic->next && ic->next->op == GOTO
4189           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4190           && labelRange <= 10)
4191         {
4192           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4193           tlbl = IC_LABEL (ic->next);
4194           emitTlbl = 0;
4195         }
4196       else
4197         {
4198           tlbl = newiTempLabel (NULL);
4199           emitTlbl = 1;
4200         }
4201       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4202       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4203           IS_AOP_PREG (IC_RESULT (ic)))
4204         emitcode ("cjne", "%s,#0x00,%05d$",
4205                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4206                   tlbl->key + 100);
4207       else
4208         {
4209           emitcode ("clr", "a");
4210           emitcode ("cjne", "a,%s,%05d$",
4211                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4212                     tlbl->key + 100);
4213         }
4214
4215       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4216       if (size > 2)
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), MSB16, FALSE, FALSE),
4222                       tlbl->key + 100);
4223           else
4224             emitcode ("cjne", "a,%s,%05d$",
4225                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4226                       tlbl->key + 100);
4227
4228           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4229         }
4230       if (size > 3)
4231         {
4232           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4233               IS_AOP_PREG (IC_RESULT (ic)))
4234             emitcode ("cjne", "%s,#0x00,%05d$",
4235                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4236                       tlbl->key + 100);
4237           else
4238             {
4239               emitcode ("cjne", "a,%s,%05d$",
4240                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4241                         tlbl->key + 100);
4242             }
4243           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4244         }
4245
4246       if (emitTlbl)
4247         {
4248           emitLabel (tlbl);
4249         }
4250       return TRUE;
4251     }
4252
4253   /* if result is dptr */
4254   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4255       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4256       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4257       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4258     {
4259       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4260         return FALSE;
4261
4262       if (icount > 9)
4263         return FALSE;
4264
4265       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4266         return FALSE;
4267
4268       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4269       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4270       while (icount--)
4271         emitcode ("inc", "dptr");
4272
4273       return TRUE;
4274     }
4275
4276   /* if the literal value of the right hand side
4277      is greater than 4 then it is not worth it */
4278   if (icount > 4)
4279     return FALSE;
4280
4281   /* if the sizes are greater than 1 then we cannot */
4282   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4283       AOP_SIZE (IC_LEFT (ic)) > 1)
4284     return FALSE;
4285
4286   /* we can if the aops of the left & result match or
4287      if they are in registers and the registers are the
4288      same */
4289   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4290     {
4291       if (icount > 3)
4292         {
4293           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4294           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4295           aopPut (IC_RESULT (ic), "a", 0);
4296         }
4297       else
4298         {
4299           while (icount--)
4300             {
4301               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4302             }
4303         }
4304
4305       return TRUE;
4306     }
4307
4308   if (icount == 1)
4309     {
4310       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4311       emitcode ("inc", "a");
4312       aopPut (IC_RESULT (ic), "a", 0);
4313       return TRUE;
4314     }
4315
4316   return FALSE;
4317 }
4318
4319 /*-----------------------------------------------------------------*/
4320 /* outBitAcc - output a bit in acc                                 */
4321 /*-----------------------------------------------------------------*/
4322 static void
4323 outBitAcc (operand * result)
4324 {
4325   symbol *tlbl = newiTempLabel (NULL);
4326   /* if the result is a bit */
4327   if (AOP_TYPE (result) == AOP_CRY)
4328     {
4329       aopPut (result, "a", 0);
4330     }
4331   else
4332     {
4333       emitcode ("jz", "%05d$", tlbl->key + 100);
4334       emitcode ("mov", "a,%s", one);
4335       emitLabel (tlbl);
4336       outAcc (result);
4337     }
4338 }
4339
4340 /*-----------------------------------------------------------------*/
4341 /* genPlusBits - generates code for addition of two bits           */
4342 /*-----------------------------------------------------------------*/
4343 static void
4344 genPlusBits (iCode * ic)
4345 {
4346   D (emitcode (";", "genPlusBits"));
4347
4348   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4349   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4350     {
4351       symbol *lbl = newiTempLabel (NULL);
4352       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4353       emitcode ("cpl", "c");
4354       emitLabel (lbl);
4355       outBitC (IC_RESULT (ic));
4356     }
4357   else
4358     {
4359       emitcode ("clr", "a");
4360       emitcode ("rlc", "a");
4361       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4362       emitcode ("addc", "a,%s", zero);
4363       outAcc (IC_RESULT (ic));
4364     }
4365 }
4366
4367 #if 0
4368 /* This is the original version of this code.
4369
4370  * This is being kept around for reference,
4371  * because I am not entirely sure I got it right...
4372  */
4373 static void
4374 adjustArithmeticResult (iCode * ic)
4375 {
4376   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4377       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4378       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4379     aopPut (IC_RESULT (ic),
4380             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4381             2);
4382
4383   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4384       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4385       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4386     aopPut (IC_RESULT (ic),
4387             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4388             2);
4389
4390   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4391       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4392       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4393       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4394       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4395     {
4396       char buffer[5];
4397       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4398       aopPut (IC_RESULT (ic), buffer, 2);
4399     }
4400 }
4401 #else
4402 /* This is the pure and virtuous version of this code.
4403  * I'm pretty certain it's right, but not enough to toss the old
4404  * code just yet...
4405  */
4406 static void
4407 adjustArithmeticResult (iCode * ic)
4408 {
4409   if (opIsGptr (IC_RESULT (ic)) &&
4410       opIsGptr (IC_LEFT (ic)) &&
4411       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4412     {
4413       aopPut (IC_RESULT (ic),
4414               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4415               GPTRSIZE - 1);
4416     }
4417
4418   if (opIsGptr (IC_RESULT (ic)) &&
4419       opIsGptr (IC_RIGHT (ic)) &&
4420       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4421     {
4422       aopPut (IC_RESULT (ic),
4423               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4424               GPTRSIZE - 1);
4425     }
4426
4427   if (opIsGptr (IC_RESULT (ic)) &&
4428       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4429       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4430       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4431       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4432     {
4433       char buffer[5];
4434       SNPRINTF (buffer, sizeof(buffer),
4435                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4436       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4437     }
4438 }
4439 #endif
4440
4441 /*-----------------------------------------------------------------*/
4442 /* genPlus - generates code for addition                           */
4443 /*-----------------------------------------------------------------*/
4444 static void
4445 genPlus (iCode * ic)
4446 {
4447   int size, offset = 0;
4448   int skip_bytes = 0;
4449   char *add = "add";
4450   bool swappedLR = FALSE;
4451   operand *leftOp, *rightOp;
4452   operand * op;
4453
4454   D (emitcode (";", "genPlus"));
4455
4456   /* special cases :- */
4457
4458   aopOp (IC_LEFT (ic), ic, FALSE);
4459   aopOp (IC_RIGHT (ic), ic, FALSE);
4460   aopOp (IC_RESULT (ic), ic, TRUE);
4461
4462   /* if literal, literal on the right or
4463      if left requires ACC or right is already
4464      in ACC */
4465   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4466       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4467       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4468     {
4469       operand *t = IC_RIGHT (ic);
4470       IC_RIGHT (ic) = IC_LEFT (ic);
4471       IC_LEFT (ic) = t;
4472       swappedLR = TRUE;
4473     }
4474
4475   /* if both left & right are in bit
4476      space */
4477   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4478       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4479     {
4480       genPlusBits (ic);
4481       goto release;
4482     }
4483
4484   /* if left in bit space & right literal */
4485   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4486       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4487     {
4488       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4489       /* if result in bit space */
4490       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4491         {
4492           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4493             emitcode ("cpl", "c");
4494           outBitC (IC_RESULT (ic));
4495         }
4496       else
4497         {
4498           size = getDataSize (IC_RESULT (ic));
4499           while (size--)
4500             {
4501               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4502               emitcode ("addc", "a,%s", zero);
4503               aopPut (IC_RESULT (ic), "a", offset++);
4504             }
4505         }
4506       goto release;
4507     }
4508
4509   /* if I can do an increment instead
4510      of add then GOOD for ME */
4511   if (genPlusIncr (ic) == TRUE)
4512     goto release;
4513
4514   size = getDataSize (IC_RESULT (ic));
4515   leftOp = IC_LEFT(ic);
4516   rightOp = IC_RIGHT(ic);
4517   op = IC_LEFT(ic);
4518
4519   /* if this is an add for an array access
4520      at a 256 byte boundary */
4521   if ( 2 == size
4522        && AOP_TYPE (op) == AOP_IMMD
4523        && IS_SYMOP (op)
4524        && IS_SPEC (OP_SYM_ETYPE (op))
4525        && SPEC_ABSA (OP_SYM_ETYPE (op))
4526        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4527      )
4528     {
4529       D(emitcode (";     genPlus aligned array",""));
4530       aopPut (IC_RESULT (ic),
4531               aopGet (rightOp, 0, FALSE, FALSE),
4532               0);
4533
4534       if( 1 == getDataSize (IC_RIGHT (ic)) )
4535         {
4536           aopPut (IC_RESULT (ic),
4537                   aopGet (leftOp, 1, FALSE, FALSE),
4538                   1);
4539         }
4540       else
4541         {
4542           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4543           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4544           aopPut (IC_RESULT (ic), "a", 1);
4545         }
4546       goto release;
4547     }
4548
4549   /* if the lower bytes of a literal are zero skip the addition */
4550   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4551     {
4552        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4553               (skip_bytes+1 < size))
4554          {
4555            skip_bytes++;
4556          }
4557        if (skip_bytes)
4558          D(emitcode (";     genPlus shortcut",""));
4559     }
4560
4561   while (size--)
4562     {
4563       if( offset >= skip_bytes )
4564         {
4565           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4566             {
4567               bool pushedB;
4568               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4569               pushedB = pushB ();
4570               emitcode("xch", "a,b");
4571               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4572               emitcode (add, "a,b");
4573               popB (pushedB);
4574             }
4575           else if (aopGetUsesAcc (leftOp, offset))
4576             {
4577               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4578               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4579             }
4580           else
4581             {
4582               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4583               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4584             }
4585           aopPut (IC_RESULT (ic), "a", offset);
4586           add = "addc";  /* further adds must propagate carry */
4587         }
4588       else
4589         {
4590           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4591               isOperandVolatile (IC_RESULT (ic), FALSE))
4592             {
4593               /* just move */
4594               aopPut (IC_RESULT (ic),
4595                       aopGet (leftOp, offset, FALSE, FALSE),
4596                       offset);
4597             }
4598         }
4599       offset++;
4600     }
4601
4602   adjustArithmeticResult (ic);
4603
4604 release:
4605   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4606   if (!swappedLR)
4607     {
4608       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4609       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4610     }
4611   else
4612     {
4613       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4615     }
4616 }
4617
4618 /*-----------------------------------------------------------------*/
4619 /* genMinusDec :- does subtraction with decrement if possible      */
4620 /*-----------------------------------------------------------------*/
4621 static bool
4622 genMinusDec (iCode * ic)
4623 {
4624   unsigned int icount;
4625   unsigned int size = getDataSize (IC_RESULT (ic));
4626
4627   /* will try to generate an increment */
4628   /* if the right side is not a literal
4629      we cannot */
4630   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4631     return FALSE;
4632
4633   /* if the literal value of the right hand side
4634      is greater than 4 then it is not worth it */
4635   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4636     return FALSE;
4637
4638   D (emitcode (";", "genMinusDec"));
4639
4640   /* if decrement >=16 bits in register or direct space */
4641   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4642         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4643         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4644       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4645       (size > 1) &&
4646       (icount == 1))
4647     {
4648       symbol *tlbl;
4649       int emitTlbl;
4650       int labelRange;
4651
4652       /* If the next instruction is a goto and the goto target
4653        * is <= 10 instructions previous to this, we can generate
4654        * jumps straight to that target.
4655        */
4656       if (ic->next && ic->next->op == GOTO
4657           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4658           && labelRange <= 10)
4659         {
4660           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4661           tlbl = IC_LABEL (ic->next);
4662           emitTlbl = 0;
4663         }
4664       else
4665         {
4666           tlbl = newiTempLabel (NULL);
4667           emitTlbl = 1;
4668         }
4669
4670       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4671       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4672           IS_AOP_PREG (IC_RESULT (ic)))
4673         emitcode ("cjne", "%s,#0xff,%05d$"
4674                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4675                   ,tlbl->key + 100);
4676       else
4677         {
4678           emitcode ("mov", "a,#0xff");
4679           emitcode ("cjne", "a,%s,%05d$"
4680                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4681                     ,tlbl->key + 100);
4682         }
4683       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4684       if (size > 2)
4685         {
4686           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4687               IS_AOP_PREG (IC_RESULT (ic)))
4688             emitcode ("cjne", "%s,#0xff,%05d$"
4689                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4690                       ,tlbl->key + 100);
4691           else
4692             {
4693               emitcode ("cjne", "a,%s,%05d$"
4694                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4695                         ,tlbl->key + 100);
4696             }
4697           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4698         }
4699       if (size > 3)
4700         {
4701           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4702               IS_AOP_PREG (IC_RESULT (ic)))
4703             emitcode ("cjne", "%s,#0xff,%05d$"
4704                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4705                       ,tlbl->key + 100);
4706           else
4707             {
4708               emitcode ("cjne", "a,%s,%05d$"
4709                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4710                         ,tlbl->key + 100);
4711             }
4712           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4713         }
4714       if (emitTlbl)
4715         {
4716           emitLabel (tlbl);
4717         }
4718       return TRUE;
4719     }
4720
4721   /* if the sizes are greater than 1 then we cannot */
4722   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4723       AOP_SIZE (IC_LEFT (ic)) > 1)
4724     return FALSE;
4725
4726   /* we can if the aops of the left & result match or
4727      if they are in registers and the registers are the
4728      same */
4729   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4730     {
4731       char *l;
4732
4733       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4734         {
4735           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4736           l = "a";
4737         }
4738       else
4739         {
4740           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4741         }
4742
4743       while (icount--)
4744         {
4745           emitcode ("dec", "%s", l);
4746         }
4747
4748       if (AOP_NEEDSACC (IC_RESULT (ic)))
4749         aopPut (IC_RESULT (ic), "a", 0);
4750
4751       return TRUE;
4752     }
4753
4754   if (icount == 1)
4755     {
4756       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4757       emitcode ("dec", "a");
4758       aopPut (IC_RESULT (ic), "a", 0);
4759       return TRUE;
4760     }
4761
4762   return FALSE;
4763 }
4764
4765 /*-----------------------------------------------------------------*/
4766 /* addSign - complete with sign                                    */
4767 /*-----------------------------------------------------------------*/
4768 static void
4769 addSign (operand * result, int offset, int sign)
4770 {
4771   int size = (getDataSize (result) - offset);
4772   if (size > 0)
4773     {
4774       if (sign)
4775         {
4776           emitcode ("rlc", "a");
4777           emitcode ("subb", "a,acc");
4778           while (size--)
4779             {
4780               aopPut (result, "a", offset++);
4781             }
4782         }
4783       else
4784         {
4785           while (size--)
4786             {
4787               aopPut (result, zero, offset++);
4788             }
4789         }
4790     }
4791 }
4792
4793 /*-----------------------------------------------------------------*/
4794 /* genMinusBits - generates code for subtraction  of two bits      */
4795 /*-----------------------------------------------------------------*/
4796 static void
4797 genMinusBits (iCode * ic)
4798 {
4799   symbol *lbl = newiTempLabel (NULL);
4800
4801   D (emitcode (";", "genMinusBits"));
4802
4803   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4804     {
4805       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4806       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4807       emitcode ("cpl", "c");
4808       emitLabel (lbl);
4809       outBitC (IC_RESULT (ic));
4810     }
4811   else
4812     {
4813       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4814       emitcode ("subb", "a,acc");
4815       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4816       emitcode ("inc", "a");
4817       emitLabel (lbl);
4818       aopPut (IC_RESULT (ic), "a", 0);
4819       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4820     }
4821 }
4822
4823 /*-----------------------------------------------------------------*/
4824 /* genMinus - generates code for subtraction                       */
4825 /*-----------------------------------------------------------------*/
4826 static void
4827 genMinus (iCode * ic)
4828 {
4829   int size, offset = 0;
4830
4831   D (emitcode (";", "genMinus"));
4832
4833   aopOp (IC_LEFT (ic), ic, FALSE);
4834   aopOp (IC_RIGHT (ic), ic, FALSE);
4835   aopOp (IC_RESULT (ic), ic, TRUE);
4836
4837   /* special cases :- */
4838   /* if both left & right are in bit space */
4839   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4840       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4841     {
4842       genMinusBits (ic);
4843       goto release;
4844     }
4845
4846   /* if I can do an decrement instead
4847      of subtract then GOOD for ME */
4848   if (genMinusDec (ic) == TRUE)
4849     goto release;
4850
4851   size = getDataSize (IC_RESULT (ic));
4852
4853   /* if literal, add a,#-lit, else normal subb */
4854   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4855     {
4856       unsigned long lit = 0L;
4857       bool useCarry = FALSE;
4858
4859       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4860       lit = -(long) lit;
4861
4862       while (size--)
4863         {
4864           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4865             {
4866               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4867               if (!offset && !size && lit== (unsigned long) -1)
4868                 {
4869                   emitcode ("dec", "a");
4870                 }
4871               else if (!useCarry)
4872                 {
4873                   /* first add without previous c */
4874                   emitcode ("add", "a,#0x%02x",
4875                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4876                   useCarry = TRUE;
4877                 }
4878               else
4879                 {
4880                   emitcode ("addc", "a,#0x%02x",
4881                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4882                 }
4883               aopPut (IC_RESULT (ic), "a", offset++);
4884             }
4885           else
4886             {
4887               /* no need to add zeroes */
4888               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4889                 {
4890                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4891                           offset);
4892                 }
4893               offset++;
4894             }
4895         }
4896     }
4897   else
4898     {
4899       operand *leftOp, *rightOp;
4900
4901       leftOp = IC_LEFT(ic);
4902       rightOp = IC_RIGHT(ic);
4903
4904       while (size--)
4905         {
4906           if (aopGetUsesAcc(rightOp, offset)) {
4907             if (aopGetUsesAcc(leftOp, offset)) {
4908               bool pushedB;
4909
4910               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4911               pushedB = pushB ();
4912               emitcode ("mov", "b,a");
4913               if (offset == 0)
4914                 CLRC;
4915               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4916               emitcode ("subb", "a,b");
4917               popB (pushedB);
4918             } else {
4919               /* reverse subtraction with 2's complement */
4920               if (offset == 0)
4921                 emitcode( "setb", "c");
4922               else
4923                 emitcode( "cpl", "c");
4924               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4925               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4926               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4927               emitcode("cpl", "a");
4928               if (size) /* skip if last byte */
4929                 emitcode( "cpl", "c");
4930             }
4931           } else {
4932             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4933             if (offset == 0)
4934               CLRC;
4935             emitcode ("subb", "a,%s",
4936                       aopGet(rightOp, offset, FALSE, TRUE));
4937           }
4938
4939           aopPut (IC_RESULT (ic), "a", offset++);
4940         }
4941     }
4942
4943   adjustArithmeticResult (ic);
4944
4945 release:
4946   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4947   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4948   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4949 }
4950
4951
4952 /*-----------------------------------------------------------------*/
4953 /* genMultbits :- multiplication of bits                           */
4954 /*-----------------------------------------------------------------*/
4955 static void
4956 genMultbits (operand * left,
4957              operand * right,
4958              operand * result)
4959 {
4960   D (emitcode (";", "genMultbits"));
4961
4962   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4963   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4964   outBitC (result);
4965 }
4966
4967 /*-----------------------------------------------------------------*/
4968 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4969 /*-----------------------------------------------------------------*/
4970 static void
4971 genMultOneByte (operand * left,
4972                 operand * right,
4973                 operand * result)
4974 {
4975   symbol *lbl;
4976   int size = AOP_SIZE (result);
4977   bool runtimeSign, compiletimeSign;
4978   bool lUnsigned, rUnsigned, pushedB;
4979
4980   D (emitcode (";", "genMultOneByte"));
4981
4982   if (size < 1 || size > 2)
4983     {
4984       /* this should never happen */
4985       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4986                AOP_SIZE(result), __FILE__, lineno);
4987       exit (1);
4988     }
4989
4990   /* (if two literals: the value is computed before) */
4991   /* if one literal, literal on the right */
4992   if (AOP_TYPE (left) == AOP_LIT)
4993     {
4994       operand *t = right;
4995       right = left;
4996       left = t;
4997       /* emitcode (";", "swapped left and right"); */
4998     }
4999   /* if no literal, unsigned on the right: shorter code */
5000   if (   AOP_TYPE (right) != AOP_LIT
5001       && SPEC_USIGN (getSpec (operandType (left))))
5002     {
5003       operand *t = right;
5004       right = left;
5005       left = t;
5006     }
5007
5008   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5009   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5010
5011   pushedB = pushB ();
5012
5013   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5014                    no need to take care about the signedness! */
5015       || (lUnsigned && rUnsigned))
5016     {
5017       /* just an unsigned 8 * 8 = 8 multiply
5018          or 8u * 8u = 16u */
5019       /* emitcode (";","unsigned"); */
5020       /* TODO: check for accumulator clash between left & right aops? */
5021
5022       if (AOP_TYPE (right) == AOP_LIT)
5023         {
5024           /* moving to accumulator first helps peepholes */
5025           MOVA (aopGet (left, 0, FALSE, FALSE));
5026           MOVB (aopGet (right, 0, FALSE, FALSE));
5027         }
5028       else
5029         {
5030           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5031           MOVA (aopGet (left, 0, FALSE, FALSE));
5032         }
5033
5034       emitcode ("mul", "ab");
5035       aopPut (result, "a", 0);
5036       if (size == 2)
5037         aopPut (result, "b", 1);
5038
5039       popB (pushedB);
5040       return;
5041     }
5042
5043   /* we have to do a signed multiply */
5044   /* emitcode (";", "signed"); */
5045
5046   /* now sign adjust for both left & right */
5047
5048   /* let's see what's needed: */
5049   /* apply negative sign during runtime */
5050   runtimeSign = FALSE;
5051   /* negative sign from literals */
5052   compiletimeSign = FALSE;
5053
5054   if (!lUnsigned)
5055     {
5056       if (AOP_TYPE(left) == AOP_LIT)
5057         {
5058           /* signed literal */
5059           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5060           if (val < 0)
5061             compiletimeSign = TRUE;
5062         }
5063       else
5064         /* signed but not literal */
5065         runtimeSign = TRUE;
5066     }
5067
5068   if (!rUnsigned)
5069     {
5070       if (AOP_TYPE(right) == AOP_LIT)
5071         {
5072           /* signed literal */
5073           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5074           if (val < 0)
5075             compiletimeSign ^= TRUE;
5076         }
5077       else
5078         /* signed but not literal */
5079         runtimeSign = TRUE;
5080     }
5081
5082   /* initialize F0, which stores the runtime sign */
5083   if (runtimeSign)
5084     {
5085       if (compiletimeSign)
5086         emitcode ("setb", "F0"); /* set sign flag */
5087       else
5088         emitcode ("clr", "F0"); /* reset sign flag */
5089     }
5090
5091   /* save the signs of the operands */
5092   if (AOP_TYPE(right) == AOP_LIT)
5093     {
5094       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5095
5096       if (!rUnsigned && val < 0)
5097         emitcode ("mov", "b,#0x%02x", -val);
5098       else
5099         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5100     }
5101   else /* ! literal */
5102     {
5103       if (rUnsigned)  /* emitcode (";", "signed"); */
5104         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5105       else
5106         {
5107           MOVA (aopGet (right, 0, FALSE, FALSE));
5108           lbl = newiTempLabel (NULL);
5109           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5110           emitcode ("cpl", "F0"); /* complement sign flag */
5111           emitcode ("cpl", "a");  /* 2's complement */
5112           emitcode ("inc", "a");
5113           emitLabel (lbl);
5114           emitcode ("mov", "b,a");
5115         }
5116     }
5117
5118   if (AOP_TYPE(left) == AOP_LIT)
5119     {
5120       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5121
5122       if (!lUnsigned && val < 0)
5123         emitcode ("mov", "a,#0x%02x", -val);
5124       else
5125         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5126     }
5127   else /* ! literal */
5128     {
5129       MOVA (aopGet (left, 0, FALSE, FALSE));
5130
5131       if (!lUnsigned)
5132         {
5133           lbl = newiTempLabel (NULL);
5134           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5135           emitcode ("cpl", "F0"); /* complement sign flag */
5136           emitcode ("cpl", "a"); /* 2's complement */
5137           emitcode ("inc", "a");
5138           emitLabel (lbl);
5139         }
5140     }
5141
5142   /* now the multiplication */
5143   emitcode ("mul", "ab");
5144   if (runtimeSign || compiletimeSign)
5145     {
5146       lbl = newiTempLabel (NULL);
5147       if (runtimeSign)
5148         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5149       emitcode ("cpl", "a"); /* lsb 2's complement */
5150       if (size != 2)
5151         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5152       else
5153         {
5154           emitcode ("add", "a,#1"); /* this sets carry flag */
5155           emitcode ("xch", "a,b");
5156           emitcode ("cpl", "a"); /* msb 2's complement */
5157           emitcode ("addc", "a,#0");
5158           emitcode ("xch", "a,b");
5159         }
5160       emitLabel (lbl);
5161     }
5162   aopPut (result, "a", 0);
5163   if (size == 2)
5164     aopPut (result, "b", 1);
5165
5166   popB (pushedB);
5167 }
5168
5169 /*-----------------------------------------------------------------*/
5170 /* genMult - generates code for multiplication                     */
5171 /*-----------------------------------------------------------------*/
5172 static void
5173 genMult (iCode * ic)
5174 {
5175   operand *left = IC_LEFT (ic);
5176   operand *right = IC_RIGHT (ic);
5177   operand *result = IC_RESULT (ic);
5178
5179   D (emitcode (";", "genMult"));
5180
5181   /* assign the asmops */
5182   aopOp (left, ic, FALSE);
5183   aopOp (right, ic, FALSE);
5184   aopOp (result, ic, TRUE);
5185
5186   /* special cases first */
5187   /* both are bits */
5188   if (AOP_TYPE (left) == AOP_CRY &&
5189       AOP_TYPE (right) == AOP_CRY)
5190     {
5191       genMultbits (left, right, result);
5192       goto release;
5193     }
5194
5195   /* if both are of size == 1 */
5196 #if 0 // one of them can be a sloc shared with the result
5197     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5198 #else
5199   if (getSize(operandType(left)) == 1 &&
5200       getSize(operandType(right)) == 1)
5201 #endif
5202     {
5203       genMultOneByte (left, right, result);
5204       goto release;
5205     }
5206
5207   /* should have been converted to function call */
5208     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5209              getSize(OP_SYMBOL(right)->type));
5210   assert (0);
5211
5212 release:
5213   freeAsmop (result, NULL, ic, TRUE);
5214   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5215   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5216 }
5217
5218 /*-----------------------------------------------------------------*/
5219 /* genDivbits :- division of bits                                  */
5220 /*-----------------------------------------------------------------*/
5221 static void
5222 genDivbits (operand * left,
5223             operand * right,
5224             operand * result)
5225 {
5226   char *l;
5227   bool pushedB;
5228
5229   D(emitcode (";     genDivbits",""));
5230
5231   pushedB = pushB ();
5232
5233   /* the result must be bit */
5234   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5235   l = aopGet (left, 0, FALSE, FALSE);
5236
5237   MOVA (l);
5238
5239   emitcode ("div", "ab");
5240   emitcode ("rrc", "a");
5241
5242   popB (pushedB);
5243
5244   aopPut (result, "c", 0);
5245 }
5246
5247 /*-----------------------------------------------------------------*/
5248 /* genDivOneByte : 8 bit division                                  */
5249 /*-----------------------------------------------------------------*/
5250 static void
5251 genDivOneByte (operand * left,
5252                operand * right,
5253                operand * result)
5254 {
5255   bool lUnsigned, rUnsigned, pushedB;
5256   bool runtimeSign, compiletimeSign;
5257   bool accuse = FALSE;
5258   bool pushedA = FALSE;
5259   symbol *lbl;
5260   int size, offset;
5261
5262   D(emitcode (";     genDivOneByte",""));
5263
5264   /* Why is it necessary that genDivOneByte() can return an int result?
5265      Have a look at:
5266
5267         volatile unsigned char uc;
5268         volatile signed char sc1, sc2;
5269         volatile int i;
5270
5271         uc  = 255;
5272         sc1 = -1;
5273         i = uc / sc1;
5274
5275      Or:
5276
5277         sc1 = -128;
5278         sc2 = -1;
5279         i = sc1 / sc2;
5280
5281      In all cases a one byte result would overflow, the following cast to int
5282      would return the wrong result.
5283
5284      Two possible solution:
5285         a) cast operands to int, if ((unsigned) / (signed)) or
5286            ((signed) / (signed))
5287         b) return an 16 bit signed int; this is what we're doing here!
5288   */
5289
5290   size = AOP_SIZE (result) - 1;
5291   offset = 1;
5292   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5293   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5294
5295   pushedB = pushB ();
5296
5297   /* signed or unsigned */
5298   if (lUnsigned && rUnsigned)
5299     {
5300       /* unsigned is easy */
5301       MOVB (aopGet (right, 0, FALSE, FALSE));
5302       MOVA (aopGet (left, 0, FALSE, FALSE));
5303       emitcode ("div", "ab");
5304       aopPut (result, "a", 0);
5305       while (size--)
5306         aopPut (result, zero, offset++);
5307
5308       popB (pushedB);
5309       return;
5310     }
5311
5312   /* signed is a little bit more difficult */
5313
5314   /* now sign adjust for both left & right */
5315
5316   /* let's see what's needed: */
5317   /* apply negative sign during runtime */
5318   runtimeSign = FALSE;
5319   /* negative sign from literals */
5320   compiletimeSign = FALSE;
5321
5322   if (!lUnsigned)
5323     {
5324       if (AOP_TYPE(left) == AOP_LIT)
5325         {
5326           /* signed literal */
5327           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5328           if (val < 0)
5329             compiletimeSign = TRUE;
5330         }
5331       else
5332         /* signed but not literal */
5333         runtimeSign = TRUE;
5334     }
5335
5336   if (!rUnsigned)
5337     {
5338       if (AOP_TYPE(right) == AOP_LIT)
5339         {
5340           /* signed literal */
5341           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5342           if (val < 0)
5343             compiletimeSign ^= TRUE;
5344         }
5345       else
5346         /* signed but not literal */
5347         runtimeSign = TRUE;
5348     }
5349
5350   /* initialize F0, which stores the runtime sign */
5351   if (runtimeSign)
5352     {
5353       if (compiletimeSign)
5354         emitcode ("setb", "F0"); /* set sign flag */
5355       else
5356         emitcode ("clr", "F0"); /* reset sign flag */
5357     }
5358
5359   /* save the signs of the operands */
5360   if (AOP_TYPE(right) == AOP_LIT)
5361     {
5362       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5363
5364       if (!rUnsigned && val < 0)
5365         emitcode ("mov", "b,#0x%02x", -val);
5366       else
5367         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5368     }
5369   else /* ! literal */
5370     {
5371       if (rUnsigned)
5372         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5373       else
5374         {
5375           MOVA (aopGet (right, 0, FALSE, FALSE));
5376           lbl = newiTempLabel (NULL);
5377           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5378           emitcode ("cpl", "F0"); /* complement sign flag */
5379           emitcode ("cpl", "a");  /* 2's complement */
5380           emitcode ("inc", "a");
5381           emitLabel (lbl);
5382           emitcode ("mov", "b,a");
5383         }
5384     }
5385
5386   if (AOP_TYPE(left) == AOP_LIT)
5387     {
5388       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5389
5390       if (!lUnsigned && val < 0)
5391         emitcode ("mov", "a,#0x%02x", -val);
5392       else
5393         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5394     }
5395   else /* ! literal */
5396     {
5397       MOVA (aopGet (left, 0, FALSE, FALSE));
5398
5399       if (!lUnsigned)
5400         {
5401           lbl = newiTempLabel (NULL);
5402           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5403           emitcode ("cpl", "F0"); /* complement sign flag */
5404           emitcode ("cpl", "a");  /* 2's complement */
5405           emitcode ("inc", "a");
5406           emitLabel (lbl);
5407         }
5408     }
5409
5410   /* now the division */
5411   emitcode ("div", "ab");
5412
5413   if (runtimeSign || compiletimeSign)
5414     {
5415       lbl = newiTempLabel (NULL);
5416       if (runtimeSign)
5417         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5418       emitcode ("cpl", "a"); /* lsb 2's complement */
5419       emitcode ("inc", "a");
5420       emitLabel (lbl);
5421
5422       accuse = aopPut (result, "a", 0);
5423       if (size > 0)
5424         {
5425           /* msb is 0x00 or 0xff depending on the sign */
5426           if (runtimeSign)
5427             {
5428               if (accuse)
5429                 {
5430                   emitcode ("push", "acc");
5431                   pushedA = TRUE;
5432                 }
5433               emitcode ("mov", "c,F0");
5434               emitcode ("subb", "a,acc");
5435               while (size--)
5436                 aopPut (result, "a", offset++);
5437             }
5438           else /* compiletimeSign */
5439             {
5440               if (aopPutUsesAcc (result, "#0xFF", offset))
5441                 {
5442                   emitcode ("push", "acc");
5443                   pushedA = TRUE;
5444                 }
5445               while (size--)
5446                 aopPut (result, "#0xff", offset++);
5447             }
5448         }
5449     }
5450   else
5451     {
5452       aopPut (result, "a", 0);
5453       while (size--)
5454         aopPut (result, zero, offset++);
5455     }
5456
5457   if (pushedA)
5458     emitcode ("pop", "acc");
5459   popB (pushedB);
5460 }
5461
5462 /*-----------------------------------------------------------------*/
5463 /* genDiv - generates code for division                            */
5464 /*-----------------------------------------------------------------*/
5465 static void
5466 genDiv (iCode * ic)
5467 {
5468   operand *left = IC_LEFT (ic);
5469   operand *right = IC_RIGHT (ic);
5470   operand *result = IC_RESULT (ic);
5471
5472   D (emitcode (";", "genDiv"));
5473
5474   /* assign the amsops */
5475   aopOp (left, ic, FALSE);
5476   aopOp (right, ic, FALSE);
5477   aopOp (result, ic, TRUE);
5478
5479   /* special cases first */
5480   /* both are bits */
5481   if (AOP_TYPE (left) == AOP_CRY &&
5482       AOP_TYPE (right) == AOP_CRY)
5483     {
5484       genDivbits (left, right, result);
5485       goto release;
5486     }
5487
5488   /* if both are of size == 1 */
5489   if (AOP_SIZE (left) == 1 &&
5490       AOP_SIZE (right) == 1)
5491     {
5492       genDivOneByte (left, right, result);
5493       goto release;
5494     }
5495
5496   /* should have been converted to function call */
5497   assert (0);
5498 release:
5499   freeAsmop (result, NULL, ic, TRUE);
5500   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5501   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5502 }
5503
5504 /*-----------------------------------------------------------------*/
5505 /* genModbits :- modulus of bits                                   */
5506 /*-----------------------------------------------------------------*/
5507 static void
5508 genModbits (operand * left,
5509             operand * right,
5510             operand * result)
5511 {
5512   char *l;
5513   bool pushedB;
5514
5515   D (emitcode (";", "genModbits"));
5516
5517   pushedB = pushB ();
5518
5519   /* the result must be bit */
5520   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5521   l = aopGet (left, 0, FALSE, FALSE);
5522
5523   MOVA (l);
5524
5525   emitcode ("div", "ab");
5526   emitcode ("mov", "a,b");
5527   emitcode ("rrc", "a");
5528
5529   popB (pushedB);
5530
5531   aopPut (result, "c", 0);
5532 }
5533
5534 /*-----------------------------------------------------------------*/
5535 /* genModOneByte : 8 bit modulus                                   */
5536 /*-----------------------------------------------------------------*/
5537 static void
5538 genModOneByte (operand * left,
5539                operand * right,
5540                operand * result)
5541 {
5542   bool lUnsigned, rUnsigned, pushedB;
5543   bool runtimeSign, compiletimeSign;
5544   symbol *lbl;
5545   int size, offset;
5546
5547   D (emitcode (";", "genModOneByte"));
5548
5549   size = AOP_SIZE (result) - 1;
5550   offset = 1;
5551   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5552   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5553
5554   /* if right is a literal, check it for 2^n */
5555   if (AOP_TYPE(right) == AOP_LIT)
5556     {
5557       unsigned char val = abs((int) operandLitValue(right));
5558       symbol *lbl2 = NULL;
5559
5560       switch (val)
5561         {
5562           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5563           case 2:
5564           case 4:
5565           case 8:
5566           case 16:
5567           case 32:
5568           case 64:
5569           case 128:
5570             if (lUnsigned)
5571               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5572                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5573               /* because iCode should have been changed to genAnd  */
5574               /* see file "SDCCopt.c", function "convertToFcall()" */
5575
5576             MOVA (aopGet (left, 0, FALSE, FALSE));
5577             emitcode ("mov", "c,acc.7");
5578             emitcode ("anl", "a,#0x%02x", val - 1);
5579             lbl = newiTempLabel (NULL);
5580             emitcode ("jz", "%05d$", (lbl->key + 100));
5581             emitcode ("jnc", "%05d$", (lbl->key + 100));
5582             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5583             if (size)
5584               {
5585                 int size2 = size;
5586                 int offs2 = offset;
5587
5588                 aopPut (result, "a", 0);
5589                 while (size2--)
5590                   aopPut (result, "#0xff", offs2++);
5591                 lbl2 = newiTempLabel (NULL);
5592                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5593               }
5594             emitLabel (lbl);
5595             aopPut (result, "a", 0);
5596             while (size--)
5597               aopPut (result, zero, offset++);
5598             if (lbl2)
5599               {
5600                 emitLabel (lbl2);
5601               }
5602             return;
5603
5604           default:
5605             break;
5606         }
5607     }
5608
5609   pushedB = pushB ();
5610
5611   /* signed or unsigned */
5612   if (lUnsigned && rUnsigned)
5613     {
5614       /* unsigned is easy */
5615       MOVB (aopGet (right, 0, FALSE, FALSE));
5616       MOVA (aopGet (left, 0, FALSE, FALSE));
5617       emitcode ("div", "ab");
5618       aopPut (result, "b", 0);
5619       while (size--)
5620         aopPut (result, zero, offset++);
5621
5622       popB (pushedB);
5623       return;
5624     }
5625
5626   /* signed is a little bit more difficult */
5627
5628   /* now sign adjust for both left & right */
5629
5630   /* modulus: sign of the right operand has no influence on the result! */
5631   if (AOP_TYPE(right) == AOP_LIT)
5632     {
5633       signed char val = (char) operandLitValue(right);
5634
5635       if (!rUnsigned && val < 0)
5636         emitcode ("mov", "b,#0x%02x", -val);
5637       else
5638         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5639     }
5640   else /* not literal */
5641     {
5642       if (rUnsigned)
5643         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5644       else
5645         {
5646           MOVA (aopGet (right, 0, FALSE, FALSE));
5647           lbl = newiTempLabel (NULL);
5648           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5649           emitcode ("cpl", "a"); /* 2's complement */
5650           emitcode ("inc", "a");
5651           emitLabel (lbl);
5652           emitcode ("mov", "b,a");
5653         }
5654     }
5655
5656   /* let's see what's needed: */
5657   /* apply negative sign during runtime */
5658   runtimeSign = FALSE;
5659   /* negative sign from literals */
5660   compiletimeSign = FALSE;
5661
5662   /* sign adjust left side */
5663   if (AOP_TYPE(left) == AOP_LIT)
5664     {
5665       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5666
5667       if (!lUnsigned && val < 0)
5668         {
5669           compiletimeSign = TRUE; /* set sign flag */
5670           emitcode ("mov", "a,#0x%02x", -val);
5671         }
5672       else
5673         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5674     }
5675   else /* ! literal */
5676     {
5677       MOVA (aopGet (left, 0, FALSE, FALSE));
5678
5679       if (!lUnsigned)
5680         {
5681           runtimeSign = TRUE;
5682           emitcode ("clr", "F0"); /* clear sign flag */
5683
5684           lbl = newiTempLabel (NULL);
5685           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5686           emitcode ("setb", "F0"); /* set sign flag */
5687           emitcode ("cpl", "a");   /* 2's complement */
5688           emitcode ("inc", "a");
5689           emitLabel (lbl);
5690         }
5691     }
5692
5693   /* now the modulus */
5694   emitcode ("div", "ab");
5695
5696   if (runtimeSign || compiletimeSign)
5697     {
5698       emitcode ("mov", "a,b");
5699       lbl = newiTempLabel (NULL);
5700       if (runtimeSign)
5701         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5702       emitcode ("cpl", "a"); /* 2's complement */
5703       emitcode ("inc", "a");
5704       emitLabel (lbl);
5705
5706       aopPut (result, "a", 0);
5707       if (size > 0)
5708         {
5709           /* msb is 0x00 or 0xff depending on the sign */
5710           if (runtimeSign)
5711             {
5712               emitcode ("mov", "c,F0");
5713               emitcode ("subb", "a,acc");
5714               while (size--)
5715                 aopPut (result, "a", offset++);
5716             }
5717           else /* compiletimeSign */
5718             while (size--)
5719               aopPut (result, "#0xff", offset++);
5720         }
5721     }
5722   else
5723     {
5724       aopPut (result, "b", 0);
5725       while (size--)
5726         aopPut (result, zero, offset++);
5727     }
5728
5729   popB (pushedB);
5730 }
5731
5732 /*-----------------------------------------------------------------*/
5733 /* genMod - generates code for division                            */
5734 /*-----------------------------------------------------------------*/
5735 static void
5736 genMod (iCode * ic)
5737 {
5738   operand *left = IC_LEFT (ic);
5739   operand *right = IC_RIGHT (ic);
5740   operand *result = IC_RESULT (ic);
5741
5742   D (emitcode (";", "genMod"));
5743
5744   /* assign the asmops */
5745   aopOp (left, ic, FALSE);
5746   aopOp (right, ic, FALSE);
5747   aopOp (result, ic, TRUE);
5748
5749   /* special cases first */
5750   /* both are bits */
5751   if (AOP_TYPE (left) == AOP_CRY &&
5752       AOP_TYPE (right) == AOP_CRY)
5753     {
5754       genModbits (left, right, result);
5755       goto release;
5756     }
5757
5758   /* if both are of size == 1 */
5759   if (AOP_SIZE (left) == 1 &&
5760       AOP_SIZE (right) == 1)
5761     {
5762       genModOneByte (left, right, result);
5763       goto release;
5764     }
5765
5766   /* should have been converted to function call */
5767   assert (0);
5768
5769 release:
5770   freeAsmop (result, NULL, ic, TRUE);
5771   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5772   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5773 }
5774
5775 /*-----------------------------------------------------------------*/
5776 /* genIfxJump :- will create a jump depending on the ifx           */
5777 /*-----------------------------------------------------------------*/
5778 static void
5779 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5780 {
5781   symbol *jlbl;
5782   symbol *tlbl = newiTempLabel (NULL);
5783   char *inst;
5784
5785   D (emitcode (";", "genIfxJump"));
5786
5787   /* if true label then we jump if condition
5788      supplied is true */
5789   if (IC_TRUE (ic))
5790     {
5791       jlbl = IC_TRUE (ic);
5792       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5793                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5794     }
5795   else
5796     {
5797       /* false label is present */
5798       jlbl = IC_FALSE (ic);
5799       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5800                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5801     }
5802   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5803     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5804   else
5805     emitcode (inst, "%05d$", tlbl->key + 100);
5806   freeForBranchAsmop (result);
5807   freeForBranchAsmop (right);
5808   freeForBranchAsmop (left);
5809   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5810   emitLabel (tlbl);
5811
5812   /* mark the icode as generated */
5813   ic->generated = 1;
5814 }
5815
5816 /*-----------------------------------------------------------------*/
5817 /* genCmp :- greater or less than comparison                       */
5818 /*-----------------------------------------------------------------*/
5819 static void
5820 genCmp (operand * left, operand * right,
5821         operand * result, iCode * ifx, int sign, iCode *ic)
5822 {
5823   int size, offset = 0;
5824   unsigned long lit = 0L;
5825   bool rightInB;
5826
5827   D (emitcode (";", "genCmp"));
5828
5829   /* if left & right are bit variables */
5830   if (AOP_TYPE (left) == AOP_CRY &&
5831       AOP_TYPE (right) == AOP_CRY)
5832     {
5833       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5834       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5835     }
5836   else
5837     {
5838       /* subtract right from left if at the
5839          end the carry flag is set then we know that
5840          left is greater than right */
5841       size = max (AOP_SIZE (left), AOP_SIZE (right));
5842
5843       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5844       if ((size == 1) && !sign &&
5845           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5846         {
5847           symbol *lbl = newiTempLabel (NULL);
5848           emitcode ("cjne", "%s,%s,%05d$",
5849                     aopGet (left, offset, FALSE, FALSE),
5850                     aopGet (right, offset, FALSE, FALSE),
5851                     lbl->key + 100);
5852           emitLabel (lbl);
5853         }
5854       else
5855         {
5856           if (AOP_TYPE (right) == AOP_LIT)
5857             {
5858               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5859               /* optimize if(x < 0) or if(x >= 0) */
5860               if (lit == 0L)
5861                 {
5862                   if (!sign)
5863                     {
5864                       CLRC;
5865                     }
5866                   else
5867                     {
5868                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5869                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5870                         {
5871                           genIfxJump (ifx, "acc.7", left, right, result);
5872                           freeAsmop (right, NULL, ic, TRUE);
5873                           freeAsmop (left, NULL, ic, TRUE);
5874
5875                           return;
5876                         }
5877                       else
5878                         {
5879                           emitcode ("rlc", "a");
5880                         }
5881                     }
5882                   goto release;
5883                 }
5884               else
5885                 {//nonzero literal
5886                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5887                   while (size && (bytelit == 0))
5888                     {
5889                       offset++;
5890                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5891                       size--;
5892                     }
5893                   CLRC;
5894                   while (size--)
5895                     {
5896                       MOVA (aopGet (left, offset, FALSE, FALSE));
5897                       if (sign && size == 0)
5898                         {
5899                           emitcode ("xrl", "a,#0x80");
5900                           emitcode ("subb", "a,#0x%02x",
5901                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5902                         }
5903                       else
5904                         {
5905                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5906                         }
5907                       offset++;
5908                     }
5909                   goto release;
5910                 }
5911             }
5912           CLRC;
5913           while (size--)
5914             {
5915               bool pushedB = FALSE;
5916               rightInB = aopGetUsesAcc(right, offset);
5917               if (rightInB)
5918                 {
5919                   pushedB = pushB ();
5920                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5921                 }
5922               MOVA (aopGet (left, offset, FALSE, FALSE));
5923               if (sign && size == 0)
5924                 {
5925                   emitcode ("xrl", "a,#0x80");
5926                   if (!rightInB)
5927                     {
5928                       pushedB = pushB ();
5929                       rightInB++;
5930                       MOVB (aopGet (right, offset, FALSE, FALSE));
5931                     }
5932                   emitcode ("xrl", "b,#0x80");
5933                   emitcode ("subb", "a,b");
5934                 }
5935               else
5936                 {
5937                   if (rightInB)
5938                     emitcode ("subb", "a,b");
5939                   else
5940                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5941                 }
5942               if (rightInB)
5943                 popB (pushedB);
5944               offset++;
5945             }
5946         }
5947     }
5948
5949 release:
5950   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5951   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5952   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5953     {
5954       outBitC (result);
5955     }
5956   else
5957     {
5958       /* if the result is used in the next
5959          ifx conditional branch then generate
5960          code a little differently */
5961       if (ifx)
5962         {
5963           genIfxJump (ifx, "c", NULL, NULL, result);
5964         }
5965       else
5966         {
5967           outBitC (result);
5968         }
5969       /* leave the result in acc */
5970     }
5971 }
5972
5973 /*-----------------------------------------------------------------*/
5974 /* genCmpGt :- greater than comparison                             */
5975 /*-----------------------------------------------------------------*/
5976 static void
5977 genCmpGt (iCode * ic, iCode * ifx)
5978 {
5979   operand *left, *right, *result;
5980   sym_link *letype, *retype;
5981   int sign;
5982
5983   D (emitcode (";", "genCmpGt"));
5984
5985   left = IC_LEFT (ic);
5986   right = IC_RIGHT (ic);
5987   result = IC_RESULT (ic);
5988
5989   letype = getSpec (operandType (left));
5990   retype = getSpec (operandType (right));
5991   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5992            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5993   /* assign the amsops */
5994   aopOp (result, ic, TRUE);
5995   aopOp (left, ic, FALSE);
5996   aopOp (right, ic, FALSE);
5997
5998   genCmp (right, left, result, ifx, sign, ic);
5999
6000   freeAsmop (result, NULL, ic, TRUE);
6001 }
6002
6003 /*-----------------------------------------------------------------*/
6004 /* genCmpLt - less than comparisons                                */
6005 /*-----------------------------------------------------------------*/
6006 static void
6007 genCmpLt (iCode * ic, iCode * ifx)
6008 {
6009   operand *left, *right, *result;
6010   sym_link *letype, *retype;
6011   int sign;
6012
6013   D (emitcode (";", "genCmpLt"));
6014
6015   left = IC_LEFT (ic);
6016   right = IC_RIGHT (ic);
6017   result = IC_RESULT (ic);
6018
6019   letype = getSpec (operandType (left));
6020   retype = getSpec (operandType (right));
6021   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6022            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6023   /* assign the amsops */
6024   aopOp (result, ic, TRUE);
6025   aopOp (left, ic, FALSE);
6026   aopOp (right, ic, FALSE);
6027
6028   genCmp (left, right, result, ifx, sign, ic);
6029
6030   freeAsmop (result, NULL, ic, TRUE);
6031 }
6032
6033 /*-----------------------------------------------------------------*/
6034 /* gencjneshort - compare and jump if not equal                    */
6035 /*-----------------------------------------------------------------*/
6036 static void
6037 gencjneshort (operand * left, operand * right, symbol * lbl)
6038 {
6039   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6040   int offset = 0;
6041   unsigned long lit = 0L;
6042
6043   D (emitcode (";", "gencjneshort"));
6044
6045   /* if the left side is a literal or
6046      if the right is in a pointer register and left
6047      is not */
6048   if ((AOP_TYPE (left) == AOP_LIT) ||
6049       (AOP_TYPE (left) == AOP_IMMD) ||
6050       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6051     {
6052       operand *t = right;
6053       right = left;
6054       left = t;
6055     }
6056
6057   if (AOP_TYPE (right) == AOP_LIT)
6058     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6059
6060   /* if the right side is a literal then anything goes */
6061   if (AOP_TYPE (right) == AOP_LIT &&
6062       AOP_TYPE (left) != AOP_DIR  &&
6063       AOP_TYPE (left) != AOP_IMMD)
6064     {
6065       while (size--)
6066         {
6067           emitcode ("cjne", "%s,%s,%05d$",
6068                     aopGet (left, offset, FALSE, FALSE),
6069                     aopGet (right, offset, FALSE, FALSE),
6070                     lbl->key + 100);
6071           offset++;
6072         }
6073     }
6074
6075   /* if the right side is in a register or in direct space or
6076      if the left is a pointer register & right is not */
6077   else if (AOP_TYPE (right) == AOP_REG ||
6078            AOP_TYPE (right) == AOP_DIR ||
6079            AOP_TYPE (right) == AOP_LIT ||
6080            AOP_TYPE (right) == AOP_IMMD ||
6081            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6082            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6083     {
6084       while (size--)
6085         {
6086           MOVA (aopGet (left, offset, FALSE, FALSE));
6087           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6088               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6089             emitcode ("jnz", "%05d$", lbl->key + 100);
6090           else
6091             emitcode ("cjne", "a,%s,%05d$",
6092                       aopGet (right, offset, FALSE, TRUE),
6093                       lbl->key + 100);
6094           offset++;
6095         }
6096     }
6097   else
6098     {
6099       /* right is a pointer reg need both a & b */
6100       while (size--)
6101         {
6102           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6103           wassertl(!BINUSE, "B was in use");
6104           MOVB (aopGet (left, offset, FALSE, FALSE));
6105           MOVA (aopGet (right, offset, FALSE, FALSE));
6106           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6107           offset++;
6108         }
6109     }
6110 }
6111
6112 /*-----------------------------------------------------------------*/
6113 /* gencjne - compare and jump if not equal                         */
6114 /*-----------------------------------------------------------------*/
6115 static void
6116 gencjne (operand * left, operand * right, symbol * lbl)
6117 {
6118   symbol *tlbl = newiTempLabel (NULL);
6119
6120   D (emitcode (";", "gencjne"));
6121
6122   gencjneshort (left, right, lbl);
6123
6124   emitcode ("mov", "a,%s", one);
6125   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6126   emitLabel (lbl);
6127   emitcode ("clr", "a");
6128   emitLabel (tlbl);
6129 }
6130
6131 /*-----------------------------------------------------------------*/
6132 /* genCmpEq - generates code for equal to                          */
6133 /*-----------------------------------------------------------------*/
6134 static void
6135 genCmpEq (iCode * ic, iCode * ifx)
6136 {
6137   bool swappedLR = FALSE;
6138   operand *left, *right, *result;
6139
6140   D (emitcode (";", "genCmpEq"));
6141
6142   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6143   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6144   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6145
6146   /* if literal, literal on the right or
6147      if the right is in a pointer register and left
6148      is not */
6149   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6150       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6151     {
6152       operand *t = IC_RIGHT (ic);
6153       IC_RIGHT (ic) = IC_LEFT (ic);
6154       IC_LEFT (ic) = t;
6155       swappedLR = TRUE;
6156     }
6157
6158   if (ifx && !AOP_SIZE (result))
6159     {
6160       symbol *tlbl;
6161       /* if they are both bit variables */
6162       if (AOP_TYPE (left) == AOP_CRY &&
6163           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6164         {
6165           if (AOP_TYPE (right) == AOP_LIT)
6166             {
6167               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6168               if (lit == 0L)
6169                 {
6170                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6171                   emitcode ("cpl", "c");
6172                 }
6173               else if (lit == 1L)
6174                 {
6175                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6176                 }
6177               else
6178                 {
6179                   emitcode ("clr", "c");
6180                 }
6181               /* AOP_TYPE(right) == AOP_CRY */
6182             }
6183           else
6184             {
6185               symbol *lbl = newiTempLabel (NULL);
6186               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6187               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6188               emitcode ("cpl", "c");
6189               emitLabel (lbl);
6190             }
6191           /* if true label then we jump if condition
6192              supplied is true */
6193           tlbl = newiTempLabel (NULL);
6194           if (IC_TRUE (ifx))
6195             {
6196               emitcode ("jnc", "%05d$", tlbl->key + 100);
6197               freeForBranchAsmop (result);
6198               freeForBranchAsmop (right);
6199               freeForBranchAsmop (left);
6200               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6201             }
6202           else
6203             {
6204               emitcode ("jc", "%05d$", tlbl->key + 100);
6205               freeForBranchAsmop (result);
6206               freeForBranchAsmop (right);
6207               freeForBranchAsmop (left);
6208               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6209             }
6210           emitLabel (tlbl);
6211         }
6212       else
6213         {
6214           tlbl = newiTempLabel (NULL);
6215           gencjneshort (left, right, tlbl);
6216           if (IC_TRUE (ifx))
6217             {
6218               freeForBranchAsmop (result);
6219               freeForBranchAsmop (right);
6220               freeForBranchAsmop (left);
6221               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6222               emitLabel (tlbl);
6223             }
6224           else
6225             {
6226               symbol *lbl = newiTempLabel (NULL);
6227               emitcode ("sjmp", "%05d$", lbl->key + 100);
6228               emitLabel (tlbl);
6229               freeForBranchAsmop (result);
6230               freeForBranchAsmop (right);
6231               freeForBranchAsmop (left);
6232               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6233               emitLabel (lbl);
6234             }
6235         }
6236       /* mark the icode as generated */
6237       ifx->generated = 1;
6238       goto release;
6239     }
6240
6241   /* if they are both bit variables */
6242   if (AOP_TYPE (left) == AOP_CRY &&
6243       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6244     {
6245       if (AOP_TYPE (right) == AOP_LIT)
6246         {
6247           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6248           if (lit == 0L)
6249             {
6250               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6251               emitcode ("cpl", "c");
6252             }
6253           else if (lit == 1L)
6254             {
6255               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6256             }
6257           else
6258             {
6259               emitcode ("clr", "c");
6260             }
6261           /* AOP_TYPE(right) == AOP_CRY */
6262         }
6263       else
6264         {
6265           symbol *lbl = newiTempLabel (NULL);
6266           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6267           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6268           emitcode ("cpl", "c");
6269           emitLabel (lbl);
6270         }
6271       /* c = 1 if egal */
6272       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6273         {
6274           outBitC (result);
6275           goto release;
6276         }
6277       if (ifx)
6278         {
6279           genIfxJump (ifx, "c", left, right, result);
6280           goto release;
6281         }
6282       /* if the result is used in an arithmetic operation
6283          then put the result in place */
6284       outBitC (result);
6285     }
6286   else
6287     {
6288       gencjne (left, right, newiTempLabel (NULL));
6289       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6290         {
6291           aopPut (result, "a", 0);
6292           goto release;
6293         }
6294       if (ifx)
6295         {
6296           genIfxJump (ifx, "a", left, right, result);
6297           goto release;
6298         }
6299       /* if the result is used in an arithmetic operation
6300          then put the result in place */
6301       if (AOP_TYPE (result) != AOP_CRY)
6302         outAcc (result);
6303       /* leave the result in acc */
6304     }
6305
6306 release:
6307   freeAsmop (result, NULL, ic, TRUE);
6308   if (!swappedLR)
6309     {
6310       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6311       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6312     }
6313   else
6314     {
6315       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6316       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6317     }
6318 }
6319
6320 /*-----------------------------------------------------------------*/
6321 /* ifxForOp - returns the icode containing the ifx for operand     */
6322 /*-----------------------------------------------------------------*/
6323 static iCode *
6324 ifxForOp (operand * op, iCode * ic)
6325 {
6326   /* if true symbol then needs to be assigned */
6327   if (IS_TRUE_SYMOP (op))
6328     return NULL;
6329
6330   /* if this has register type condition and
6331      the next instruction is ifx with the same operand
6332      and live to of the operand is upto the ifx only then */
6333   if (ic->next &&
6334       ic->next->op == IFX &&
6335       IC_COND (ic->next)->key == op->key &&
6336       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6337     return ic->next;
6338
6339   return NULL;
6340 }
6341
6342 /*-----------------------------------------------------------------*/
6343 /* hasInc - operand is incremented before any other use            */
6344 /*-----------------------------------------------------------------*/
6345 static iCode *
6346 hasInc (operand *op, iCode *ic, int osize)
6347 {
6348   sym_link *type = operandType(op);
6349   sym_link *retype = getSpec (type);
6350   iCode *lic = ic->next;
6351   int isize ;
6352
6353   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6354   if (!IS_SYMOP(op)) return NULL;
6355
6356   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6357   if (IS_AGGREGATE(type->next)) return NULL;
6358   if (osize != (isize = getSize(type->next))) return NULL;
6359
6360   while (lic) {
6361     /* if operand of the form op = op + <sizeof *op> */
6362     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6363         isOperandEqual(IC_RESULT(lic),op) &&
6364         isOperandLiteral(IC_RIGHT(lic)) &&
6365         operandLitValue(IC_RIGHT(lic)) == isize) {
6366       return lic;
6367     }
6368     /* if the operand used or deffed */
6369     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6370       return NULL;
6371     }
6372     /* if GOTO or IFX */
6373     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6374     lic = lic->next;
6375   }
6376   return NULL;
6377 }
6378
6379 /*-----------------------------------------------------------------*/
6380 /* genAndOp - for && operation                                     */
6381 /*-----------------------------------------------------------------*/
6382 static void
6383 genAndOp (iCode * ic)
6384 {
6385   operand *left, *right, *result;
6386   symbol *tlbl;
6387
6388   D (emitcode (";", "genAndOp"));
6389
6390   /* note here that && operations that are in an
6391      if statement are taken away by backPatchLabels
6392      only those used in arthmetic operations remain */
6393   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6394   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6395   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6396
6397   /* if both are bit variables */
6398   if (AOP_TYPE (left) == AOP_CRY &&
6399       AOP_TYPE (right) == AOP_CRY)
6400     {
6401       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6402       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6403       outBitC (result);
6404     }
6405   else
6406     {
6407       tlbl = newiTempLabel (NULL);
6408       toBoolean (left);
6409       emitcode ("jz", "%05d$", tlbl->key + 100);
6410       toBoolean (right);
6411       emitLabel (tlbl);
6412       outBitAcc (result);
6413     }
6414
6415   freeAsmop (result, NULL, ic, TRUE);
6416   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6417   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6418 }
6419
6420
6421 /*-----------------------------------------------------------------*/
6422 /* genOrOp - for || operation                                      */
6423 /*-----------------------------------------------------------------*/
6424 static void
6425 genOrOp (iCode * ic)
6426 {
6427   operand *left, *right, *result;
6428   symbol *tlbl;
6429
6430   D (emitcode (";", "genOrOp"));
6431
6432   /* note here that || operations that are in an
6433      if statement are taken away by backPatchLabels
6434      only those used in arthmetic operations remain */
6435   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6436   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6437   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6438
6439   /* if both are bit variables */
6440   if (AOP_TYPE (left) == AOP_CRY &&
6441       AOP_TYPE (right) == AOP_CRY)
6442     {
6443       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6444       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6445       outBitC (result);
6446     }
6447   else
6448     {
6449       tlbl = newiTempLabel (NULL);
6450       toBoolean (left);
6451       emitcode ("jnz", "%05d$", tlbl->key + 100);
6452       toBoolean (right);
6453       emitLabel (tlbl);
6454       outBitAcc (result);
6455     }
6456
6457   freeAsmop (result, NULL, ic, TRUE);
6458   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6459   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6460 }
6461
6462 /*-----------------------------------------------------------------*/
6463 /* isLiteralBit - test if lit == 2^n                               */
6464 /*-----------------------------------------------------------------*/
6465 static int
6466 isLiteralBit (unsigned long lit)
6467 {
6468   unsigned long pw[32] =
6469   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6470    0x100L, 0x200L, 0x400L, 0x800L,
6471    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6472    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6473    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6474    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6475    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6476   int idx;
6477
6478   for (idx = 0; idx < 32; idx++)
6479     if (lit == pw[idx])
6480       return idx + 1;
6481   return 0;
6482 }
6483
6484 /*-----------------------------------------------------------------*/
6485 /* continueIfTrue -                                                */
6486 /*-----------------------------------------------------------------*/
6487 static void
6488 continueIfTrue (iCode * ic)
6489 {
6490   if (IC_TRUE (ic))
6491     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6492   ic->generated = 1;
6493 }
6494
6495 /*-----------------------------------------------------------------*/
6496 /* jmpIfTrue -                                                     */
6497 /*-----------------------------------------------------------------*/
6498 static void
6499 jumpIfTrue (iCode * ic)
6500 {
6501   if (!IC_TRUE (ic))
6502     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6503   ic->generated = 1;
6504 }
6505
6506 /*-----------------------------------------------------------------*/
6507 /* jmpTrueOrFalse -                                                */
6508 /*-----------------------------------------------------------------*/
6509 static void
6510 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6511 {
6512   // ugly but optimized by peephole
6513   if (IC_TRUE (ic))
6514     {
6515       symbol *nlbl = newiTempLabel (NULL);
6516       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6517       emitLabel (tlbl);
6518       freeForBranchAsmop (result);
6519       freeForBranchAsmop (right);
6520       freeForBranchAsmop (left);
6521       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6522       emitLabel (nlbl);
6523     }
6524   else
6525     {
6526       freeForBranchAsmop (result);
6527       freeForBranchAsmop (right);
6528       freeForBranchAsmop (left);
6529       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6530       emitLabel (tlbl);
6531     }
6532   ic->generated = 1;
6533 }
6534
6535 /*-----------------------------------------------------------------*/
6536 /* genAnd  - code for and                                          */
6537 /*-----------------------------------------------------------------*/
6538 static void
6539 genAnd (iCode * ic, iCode * ifx)
6540 {
6541   operand *left, *right, *result;
6542   int size, offset = 0;
6543   unsigned long lit = 0L;
6544   int bytelit = 0;
6545   char buffer[10];
6546
6547   D (emitcode (";", "genAnd"));
6548
6549   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6550   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6551   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6552
6553 #ifdef DEBUG_TYPE
6554   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6555             AOP_TYPE (result),
6556             AOP_TYPE (left), AOP_TYPE (right));
6557   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6558             AOP_SIZE (result),
6559             AOP_SIZE (left), AOP_SIZE (right));
6560 #endif
6561
6562   /* if left is a literal & right is not then exchange them */
6563   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6564       AOP_NEEDSACC (left))
6565     {
6566       operand *tmp = right;
6567       right = left;
6568       left = tmp;
6569     }
6570
6571   /* if result = right then exchange left and right */
6572   if (sameRegs (AOP (result), AOP (right)))
6573     {
6574       operand *tmp = right;
6575       right = left;
6576       left = tmp;
6577     }
6578
6579   /* if right is bit then exchange them */
6580   if (AOP_TYPE (right) == AOP_CRY &&
6581       AOP_TYPE (left) != AOP_CRY)
6582     {
6583       operand *tmp = right;
6584       right = left;
6585       left = tmp;
6586     }
6587   if (AOP_TYPE (right) == AOP_LIT)
6588     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6589
6590   size = AOP_SIZE (result);
6591
6592   // if(bit & yy)
6593   // result = bit & yy;
6594   if (AOP_TYPE (left) == AOP_CRY)
6595     {
6596       // c = bit & literal;
6597       if (AOP_TYPE (right) == AOP_LIT)
6598         {
6599           if (lit & 1)
6600             {
6601               if (size && sameRegs (AOP (result), AOP (left)))
6602                 // no change
6603                 goto release;
6604               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6605             }
6606           else
6607             {
6608               // bit(result) = 0;
6609               if (size && (AOP_TYPE (result) == AOP_CRY))
6610                 {
6611                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6612                   goto release;
6613                 }
6614               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6615                 {
6616                   jumpIfTrue (ifx);
6617                   goto release;
6618                 }
6619               emitcode ("clr", "c");
6620             }
6621         }
6622       else
6623         {
6624           if (AOP_TYPE (right) == AOP_CRY)
6625             {
6626               // c = bit & bit;
6627               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6628               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6629             }
6630           else
6631             {
6632               // c = bit & val;
6633               MOVA (aopGet (right, 0, FALSE, FALSE));
6634               // c = lsb
6635               emitcode ("rrc", "a");
6636               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6637             }
6638         }
6639       // bit = c
6640       // val = c
6641       if (size)
6642         outBitC (result);
6643       // if(bit & ...)
6644       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6645         genIfxJump (ifx, "c", left, right, result);
6646       goto release;
6647     }
6648
6649   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6650   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6651   if ((AOP_TYPE (right) == AOP_LIT) &&
6652       (AOP_TYPE (result) == AOP_CRY) &&
6653       (AOP_TYPE (left) != AOP_CRY))
6654     {
6655       int posbit = isLiteralBit (lit);
6656       /* left &  2^n */
6657       if (posbit)
6658         {
6659           posbit--;
6660           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6661           // bit = left & 2^n
6662           if (size)
6663             {
6664               switch (posbit & 0x07)
6665                 {
6666                   case 0: emitcode ("rrc", "a");
6667                           break;
6668                   case 7: emitcode ("rlc", "a");
6669                           break;
6670                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6671                           break;
6672                 }
6673             }
6674           // if(left &  2^n)
6675           else
6676             {
6677               if (ifx)
6678                 {
6679                   SNPRINTF (buffer, sizeof(buffer),
6680                             "acc.%d", posbit & 0x07);
6681                   genIfxJump (ifx, buffer, left, right, result);
6682                 }
6683               else
6684                 {// what is this case? just found it in ds390/gen.c
6685                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6686                 }
6687               goto release;
6688             }
6689         }
6690       else
6691         {
6692           symbol *tlbl = newiTempLabel (NULL);
6693           int sizel = AOP_SIZE (left);
6694           if (size)
6695             emitcode ("setb", "c");
6696           while (sizel--)
6697             {
6698               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6699                 {
6700                   MOVA (aopGet (left, offset, FALSE, FALSE));
6701                   // byte ==  2^n ?
6702                   if ((posbit = isLiteralBit (bytelit)) != 0)
6703                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6704                   else
6705                     {
6706                       if (bytelit != 0x0FFL)
6707                         emitcode ("anl", "a,%s",
6708                                   aopGet (right, offset, FALSE, TRUE));
6709                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6710                     }
6711                 }
6712               offset++;
6713             }
6714           // bit = left & literal
6715           if (size)
6716             {
6717               emitcode ("clr", "c");
6718               emitLabel (tlbl);
6719             }
6720           // if(left & literal)
6721           else
6722             {
6723               if (ifx)
6724                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6725               else
6726                 emitLabel (tlbl);
6727               goto release;
6728             }
6729         }
6730       outBitC (result);
6731       goto release;
6732     }
6733
6734   /* if left is same as result */
6735   if (sameRegs (AOP (result), AOP (left)))
6736     {
6737       for (; size--; offset++)
6738         {
6739           if (AOP_TYPE (right) == AOP_LIT)
6740             {
6741               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6742               if (bytelit == 0x0FF)
6743                 {
6744                   /* dummy read of volatile operand */
6745                   if (isOperandVolatile (left, FALSE))
6746                     MOVA (aopGet (left, offset, FALSE, FALSE));
6747                   else
6748                     continue;
6749                 }
6750               else if (bytelit == 0)
6751                 {
6752                   aopPut (result, zero, offset);
6753                 }
6754               else if (IS_AOP_PREG (result))
6755                 {
6756                   MOVA (aopGet (left, offset, FALSE, TRUE));
6757                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6758                   aopPut (result, "a", offset);
6759                 }
6760               else
6761                 emitcode ("anl", "%s,%s",
6762                           aopGet (left, offset, FALSE, TRUE),
6763                           aopGet (right, offset, FALSE, FALSE));
6764             }
6765           else
6766             {
6767               if (AOP_TYPE (left) == AOP_ACC)
6768                 {
6769                   if (offset)
6770                     emitcode("mov", "a,b");
6771                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6772                 }
6773               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6774                 {
6775                   MOVB (aopGet (left, offset, FALSE, FALSE));
6776                   MOVA (aopGet (right, offset, FALSE, FALSE));
6777                   emitcode ("anl", "a,b");
6778                   aopPut (result, "a", offset);
6779                 }
6780               else if (aopGetUsesAcc (left, offset))
6781                 {
6782                   MOVA (aopGet (left, offset, FALSE, FALSE));
6783                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6784                   aopPut (result, "a", offset);
6785                 }
6786               else
6787                 {
6788                   MOVA (aopGet (right, offset, FALSE, FALSE));
6789                   if (IS_AOP_PREG (result))
6790                     {
6791                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6792                       aopPut (result, "a", offset);
6793                     }
6794                   else
6795                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6796                 }
6797             }
6798         }
6799     }
6800   else
6801     {
6802       // left & result in different registers
6803       if (AOP_TYPE (result) == AOP_CRY)
6804         {
6805           // result = bit
6806           // if(size), result in bit
6807           // if(!size && ifx), conditional oper: if(left & right)
6808           symbol *tlbl = newiTempLabel (NULL);
6809           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6810           if (size)
6811             emitcode ("setb", "c");
6812           while (sizer--)
6813             {
6814               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6815                   && AOP_TYPE(left)==AOP_ACC)
6816                 {
6817                   if (offset)
6818                     emitcode("mov", "a,b");
6819                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6820                 }
6821               else if (AOP_TYPE(left)==AOP_ACC)
6822                 {
6823                   if (!offset)
6824                     {
6825                       bool pushedB = pushB ();
6826                       emitcode("mov", "b,a");
6827                       MOVA (aopGet (right, offset, FALSE, FALSE));
6828                       emitcode("anl", "a,b");
6829                       popB (pushedB);
6830                     }
6831                   else
6832                     {
6833                       MOVA (aopGet (right, offset, FALSE, FALSE));
6834                       emitcode("anl", "a,b");
6835                     }
6836                 }
6837               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6838                 {
6839                   MOVB (aopGet (left, offset, FALSE, FALSE));
6840                   MOVA (aopGet (right, offset, FALSE, FALSE));
6841                   emitcode ("anl", "a,b");
6842                 }
6843               else if (aopGetUsesAcc (left, offset))
6844                 {
6845                   MOVA (aopGet (left, offset, FALSE, FALSE));
6846                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6847                     }
6848               else
6849                 {
6850                   MOVA (aopGet (right, offset, FALSE, FALSE));
6851                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6852                 }
6853
6854               emitcode ("jnz", "%05d$", tlbl->key + 100);
6855               offset++;
6856             }
6857           if (size)
6858             {
6859               CLRC;
6860               emitLabel (tlbl);
6861               outBitC (result);
6862             }
6863           else if (ifx)
6864             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6865           else
6866             emitLabel (tlbl);
6867         }
6868       else
6869         {
6870           for (; (size--); offset++)
6871             {
6872               // normal case
6873               // result = left & right
6874               if (AOP_TYPE (right) == AOP_LIT)
6875                 {
6876                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6877                   if (bytelit == 0x0FF)
6878                     {
6879                       aopPut (result,
6880                               aopGet (left, offset, FALSE, FALSE),
6881                               offset);
6882                       continue;
6883                     }
6884                   else if (bytelit == 0)
6885                     {
6886                       /* dummy read of volatile operand */
6887                       if (isOperandVolatile (left, FALSE))
6888                         MOVA (aopGet (left, offset, FALSE, FALSE));
6889                       aopPut (result, zero, offset);
6890                       continue;
6891                     }
6892                   else if (AOP_TYPE (left) == AOP_ACC)
6893                     {
6894                       if (!offset)
6895                         {
6896                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6897                           aopPut (result, "a", offset);
6898                           continue;
6899                         }
6900                       else
6901                         {
6902                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6903                           aopPut (result, "b", offset);
6904                           continue;
6905                         }
6906                     }
6907                 }
6908               // faster than result <- left, anl result,right
6909               // and better if result is SFR
6910               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6911                   && AOP_TYPE(left)==AOP_ACC)
6912                 {
6913                   if (offset)
6914                     emitcode("mov", "a,b");
6915                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6916                 }
6917               else if (AOP_TYPE(left)==AOP_ACC)
6918                 {
6919                   if (!offset)
6920                     {
6921                       bool pushedB = pushB ();
6922                       emitcode("mov", "b,a");
6923                       MOVA (aopGet (right, offset, FALSE, FALSE));
6924                       emitcode("anl", "a,b");
6925                       popB (pushedB);
6926                     }
6927                   else
6928                     {
6929                       MOVA (aopGet (right, offset, FALSE, FALSE));
6930                       emitcode("anl", "a,b");
6931                     }
6932                 }
6933               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6934                 {
6935                   MOVB (aopGet (left, offset, FALSE, FALSE));
6936                   MOVA (aopGet (right, offset, FALSE, FALSE));
6937                   emitcode ("anl", "a,b");
6938                 }
6939               else if (aopGetUsesAcc (left, offset))
6940                 {
6941                   MOVA (aopGet (left, offset, FALSE, FALSE));
6942                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6943                 }
6944               else
6945                 {
6946                   MOVA (aopGet (right, offset, FALSE, FALSE));
6947                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6948                 }
6949               aopPut (result, "a", offset);
6950             }
6951         }
6952     }
6953
6954 release:
6955   freeAsmop (result, NULL, ic, TRUE);
6956   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6957   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6958 }
6959
6960 /*-----------------------------------------------------------------*/
6961 /* genOr  - code for or                                            */
6962 /*-----------------------------------------------------------------*/
6963 static void
6964 genOr (iCode * ic, iCode * ifx)
6965 {
6966   operand *left, *right, *result;
6967   int size, offset = 0;
6968   unsigned long lit = 0L;
6969   int bytelit = 0;
6970
6971   D (emitcode (";", "genOr"));
6972
6973   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6974   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6975   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6976
6977 #ifdef DEBUG_TYPE
6978   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6979             AOP_TYPE (result),
6980             AOP_TYPE (left), AOP_TYPE (right));
6981   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6982             AOP_SIZE (result),
6983             AOP_SIZE (left), AOP_SIZE (right));
6984 #endif
6985
6986   /* if left is a literal & right is not then exchange them */
6987   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6988       AOP_NEEDSACC (left))
6989     {
6990       operand *tmp = right;
6991       right = left;
6992       left = tmp;
6993     }
6994
6995   /* if result = right then exchange them */
6996   if (sameRegs (AOP (result), AOP (right)))
6997     {
6998       operand *tmp = right;
6999       right = left;
7000       left = tmp;
7001     }
7002
7003   /* if right is bit then exchange them */
7004   if (AOP_TYPE (right) == AOP_CRY &&
7005       AOP_TYPE (left) != AOP_CRY)
7006     {
7007       operand *tmp = right;
7008       right = left;
7009       left = tmp;
7010     }
7011   if (AOP_TYPE (right) == AOP_LIT)
7012     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7013
7014   size = AOP_SIZE (result);
7015
7016   // if(bit | yy)
7017   // xx = bit | yy;
7018   if (AOP_TYPE (left) == AOP_CRY)
7019     {
7020       if (AOP_TYPE (right) == AOP_LIT)
7021         {
7022           // c = bit | literal;
7023           if (lit)
7024             {
7025               // lit != 0 => result = 1
7026               if (AOP_TYPE (result) == AOP_CRY)
7027                 {
7028                   if (size)
7029                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7030                   else if (ifx)
7031                     continueIfTrue (ifx);
7032                   goto release;
7033                 }
7034               emitcode ("setb", "c");
7035             }
7036           else
7037             {
7038               // lit == 0 => result = left
7039               if (size && sameRegs (AOP (result), AOP (left)))
7040                 goto release;
7041               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7042             }
7043         }
7044       else
7045         {
7046           if (AOP_TYPE (right) == AOP_CRY)
7047             {
7048               // c = bit | bit;
7049               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7050               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7051             }
7052           else
7053             {
7054               // c = bit | val;
7055               symbol *tlbl = newiTempLabel (NULL);
7056               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7057                 emitcode ("setb", "c");
7058               emitcode ("jb", "%s,%05d$",
7059                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7060               toBoolean (right);
7061               emitcode ("jnz", "%05d$", tlbl->key + 100);
7062               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7063                 {
7064                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7065                   goto release;
7066                 }
7067               else
7068                 {
7069                   CLRC;
7070                   emitLabel (tlbl);
7071                 }
7072             }
7073         }
7074       // bit = c
7075       // val = c
7076       if (size)
7077         outBitC (result);
7078       // if(bit | ...)
7079       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7080         genIfxJump (ifx, "c", left, right, result);
7081       goto release;
7082     }
7083
7084   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7085   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7086   if ((AOP_TYPE (right) == AOP_LIT) &&
7087       (AOP_TYPE (result) == AOP_CRY) &&
7088       (AOP_TYPE (left) != AOP_CRY))
7089     {
7090       if (lit)
7091         {
7092           // result = 1
7093           if (size)
7094             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7095           else
7096             continueIfTrue (ifx);
7097           goto release;
7098         }
7099       else
7100         {
7101           // lit = 0, result = boolean(left)
7102           if (size)
7103             emitcode ("setb", "c");
7104           toBoolean (right);
7105           if (size)
7106             {
7107               symbol *tlbl = newiTempLabel (NULL);
7108               emitcode ("jnz", "%05d$", tlbl->key + 100);
7109               CLRC;
7110               emitLabel (tlbl);
7111             }
7112           else
7113             {
7114               genIfxJump (ifx, "a", left, right, result);
7115               goto release;
7116             }
7117         }
7118       outBitC (result);
7119       goto release;
7120     }
7121
7122   /* if left is same as result */
7123   if (sameRegs (AOP (result), AOP (left)))
7124     {
7125       for (; size--; offset++)
7126         {
7127           if (AOP_TYPE (right) == AOP_LIT)
7128             {
7129               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7130               if (bytelit == 0)
7131                 {
7132                   /* dummy read of volatile operand */
7133                   if (isOperandVolatile (left, FALSE))
7134                     MOVA (aopGet (left, offset, FALSE, FALSE));
7135                   else
7136                     continue;
7137                 }
7138               else if (bytelit == 0x0FF)
7139                 {
7140                   aopPut (result, "#0xFF", offset);
7141                 }
7142               else if (IS_AOP_PREG (left))
7143                 {
7144                   MOVA (aopGet (left, offset, FALSE, TRUE));
7145                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7146                   aopPut (result, "a", offset);
7147                 }
7148               else
7149                 {
7150                   emitcode ("orl", "%s,%s",
7151                             aopGet (left, offset, FALSE, TRUE),
7152                             aopGet (right, offset, FALSE, FALSE));
7153                 }
7154             }
7155           else
7156             {
7157               if (AOP_TYPE (left) == AOP_ACC)
7158                 {
7159                   if (offset)
7160                     emitcode("mov", "a,b");
7161                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7162                 }
7163               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7164                 {
7165                   MOVB (aopGet (left, offset, FALSE, FALSE));
7166                   MOVA (aopGet (right, offset, FALSE, FALSE));
7167                   emitcode ("orl", "a,b");
7168                   aopPut (result, "a", offset);
7169                 }
7170               else if (aopGetUsesAcc (left, offset))
7171                 {
7172                   MOVA (aopGet (left, offset, FALSE, FALSE));
7173                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7174                   aopPut (result, "a", offset);
7175                 }
7176               else
7177                 {
7178                   MOVA (aopGet (right, offset, FALSE, FALSE));
7179                   if (IS_AOP_PREG (left))
7180                     {
7181                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7182                       aopPut (result, "a", offset);
7183                     }
7184                   else
7185                     {
7186                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7187                     }
7188                 }
7189             }
7190         }
7191     }
7192   else
7193     {
7194       // left & result in different registers
7195       if (AOP_TYPE (result) == AOP_CRY)
7196         {
7197           // result = bit
7198           // if(size), result in bit
7199           // if(!size && ifx), conditional oper: if(left | right)
7200           symbol *tlbl = newiTempLabel (NULL);
7201           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7202           if (size)
7203             emitcode ("setb", "c");
7204           while (sizer--)
7205             {
7206               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7207                   && AOP_TYPE(left)==AOP_ACC)
7208                 {
7209                   if (offset)
7210                     emitcode("mov", "a,b");
7211                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7212                 }
7213               else if (AOP_TYPE(left)==AOP_ACC)
7214                 {
7215                   if (!offset)
7216                     {
7217                       bool pushedB = pushB ();
7218                       emitcode("mov", "b,a");
7219                       MOVA (aopGet (right, offset, FALSE, FALSE));
7220                       emitcode("orl", "a,b");
7221                       popB (pushedB);
7222                     }
7223                   else
7224                     {
7225                       MOVA (aopGet (right, offset, FALSE, FALSE));
7226                       emitcode("orl", "a,b");
7227                     }
7228                 }
7229               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7230                 {
7231                   MOVB (aopGet (left, offset, FALSE, FALSE));
7232                   MOVA (aopGet (right, offset, FALSE, FALSE));
7233                   emitcode ("orl", "a,b");
7234                 }
7235               else if (aopGetUsesAcc (left, offset))
7236                 {
7237                   MOVA (aopGet (left, offset, FALSE, FALSE));
7238                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7239                 }
7240               else
7241                 {
7242                   MOVA (aopGet (right, offset, FALSE, FALSE));
7243                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7244               }
7245
7246               emitcode ("jnz", "%05d$", tlbl->key + 100);
7247               offset++;
7248             }
7249           if (size)
7250             {
7251               CLRC;
7252               emitLabel (tlbl);
7253               outBitC (result);
7254             }
7255           else if (ifx)
7256             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7257           else
7258             emitLabel (tlbl);
7259         }
7260       else
7261         {
7262           for (; (size--); offset++)
7263             {
7264               // normal case
7265               // result = left | right
7266               if (AOP_TYPE (right) == AOP_LIT)
7267                 {
7268                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7269                   if (bytelit == 0)
7270                     {
7271                       aopPut (result,
7272                               aopGet (left, offset, FALSE, FALSE),
7273                               offset);
7274                       continue;
7275                     }
7276                   else if (bytelit == 0x0FF)
7277                     {
7278                       /* dummy read of volatile operand */
7279                       if (isOperandVolatile (left, FALSE))
7280                         MOVA (aopGet (left, offset, FALSE, FALSE));
7281                       aopPut (result, "#0xFF", offset);
7282                       continue;
7283                     }
7284                 }
7285               // faster than result <- left, orl result,right
7286               // and better if result is SFR
7287               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7288                   && AOP_TYPE(left)==AOP_ACC)
7289                 {
7290                   if (offset)
7291                     emitcode("mov", "a,b");
7292                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7293                 }
7294               else if (AOP_TYPE(left)==AOP_ACC)
7295                 {
7296                   if (!offset)
7297                     {
7298                       bool pushedB = pushB ();
7299                       emitcode("mov", "b,a");
7300                       MOVA (aopGet (right, offset, FALSE, FALSE));
7301                       emitcode("orl", "a,b");
7302                       popB (pushedB);
7303                     }
7304                   else
7305                     {
7306                       MOVA (aopGet (right, offset, FALSE, FALSE));
7307                       emitcode("orl", "a,b");
7308                     }
7309                 }
7310               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7311                 {
7312                   MOVB (aopGet (left, offset, FALSE, FALSE));
7313                   MOVA (aopGet (right, offset, FALSE, FALSE));
7314                   emitcode ("orl", "a,b");
7315                 }
7316               else if (aopGetUsesAcc (left, offset))
7317                 {
7318                   MOVA (aopGet (left, offset, FALSE, FALSE));
7319                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7320                 }
7321               else
7322                 {
7323                   MOVA (aopGet (right, offset, FALSE, FALSE));
7324                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7325                 }
7326               aopPut (result, "a", offset);
7327             }
7328         }
7329     }
7330
7331 release:
7332   freeAsmop (result, NULL, ic, TRUE);
7333   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7334   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7335 }
7336
7337 /*-----------------------------------------------------------------*/
7338 /* genXor - code for xclusive or                                   */
7339 /*-----------------------------------------------------------------*/
7340 static void
7341 genXor (iCode * ic, iCode * ifx)
7342 {
7343   operand *left, *right, *result;
7344   int size, offset = 0;
7345   unsigned long lit = 0L;
7346   int bytelit = 0;
7347
7348   D (emitcode (";", "genXor"));
7349
7350   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7351   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7352   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7353
7354 #ifdef DEBUG_TYPE
7355   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7356             AOP_TYPE (result),
7357             AOP_TYPE (left), AOP_TYPE (right));
7358   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7359             AOP_SIZE (result),
7360             AOP_SIZE (left), AOP_SIZE (right));
7361 #endif
7362
7363   /* if left is a literal & right is not ||
7364      if left needs acc & right does not */
7365   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7366       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7367     {
7368       operand *tmp = right;
7369       right = left;
7370       left = tmp;
7371     }
7372
7373   /* if result = right then exchange them */
7374   if (sameRegs (AOP (result), AOP (right)))
7375     {
7376       operand *tmp = right;
7377       right = left;
7378       left = tmp;
7379     }
7380
7381   /* if right is bit then exchange them */
7382   if (AOP_TYPE (right) == AOP_CRY &&
7383       AOP_TYPE (left) != AOP_CRY)
7384     {
7385       operand *tmp = right;
7386       right = left;
7387       left = tmp;
7388     }
7389   if (AOP_TYPE (right) == AOP_LIT)
7390     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7391
7392   size = AOP_SIZE (result);
7393
7394   // if(bit ^ yy)
7395   // xx = bit ^ yy;
7396   if (AOP_TYPE (left) == AOP_CRY)
7397     {
7398       if (AOP_TYPE (right) == AOP_LIT)
7399         {
7400           // c = bit & literal;
7401           if (lit >> 1)
7402             {
7403               // lit>>1  != 0 => result = 1
7404               if (AOP_TYPE (result) == AOP_CRY)
7405                 {
7406                   if (size)
7407                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7408                   else if (ifx)
7409                     continueIfTrue (ifx);
7410                   goto release;
7411                 }
7412               emitcode ("setb", "c");
7413             }
7414           else
7415             {
7416               // lit == (0 or 1)
7417               if (lit == 0)
7418                 {
7419                   // lit == 0, result = left
7420                   if (size && sameRegs (AOP (result), AOP (left)))
7421                     goto release;
7422                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7423                 }
7424               else
7425                 {
7426                   // lit == 1, result = not(left)
7427                   if (size && sameRegs (AOP (result), AOP (left)))
7428                     {
7429                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7430                       goto release;
7431                     }
7432                   else
7433                     {
7434                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7435                       emitcode ("cpl", "c");
7436                     }
7437                 }
7438             }
7439         }
7440       else
7441         {
7442           // right != literal
7443           symbol *tlbl = newiTempLabel (NULL);
7444           if (AOP_TYPE (right) == AOP_CRY)
7445             {
7446               // c = bit ^ bit;
7447               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7448             }
7449           else
7450             {
7451               int sizer = AOP_SIZE (right);
7452               // c = bit ^ val
7453               // if val>>1 != 0, result = 1
7454               emitcode ("setb", "c");
7455               while (sizer)
7456                 {
7457                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7458                   if (sizer == 1)
7459                     // test the msb of the lsb
7460                     emitcode ("anl", "a,#0xfe");
7461                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7462                   sizer--;
7463                 }
7464               // val = (0,1)
7465               emitcode ("rrc", "a");
7466             }
7467           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7468           emitcode ("cpl", "c");
7469           emitLabel (tlbl);
7470         }
7471       // bit = c
7472       // val = c
7473       if (size)
7474         outBitC (result);
7475       // if(bit | ...)
7476       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7477         genIfxJump (ifx, "c", left, right, result);
7478       goto release;
7479     }
7480
7481   /* if left is same as result */
7482   if (sameRegs (AOP (result), AOP (left)))
7483     {
7484       for (; size--; offset++)
7485         {
7486           if (AOP_TYPE (right) == AOP_LIT)
7487             {
7488               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7489               if (bytelit == 0)
7490                 {
7491                   /* dummy read of volatile operand */
7492                   if (isOperandVolatile (left, FALSE))
7493                     MOVA (aopGet (left, offset, FALSE, FALSE));
7494                   else
7495                     continue;
7496                 }
7497               else if (IS_AOP_PREG (left))
7498                 {
7499                   MOVA (aopGet (left, offset, FALSE, TRUE));
7500                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7501                   aopPut (result, "a", offset);
7502                 }
7503               else
7504                 {
7505                   emitcode ("xrl", "%s,%s",
7506                             aopGet (left, offset, FALSE, TRUE),
7507                             aopGet (right, offset, FALSE, FALSE));
7508                 }
7509             }
7510           else
7511             {
7512               if (AOP_TYPE (left) == AOP_ACC)
7513                 {
7514                   if (offset)
7515                     emitcode("mov", "a,b");
7516                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7517                 }
7518               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7519                 {
7520                   MOVB (aopGet (left, offset, FALSE, FALSE));
7521                   MOVA (aopGet (right, offset, FALSE, FALSE));
7522                   emitcode ("xrl", "a,b");
7523                   aopPut (result, "a", offset);
7524                 }
7525               else if (aopGetUsesAcc (left, offset))
7526                 {
7527                   MOVA (aopGet (left, offset, FALSE, FALSE));
7528                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7529                   aopPut (result, "a", offset);
7530                 }
7531               else
7532                 {
7533                   MOVA (aopGet (right, offset, FALSE, FALSE));
7534                   if (IS_AOP_PREG (left))
7535                     {
7536                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7537                       aopPut (result, "a", offset);
7538                     }
7539                   else
7540                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7541                 }
7542             }
7543         }
7544     }
7545   else
7546     {
7547       // left & result in different registers
7548       if (AOP_TYPE (result) == AOP_CRY)
7549         {
7550           // result = bit
7551           // if(size), result in bit
7552           // if(!size && ifx), conditional oper: if(left ^ right)
7553           symbol *tlbl = newiTempLabel (NULL);
7554           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7555
7556           if (size)
7557             emitcode ("setb", "c");
7558           while (sizer--)
7559             {
7560               if ((AOP_TYPE (right) == AOP_LIT) &&
7561                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7562                 {
7563                   MOVA (aopGet (left, offset, FALSE, FALSE));
7564                 }
7565               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7566                   && AOP_TYPE(left)==AOP_ACC)
7567                 {
7568                   if (offset)
7569                     emitcode("mov", "a,b");
7570                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7571                 }
7572               else if (AOP_TYPE(left)==AOP_ACC)
7573                 {
7574                   if (!offset)
7575                     {
7576                       bool pushedB = pushB ();
7577                       emitcode("mov", "b,a");
7578                       MOVA (aopGet (right, offset, FALSE, FALSE));
7579                       emitcode("xrl", "a,b");
7580                       popB (pushedB);
7581                     }
7582                   else
7583                     {
7584                       MOVA (aopGet (right, offset, FALSE, FALSE));
7585                       emitcode("xrl", "a,b");
7586                     }
7587                 }
7588               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7589                 {
7590                   MOVB (aopGet (left, offset, FALSE, FALSE));
7591                   MOVA (aopGet (right, offset, FALSE, FALSE));
7592                   emitcode ("xrl", "a,b");
7593                 }
7594               else if (aopGetUsesAcc (left, offset))
7595                 {
7596                   MOVA (aopGet (left, offset, FALSE, FALSE));
7597                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7598                 }
7599               else
7600                 {
7601                   MOVA (aopGet (right, offset, FALSE, FALSE));
7602                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7603                 }
7604
7605               emitcode ("jnz", "%05d$", tlbl->key + 100);
7606               offset++;
7607             }
7608           if (size)
7609             {
7610               CLRC;
7611               emitLabel (tlbl);
7612               outBitC (result);
7613             }
7614           else if (ifx)
7615             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7616         }
7617       else
7618         {
7619           for (; (size--); offset++)
7620             {
7621               // normal case
7622               // result = left ^ right
7623               if (AOP_TYPE (right) == AOP_LIT)
7624                 {
7625                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7626                   if (bytelit == 0)
7627                     {
7628                       aopPut (result,
7629                               aopGet (left, offset, FALSE, FALSE),
7630                               offset);
7631                       continue;
7632                     }
7633                 }
7634               // faster than result <- left, xrl result,right
7635               // and better if result is SFR
7636               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7637                   && AOP_TYPE(left)==AOP_ACC)
7638                 {
7639                   if (offset)
7640                     emitcode("mov", "a,b");
7641                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7642                 }
7643               else if (AOP_TYPE(left)==AOP_ACC)
7644                 {
7645                   if (!offset)
7646                     {
7647                       bool pushedB = pushB ();
7648                       emitcode("mov", "b,a");
7649                       MOVA (aopGet (right, offset, FALSE, FALSE));
7650                       emitcode("xrl", "a,b");
7651                       popB (pushedB);
7652                     }
7653                   else
7654                     {
7655                       MOVA (aopGet (right, offset, FALSE, FALSE));
7656                       emitcode("xrl", "a,b");
7657                     }
7658                 }
7659               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7660                 {
7661                   MOVB (aopGet (left, offset, FALSE, FALSE));
7662                   MOVA (aopGet (right, offset, FALSE, FALSE));
7663                   emitcode ("xrl", "a,b");
7664                 }
7665               else if (aopGetUsesAcc (left, offset))
7666                 {
7667                   MOVA (aopGet (left, offset, FALSE, FALSE));
7668                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7669                 }
7670               else
7671                 {
7672                   MOVA (aopGet (right, offset, FALSE, FALSE));
7673                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7674                 }
7675               aopPut (result, "a", offset);
7676             }
7677         }
7678     }
7679
7680 release:
7681   freeAsmop (result, NULL, ic, TRUE);
7682   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7683   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7684 }
7685
7686 /*-----------------------------------------------------------------*/
7687 /* genInline - write the inline code out                           */
7688 /*-----------------------------------------------------------------*/
7689 static void
7690 genInline (iCode * ic)
7691 {
7692   char *buffer, *bp, *bp1;
7693
7694   D (emitcode (";", "genInline"));
7695
7696   _G.inLine += (!options.asmpeep);
7697
7698   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7699
7700   /* emit each line as a code */
7701   while (*bp)
7702     {
7703       if (*bp == '\n')
7704         {
7705           *bp++ = '\0';
7706           emitcode (bp1, "");
7707           bp1 = bp;
7708         }
7709       else
7710         {
7711           /* Add \n for labels, not dirs such as c:\mydir */
7712           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7713             {
7714               bp++;
7715               *bp = '\0';
7716               bp++;
7717               emitcode (bp1, "");
7718               bp1 = bp;
7719             }
7720           else
7721             bp++;
7722         }
7723     }
7724   if (bp1 != bp)
7725     emitcode (bp1, "");
7726   /*     emitcode("",buffer); */
7727   _G.inLine -= (!options.asmpeep);
7728 }
7729
7730 /*-----------------------------------------------------------------*/
7731 /* genRRC - rotate right with carry                                */
7732 /*-----------------------------------------------------------------*/
7733 static void
7734 genRRC (iCode * ic)
7735 {
7736   operand *left, *result;
7737   int size, offset;
7738   char *l;
7739
7740   D (emitcode (";", "genRRC"));
7741
7742   /* rotate right with carry */
7743   left = IC_LEFT (ic);
7744   result = IC_RESULT (ic);
7745   aopOp (left, ic, FALSE);
7746   aopOp (result, ic, FALSE);
7747
7748   /* move it to the result */
7749   size = AOP_SIZE (result);
7750   offset = size - 1;
7751   if (size == 1) { /* special case for 1 byte */
7752       l = aopGet (left, offset, FALSE, FALSE);
7753       MOVA (l);
7754       emitcode ("rr", "a");
7755       goto release;
7756   }
7757   /* no need to clear carry, bit7 will be written later */
7758   while (size--)
7759     {
7760       l = aopGet (left, offset, FALSE, FALSE);
7761       MOVA (l);
7762       emitcode ("rrc", "a");
7763       if (AOP_SIZE (result) > 1)
7764         aopPut (result, "a", offset--);
7765     }
7766   /* now we need to put the carry into the
7767      highest order byte of the result */
7768   if (AOP_SIZE (result) > 1)
7769     {
7770       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7771       MOVA (l);
7772     }
7773   emitcode ("mov", "acc.7,c");
7774  release:
7775   aopPut (result, "a", AOP_SIZE (result) - 1);
7776   freeAsmop (result, NULL, ic, TRUE);
7777   freeAsmop (left, NULL, ic, TRUE);
7778 }
7779
7780 /*-----------------------------------------------------------------*/
7781 /* genRLC - generate code for rotate left with carry               */
7782 /*-----------------------------------------------------------------*/
7783 static void
7784 genRLC (iCode * ic)
7785 {
7786   operand *left, *result;
7787   int size, offset;
7788   char *l;
7789
7790   D (emitcode (";", "genRLC"));
7791
7792   /* rotate right with carry */
7793   left = IC_LEFT (ic);
7794   result = IC_RESULT (ic);
7795   aopOp (left, ic, FALSE);
7796   aopOp (result, ic, FALSE);
7797
7798   /* move it to the result */
7799   size = AOP_SIZE (result);
7800   offset = 0;
7801   if (size--)
7802     {
7803       l = aopGet (left, offset, FALSE, FALSE);
7804       MOVA (l);
7805       if (size == 0) { /* special case for 1 byte */
7806               emitcode("rl","a");
7807               goto release;
7808       }
7809       emitcode("rlc","a"); /* bit0 will be written later */
7810       if (AOP_SIZE (result) > 1)
7811         {
7812           aopPut (result, "a", offset++);
7813         }
7814
7815       while (size--)
7816         {
7817           l = aopGet (left, offset, FALSE, FALSE);
7818           MOVA (l);
7819           emitcode ("rlc", "a");
7820           if (AOP_SIZE (result) > 1)
7821             aopPut (result, "a", offset++);
7822         }
7823     }
7824   /* now we need to put the carry into the
7825      highest order byte of the result */
7826   if (AOP_SIZE (result) > 1)
7827     {
7828       l = aopGet (result, 0, FALSE, FALSE);
7829       MOVA (l);
7830     }
7831   emitcode ("mov", "acc.0,c");
7832  release:
7833   aopPut (result, "a", 0);
7834   freeAsmop (result, NULL, ic, TRUE);
7835   freeAsmop (left, NULL, ic, TRUE);
7836 }
7837
7838 /*-----------------------------------------------------------------*/
7839 /* genGetHbit - generates code get highest order bit               */
7840 /*-----------------------------------------------------------------*/
7841 static void
7842 genGetHbit (iCode * ic)
7843 {
7844   operand *left, *result;
7845
7846   D (emitcode (";", "genGetHbit"));
7847
7848   left = IC_LEFT (ic);
7849   result = IC_RESULT (ic);
7850   aopOp (left, ic, FALSE);
7851   aopOp (result, ic, FALSE);
7852
7853   /* get the highest order byte into a */
7854   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7855   if (AOP_TYPE (result) == AOP_CRY)
7856     {
7857       emitcode ("rlc", "a");
7858       outBitC (result);
7859     }
7860   else
7861     {
7862       emitcode ("rl", "a");
7863       emitcode ("anl", "a,#0x01");
7864       outAcc (result);
7865     }
7866
7867   freeAsmop (result, NULL, ic, TRUE);
7868   freeAsmop (left, NULL, ic, TRUE);
7869 }
7870
7871 /*-----------------------------------------------------------------*/
7872 /* genGetAbit - generates code get a single bit                    */
7873 /*-----------------------------------------------------------------*/
7874 static void
7875 genGetAbit (iCode * ic)
7876 {
7877   operand *left, *right, *result;
7878   int shCount;
7879
7880   D (emitcode (";", "genGetAbit"));
7881
7882   left = IC_LEFT (ic);
7883   right = IC_RIGHT (ic);
7884   result = IC_RESULT (ic);
7885   aopOp (left, ic, FALSE);
7886   aopOp (right, ic, FALSE);
7887   aopOp (result, ic, FALSE);
7888
7889   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7890
7891   /* get the needed byte into a */
7892   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7893   shCount %= 8;
7894   if (AOP_TYPE (result) == AOP_CRY)
7895     {
7896       if ((shCount) == 7)
7897           emitcode ("rlc", "a");
7898       else if ((shCount) == 0)
7899           emitcode ("rrc", "a");
7900       else
7901           emitcode ("mov", "c,acc[%d]", shCount);
7902       outBitC (result);
7903     }
7904   else
7905     {
7906       switch (shCount)
7907         {
7908         case 2:
7909           emitcode ("rr", "a");
7910           //fallthrough
7911         case 1:
7912           emitcode ("rr", "a");
7913           //fallthrough
7914         case 0:
7915           emitcode ("anl", "a,#0x01");
7916           break;
7917         case 3:
7918         case 5:
7919           emitcode ("mov", "c,acc[%d]", shCount);
7920           emitcode ("clr", "a");
7921           emitcode ("rlc", "a");
7922           break;
7923         case 4:
7924           emitcode ("swap", "a");
7925           emitcode ("anl", "a,#0x01");
7926           break;
7927         case 6:
7928           emitcode ("rl", "a");
7929           //fallthrough
7930         case 7:
7931           emitcode ("rl", "a");
7932           emitcode ("anl", "a,#0x01");
7933           break;
7934         }
7935       outAcc (result);
7936     }
7937
7938   freeAsmop (result, NULL, ic, TRUE);
7939   freeAsmop (right, NULL, ic, TRUE);
7940   freeAsmop (left, NULL, ic, TRUE);
7941 }
7942
7943 /*-----------------------------------------------------------------*/
7944 /* genGetByte - generates code get a single byte                   */
7945 /*-----------------------------------------------------------------*/
7946 static void
7947 genGetByte (iCode * ic)
7948 {
7949   operand *left, *right, *result;
7950   int offset;
7951
7952   D (emitcode (";", "genGetByte"));
7953
7954   left = IC_LEFT (ic);
7955   right = IC_RIGHT (ic);
7956   result = IC_RESULT (ic);
7957   aopOp (left, ic, FALSE);
7958   aopOp (right, ic, FALSE);
7959   aopOp (result, ic, FALSE);
7960
7961   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7962   aopPut (result,
7963           aopGet (left, offset, FALSE, FALSE),
7964           0);
7965
7966   freeAsmop (result, NULL, ic, TRUE);
7967   freeAsmop (right, NULL, ic, TRUE);
7968   freeAsmop (left, NULL, ic, TRUE);
7969 }
7970
7971 /*-----------------------------------------------------------------*/
7972 /* genGetWord - generates code get two bytes                       */
7973 /*-----------------------------------------------------------------*/
7974 static void
7975 genGetWord (iCode * ic)
7976 {
7977   operand *left, *right, *result;
7978   int offset;
7979
7980   D (emitcode (";", "genGetWord"));
7981
7982   left = IC_LEFT (ic);
7983   right = IC_RIGHT (ic);
7984   result = IC_RESULT (ic);
7985   aopOp (left, ic, FALSE);
7986   aopOp (right, ic, FALSE);
7987   aopOp (result, ic, FALSE);
7988
7989   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7990   aopPut (result,
7991           aopGet (left, offset, FALSE, FALSE),
7992           0);
7993   aopPut (result,
7994           aopGet (left, offset+1, FALSE, FALSE),
7995           1);
7996
7997   freeAsmop (result, NULL, ic, TRUE);
7998   freeAsmop (right, NULL, ic, TRUE);
7999   freeAsmop (left, NULL, ic, TRUE);
8000 }
8001
8002 /*-----------------------------------------------------------------*/
8003 /* genSwap - generates code to swap nibbles or bytes               */
8004 /*-----------------------------------------------------------------*/
8005 static void
8006 genSwap (iCode * ic)
8007 {
8008   operand *left, *result;
8009
8010   D(emitcode (";     genSwap",""));
8011
8012   left = IC_LEFT (ic);
8013   result = IC_RESULT (ic);
8014   aopOp (left, ic, FALSE);
8015   aopOp (result, ic, FALSE);
8016
8017   switch (AOP_SIZE (left))
8018     {
8019     case 1: /* swap nibbles in byte */
8020       MOVA (aopGet (left, 0, FALSE, FALSE));
8021       emitcode ("swap", "a");
8022       aopPut (result, "a", 0);
8023       break;
8024     case 2: /* swap bytes in word */
8025       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8026         {
8027           MOVA (aopGet (left, 0, FALSE, FALSE));
8028           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8029           aopPut (result, "a", 1);
8030         }
8031       else if (operandsEqu (left, result))
8032         {
8033           char * reg = "a";
8034           bool pushedB = FALSE, leftInB = FALSE;
8035
8036           MOVA (aopGet (left, 0, FALSE, FALSE));
8037           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8038             {
8039               pushedB = pushB ();
8040               emitcode ("mov", "b,a");
8041               reg = "b";
8042               leftInB = TRUE;
8043             }
8044           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8045           aopPut (result, reg, 1);
8046
8047           if (leftInB)
8048             popB (pushedB);
8049         }
8050       else
8051         {
8052           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8053           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8054         }
8055       break;
8056     default:
8057       wassertl(FALSE, "unsupported SWAP operand size");
8058     }
8059
8060   freeAsmop (result, NULL, ic, TRUE);
8061   freeAsmop (left, NULL, ic, TRUE);
8062 }
8063
8064 /*-----------------------------------------------------------------*/
8065 /* AccRol - rotate left accumulator by known count                 */
8066 /*-----------------------------------------------------------------*/
8067 static void
8068 AccRol (int shCount)
8069 {
8070   shCount &= 0x0007;            // shCount : 0..7
8071
8072   switch (shCount)
8073     {
8074     case 0:
8075       break;
8076     case 1:
8077       emitcode ("rl", "a");
8078       break;
8079     case 2:
8080       emitcode ("rl", "a");
8081       emitcode ("rl", "a");
8082       break;
8083     case 3:
8084       emitcode ("swap", "a");
8085       emitcode ("rr", "a");
8086       break;
8087     case 4:
8088       emitcode ("swap", "a");
8089       break;
8090     case 5:
8091       emitcode ("swap", "a");
8092       emitcode ("rl", "a");
8093       break;
8094     case 6:
8095       emitcode ("rr", "a");
8096       emitcode ("rr", "a");
8097       break;
8098     case 7:
8099       emitcode ("rr", "a");
8100       break;
8101     }
8102 }
8103
8104 /*-----------------------------------------------------------------*/
8105 /* AccLsh - left shift accumulator by known count                  */
8106 /*-----------------------------------------------------------------*/
8107 static void
8108 AccLsh (int shCount)
8109 {
8110   if (shCount != 0)
8111     {
8112       if (shCount == 1)
8113         emitcode ("add", "a,acc");
8114       else if (shCount == 2)
8115         {
8116           emitcode ("add", "a,acc");
8117           emitcode ("add", "a,acc");
8118         }
8119       else
8120         {
8121           /* rotate left accumulator */
8122           AccRol (shCount);
8123           /* and kill the lower order bits */
8124           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8125         }
8126     }
8127 }
8128
8129 /*-----------------------------------------------------------------*/
8130 /* AccRsh - right shift accumulator by known count                 */
8131 /*-----------------------------------------------------------------*/
8132 static void
8133 AccRsh (int shCount)
8134 {
8135   if (shCount != 0)
8136     {
8137       if (shCount == 1)
8138         {
8139           CLRC;
8140           emitcode ("rrc", "a");
8141         }
8142       else
8143         {
8144           /* rotate right accumulator */
8145           AccRol (8 - shCount);
8146           /* and kill the higher order bits */
8147           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8148         }
8149     }
8150 }
8151
8152 /*-----------------------------------------------------------------*/
8153 /* AccSRsh - signed right shift accumulator by known count                 */
8154 /*-----------------------------------------------------------------*/
8155 static void
8156 AccSRsh (int shCount)
8157 {
8158   symbol *tlbl;
8159   if (shCount != 0)
8160     {
8161       if (shCount == 1)
8162         {
8163           emitcode ("mov", "c,acc.7");
8164           emitcode ("rrc", "a");
8165         }
8166       else if (shCount == 2)
8167         {
8168           emitcode ("mov", "c,acc.7");
8169           emitcode ("rrc", "a");
8170           emitcode ("mov", "c,acc.7");
8171           emitcode ("rrc", "a");
8172         }
8173       else
8174         {
8175           tlbl = newiTempLabel (NULL);
8176           /* rotate right accumulator */
8177           AccRol (8 - shCount);
8178           /* and kill the higher order bits */
8179           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8180           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8181           emitcode ("orl", "a,#0x%02x",
8182                     (unsigned char) ~SRMask[shCount]);
8183           emitLabel (tlbl);
8184         }
8185     }
8186 }
8187
8188 /*-----------------------------------------------------------------*/
8189 /* shiftR1Left2Result - shift right one byte from left to result   */
8190 /*-----------------------------------------------------------------*/
8191 static void
8192 shiftR1Left2Result (operand * left, int offl,
8193                     operand * result, int offr,
8194                     int shCount, int sign)
8195 {
8196   MOVA (aopGet (left, offl, FALSE, FALSE));
8197   /* shift right accumulator */
8198   if (sign)
8199     AccSRsh (shCount);
8200   else
8201     AccRsh (shCount);
8202   aopPut (result, "a", offr);
8203 }
8204
8205 /*-----------------------------------------------------------------*/
8206 /* shiftL1Left2Result - shift left one byte from left to result    */
8207 /*-----------------------------------------------------------------*/
8208 static void
8209 shiftL1Left2Result (operand * left, int offl,
8210                     operand * result, int offr, int shCount)
8211 {
8212   char *l;
8213   l = aopGet (left, offl, FALSE, FALSE);
8214   MOVA (l);
8215   /* shift left accumulator */
8216   AccLsh (shCount);
8217   aopPut (result, "a", offr);
8218 }
8219
8220 /*-----------------------------------------------------------------*/
8221 /* movLeft2Result - move byte from left to result                  */
8222 /*-----------------------------------------------------------------*/
8223 static void
8224 movLeft2Result (operand * left, int offl,
8225                 operand * result, int offr, int sign)
8226 {
8227   char *l;
8228   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8229     {
8230       l = aopGet (left, offl, FALSE, FALSE);
8231
8232       if (*l == '@' && (IS_AOP_PREG (result)))
8233         {
8234           emitcode ("mov", "a,%s", l);
8235           aopPut (result, "a", offr);
8236         }
8237       else
8238         {
8239           if (!sign)
8240             {
8241               aopPut (result, l, offr);
8242             }
8243           else
8244             {
8245               /* MSB sign in acc.7 ! */
8246               if (getDataSize (left) == offl + 1)
8247                 {
8248                   MOVA (l);
8249                   aopPut (result, "a", offr);
8250                 }
8251             }
8252         }
8253     }
8254 }
8255
8256 /*-----------------------------------------------------------------*/
8257 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8258 /*-----------------------------------------------------------------*/
8259 static void
8260 AccAXRrl1 (char *x)
8261 {
8262   emitcode ("rrc", "a");
8263   emitcode ("xch", "a,%s", x);
8264   emitcode ("rrc", "a");
8265   emitcode ("xch", "a,%s", x);
8266 }
8267
8268 /*-----------------------------------------------------------------*/
8269 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8270 /*-----------------------------------------------------------------*/
8271 static void
8272 AccAXLrl1 (char *x)
8273 {
8274   emitcode ("xch", "a,%s", x);
8275   emitcode ("rlc", "a");
8276   emitcode ("xch", "a,%s", x);
8277   emitcode ("rlc", "a");
8278 }
8279
8280 /*-----------------------------------------------------------------*/
8281 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8282 /*-----------------------------------------------------------------*/
8283 static void
8284 AccAXLsh1 (char *x)
8285 {
8286   emitcode ("xch", "a,%s", x);
8287   emitcode ("add", "a,acc");
8288   emitcode ("xch", "a,%s", x);
8289   emitcode ("rlc", "a");
8290 }
8291
8292 /*-----------------------------------------------------------------*/
8293 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8294 /*-----------------------------------------------------------------*/
8295 static void
8296 AccAXLsh (char *x, int shCount)
8297 {
8298   switch (shCount)
8299     {
8300     case 0:
8301       break;
8302     case 1:
8303       AccAXLsh1 (x);
8304       break;
8305     case 2:
8306       AccAXLsh1 (x);
8307       AccAXLsh1 (x);
8308       break;
8309     case 3:
8310     case 4:
8311     case 5:                     // AAAAABBB:CCCCCDDD
8312
8313       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8314
8315       emitcode ("anl", "a,#0x%02x",
8316                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8317
8318       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8319
8320       AccRol (shCount);         // DDDCCCCC:BBB00000
8321
8322       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8323
8324       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8325
8326       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8327
8328       emitcode ("anl", "a,#0x%02x",
8329                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8330
8331       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8332
8333       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8334
8335       break;
8336     case 6:                     // AAAAAABB:CCCCCCDD
8337       emitcode ("anl", "a,#0x%02x",
8338                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8339       emitcode ("mov", "c,acc.0");      // c = B
8340       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8341 #if 0 // REMOVE ME
8342       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8343       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8344 #else
8345       emitcode("rrc","a");
8346       emitcode("xch","a,%s", x);
8347       emitcode("rrc","a");
8348       emitcode("mov","c,acc.0"); //<< get correct bit
8349       emitcode("xch","a,%s", x);
8350
8351       emitcode("rrc","a");
8352       emitcode("xch","a,%s", x);
8353       emitcode("rrc","a");
8354       emitcode("xch","a,%s", x);
8355 #endif
8356       break;
8357     case 7:                     // a:x <<= 7
8358
8359       emitcode ("anl", "a,#0x%02x",
8360                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8361
8362       emitcode ("mov", "c,acc.0");      // c = B
8363
8364       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8365
8366       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8367
8368       break;
8369     default:
8370       break;
8371     }
8372 }
8373
8374 /*-----------------------------------------------------------------*/
8375 /* AccAXRsh - right shift a:x known count (0..7)                   */
8376 /*-----------------------------------------------------------------*/
8377 static void
8378 AccAXRsh (char *x, int shCount)
8379 {
8380   switch (shCount)
8381     {
8382     case 0:
8383       break;
8384     case 1:
8385       CLRC;
8386       AccAXRrl1 (x);            // 0->a:x
8387
8388       break;
8389     case 2:
8390       CLRC;
8391       AccAXRrl1 (x);            // 0->a:x
8392
8393       CLRC;
8394       AccAXRrl1 (x);            // 0->a:x
8395
8396       break;
8397     case 3:
8398     case 4:
8399     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8400
8401       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8402
8403       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8404
8405       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8406
8407       emitcode ("anl", "a,#0x%02x",
8408                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8409
8410       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8411
8412       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8413
8414       emitcode ("anl", "a,#0x%02x",
8415                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8416
8417       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8418
8419       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8420
8421       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8422
8423       break;
8424     case 6:                     // AABBBBBB:CCDDDDDD
8425
8426       emitcode ("mov", "c,acc.7");
8427       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8428
8429       emitcode ("mov", "c,acc.7");
8430       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8431
8432       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8433
8434       emitcode ("anl", "a,#0x%02x",
8435                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8436
8437       break;
8438     case 7:                     // ABBBBBBB:CDDDDDDD
8439
8440       emitcode ("mov", "c,acc.7");      // c = A
8441
8442       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8443
8444       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8445
8446       emitcode ("anl", "a,#0x%02x",
8447                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8448
8449       break;
8450     default:
8451       break;
8452     }
8453 }
8454
8455 /*-----------------------------------------------------------------*/
8456 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8457 /*-----------------------------------------------------------------*/
8458 static void
8459 AccAXRshS (char *x, int shCount)
8460 {
8461   symbol *tlbl;
8462   switch (shCount)
8463     {
8464     case 0:
8465       break;
8466     case 1:
8467       emitcode ("mov", "c,acc.7");
8468       AccAXRrl1 (x);            // s->a:x
8469
8470       break;
8471     case 2:
8472       emitcode ("mov", "c,acc.7");
8473       AccAXRrl1 (x);            // s->a:x
8474
8475       emitcode ("mov", "c,acc.7");
8476       AccAXRrl1 (x);            // s->a:x
8477
8478       break;
8479     case 3:
8480     case 4:
8481     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8482
8483       tlbl = newiTempLabel (NULL);
8484       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8485
8486       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8487
8488       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8489
8490       emitcode ("anl", "a,#0x%02x",
8491                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8492
8493       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8494
8495       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8496
8497       emitcode ("anl", "a,#0x%02x",
8498                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8499
8500       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8501
8502       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8503
8504       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8505
8506       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8507       emitcode ("orl", "a,#0x%02x",
8508                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8509
8510       emitLabel (tlbl);
8511       break;                    // SSSSAAAA:BBBCCCCC
8512
8513     case 6:                     // AABBBBBB:CCDDDDDD
8514
8515       tlbl = newiTempLabel (NULL);
8516       emitcode ("mov", "c,acc.7");
8517       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8518
8519       emitcode ("mov", "c,acc.7");
8520       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8521
8522       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8523
8524       emitcode ("anl", "a,#0x%02x",
8525                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8526
8527       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8528       emitcode ("orl", "a,#0x%02x",
8529                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8530
8531       emitLabel (tlbl);
8532       break;
8533     case 7:                     // ABBBBBBB:CDDDDDDD
8534
8535       tlbl = newiTempLabel (NULL);
8536       emitcode ("mov", "c,acc.7");      // c = A
8537
8538       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8539
8540       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8541
8542       emitcode ("anl", "a,#0x%02x",
8543                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8544
8545       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8546       emitcode ("orl", "a,#0x%02x",
8547                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8548
8549       emitLabel (tlbl);
8550       break;
8551     default:
8552       break;
8553     }
8554 }
8555
8556 /*-----------------------------------------------------------------*/
8557 /* shiftL2Left2Result - shift left two bytes from left to result   */
8558 /*-----------------------------------------------------------------*/
8559 static void
8560 shiftL2Left2Result (operand * left, int offl,
8561                     operand * result, int offr, int shCount)
8562 {
8563   char * x;
8564   bool pushedB = FALSE;
8565   bool usedB = FALSE;
8566
8567   if (sameRegs (AOP (result), AOP (left)) &&
8568       ((offl + MSB16) == offr))
8569     {
8570       /* don't crash result[offr] */
8571       MOVA (aopGet (left, offl, FALSE, FALSE));
8572       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8573       usedB = !strncmp(x, "b", 1);
8574     }
8575   else if (aopGetUsesAcc (result, offr))
8576     {
8577       movLeft2Result (left, offl, result, offr, 0);
8578       pushedB = pushB ();
8579       usedB = TRUE;
8580       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8581       MOVA (aopGet (result, offr, FALSE, FALSE));
8582       emitcode ("xch", "a,b");
8583       x = "b";
8584     }
8585   else
8586     {
8587       movLeft2Result (left, offl, result, offr, 0);
8588       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8589       x = aopGet (result, offr, FALSE, FALSE);
8590     }
8591   /* ax << shCount (x = lsb(result)) */
8592   AccAXLsh (x, shCount);
8593   if (usedB)
8594     {
8595       emitcode ("xch", "a,b");
8596       aopPut (result, "a", offr);
8597       aopPut (result, "b", offr + MSB16);
8598       popB (pushedB);
8599     }
8600   else
8601     {
8602       aopPut (result, "a", offr + MSB16);
8603     }
8604 }
8605
8606
8607 /*-----------------------------------------------------------------*/
8608 /* shiftR2Left2Result - shift right two bytes from left to result  */
8609 /*-----------------------------------------------------------------*/
8610 static void
8611 shiftR2Left2Result (operand * left, int offl,
8612                     operand * result, int offr,
8613                     int shCount, int sign)
8614 {
8615   char * x;
8616   bool pushedB = FALSE;
8617   bool usedB = FALSE;
8618
8619   if (sameRegs (AOP (result), AOP (left)) &&
8620       ((offl + MSB16) == offr))
8621     {
8622       /* don't crash result[offr] */
8623       MOVA (aopGet (left, offl, FALSE, FALSE));
8624       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8625       usedB = !strncmp(x, "b", 1);
8626     }
8627   else if (aopGetUsesAcc (result, offr))
8628     {
8629       movLeft2Result (left, offl, result, offr, 0);
8630       pushedB = pushB ();
8631       usedB = TRUE;
8632       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8633       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8634       x = "b";
8635     }
8636   else
8637     {
8638       movLeft2Result (left, offl, result, offr, 0);
8639       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8640       x = aopGet (result, offr, FALSE, FALSE);
8641     }
8642   /* a:x >> shCount (x = lsb(result)) */
8643   if (sign)
8644     AccAXRshS (x, shCount);
8645   else
8646     AccAXRsh (x, shCount);
8647   if (usedB)
8648     {
8649       emitcode ("xch", "a,b");
8650       aopPut (result, "a", offr);
8651       emitcode ("xch", "a,b");
8652       popB (pushedB);
8653     }
8654   if (getDataSize (result) > 1)
8655     aopPut (result, "a", offr + MSB16);
8656 }
8657
8658 /*-----------------------------------------------------------------*/
8659 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8660 /*-----------------------------------------------------------------*/
8661 static void
8662 shiftLLeftOrResult (operand * left, int offl,
8663                     operand * result, int offr, int shCount)
8664 {
8665   MOVA (aopGet (left, offl, FALSE, FALSE));
8666   /* shift left accumulator */
8667   AccLsh (shCount);
8668   /* or with result */
8669   if (aopGetUsesAcc (result, offr))
8670     {
8671       emitcode ("xch", "a,b");
8672       MOVA (aopGet (result, offr, FALSE, FALSE));
8673       emitcode ("orl", "a,b");
8674     }
8675   else
8676     {
8677       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8678     }
8679   /* back to result */
8680   aopPut (result, "a", offr);
8681 }
8682
8683 /*-----------------------------------------------------------------*/
8684 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8685 /*-----------------------------------------------------------------*/
8686 static void
8687 shiftRLeftOrResult (operand * left, int offl,
8688                     operand * result, int offr, int shCount)
8689 {
8690   MOVA (aopGet (left, offl, FALSE, FALSE));
8691   /* shift right accumulator */
8692   AccRsh (shCount);
8693   /* or with result */
8694   if (aopGetUsesAcc(result, offr))
8695     {
8696       emitcode ("xch", "a,b");
8697       MOVA (aopGet (result, offr, FALSE, FALSE));
8698       emitcode ("orl", "a,b");
8699     }
8700   else
8701     {
8702       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8703     }
8704   /* back to result */
8705   aopPut (result, "a", offr);
8706 }
8707
8708 /*-----------------------------------------------------------------*/
8709 /* genlshOne - left shift a one byte quantity by known count       */
8710 /*-----------------------------------------------------------------*/
8711 static void
8712 genlshOne (operand * result, operand * left, int shCount)
8713 {
8714   D (emitcode (";", "genlshOne"));
8715
8716   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8717 }
8718
8719 /*-----------------------------------------------------------------*/
8720 /* genlshTwo - left shift two bytes by known amount != 0           */
8721 /*-----------------------------------------------------------------*/
8722 static void
8723 genlshTwo (operand * result, operand * left, int shCount)
8724 {
8725   int size;
8726
8727   D (emitcode (";", "genlshTwo"));
8728
8729   size = getDataSize (result);
8730
8731   /* if shCount >= 8 */
8732   if (shCount >= 8)
8733     {
8734       shCount -= 8;
8735
8736       if (size > 1)
8737         {
8738           if (shCount)
8739             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8740           else
8741             movLeft2Result (left, LSB, result, MSB16, 0);
8742         }
8743       aopPut (result, zero, LSB);
8744     }
8745
8746   /*  1 <= shCount <= 7 */
8747   else
8748     {
8749       if (size == 1)
8750         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8751       else
8752         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8753     }
8754 }
8755
8756 /*-----------------------------------------------------------------*/
8757 /* shiftLLong - shift left one long from left to result            */
8758 /* offl = LSB or MSB16                                             */
8759 /*-----------------------------------------------------------------*/
8760 static void
8761 shiftLLong (operand * left, operand * result, int offr)
8762 {
8763   char *l;
8764   int size = AOP_SIZE (result);
8765
8766   if (size >= LSB + offr)
8767     {
8768       l = aopGet (left, LSB, FALSE, FALSE);
8769       MOVA (l);
8770       emitcode ("add", "a,acc");
8771       if (sameRegs (AOP (left), AOP (result)) &&
8772           size >= MSB16 + offr && offr != LSB)
8773         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8774       else
8775         aopPut (result, "a", LSB + offr);
8776     }
8777
8778   if (size >= MSB16 + offr)
8779     {
8780       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8781         {
8782           l = aopGet (left, MSB16, FALSE, FALSE);
8783           MOVA (l);
8784         }
8785       emitcode ("rlc", "a");
8786       if (sameRegs (AOP (left), AOP (result)) &&
8787           size >= MSB24 + offr && offr != LSB)
8788         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8789       else
8790         aopPut (result, "a", MSB16 + offr);
8791     }
8792
8793   if (size >= MSB24 + offr)
8794     {
8795       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8796         {
8797           l = aopGet (left, MSB24, FALSE, FALSE);
8798           MOVA (l);
8799         }
8800       emitcode ("rlc", "a");
8801       if (sameRegs (AOP (left), AOP (result)) &&
8802           size >= MSB32 + offr && offr != LSB)
8803         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8804       else
8805         aopPut (result, "a", MSB24 + offr);
8806     }
8807
8808   if (size > MSB32 + offr)
8809     {
8810       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8811         {
8812           l = aopGet (left, MSB32, FALSE, FALSE);
8813           MOVA (l);
8814         }
8815       emitcode ("rlc", "a");
8816       aopPut (result, "a", MSB32 + offr);
8817     }
8818   if (offr != LSB)
8819     aopPut (result, zero, LSB);
8820 }
8821
8822 /*-----------------------------------------------------------------*/
8823 /* genlshFour - shift four byte by a known amount != 0             */
8824 /*-----------------------------------------------------------------*/
8825 static void
8826 genlshFour (operand * result, operand * left, int shCount)
8827 {
8828   int size;
8829
8830   D (emitcode (";", "genlshFour"));
8831
8832   size = AOP_SIZE (result);
8833
8834   /* if shifting more that 3 bytes */
8835   if (shCount >= 24)
8836     {
8837       shCount -= 24;
8838       if (shCount)
8839         /* lowest order of left goes to the highest
8840            order of the destination */
8841         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8842       else
8843         movLeft2Result (left, LSB, result, MSB32, 0);
8844       aopPut (result, zero, LSB);
8845       aopPut (result, zero, MSB16);
8846       aopPut (result, zero, MSB24);
8847       return;
8848     }
8849
8850   /* more than two bytes */
8851   else if (shCount >= 16)
8852     {
8853       /* lower order two bytes goes to higher order two bytes */
8854       shCount -= 16;
8855       /* if some more remaining */
8856       if (shCount)
8857         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8858       else
8859         {
8860           movLeft2Result (left, MSB16, result, MSB32, 0);
8861           movLeft2Result (left, LSB, result, MSB24, 0);
8862         }
8863       aopPut (result, zero, MSB16);
8864       aopPut (result, zero, LSB);
8865       return;
8866     }
8867
8868   /* if more than 1 byte */
8869   else if (shCount >= 8)
8870     {
8871       /* lower order three bytes goes to higher order  three bytes */
8872       shCount -= 8;
8873       if (size == 2)
8874         {
8875           if (shCount)
8876             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8877           else
8878             movLeft2Result (left, LSB, result, MSB16, 0);
8879         }
8880       else
8881         {                       /* size = 4 */
8882           if (shCount == 0)
8883             {
8884               movLeft2Result (left, MSB24, result, MSB32, 0);
8885               movLeft2Result (left, MSB16, result, MSB24, 0);
8886               movLeft2Result (left, LSB, result, MSB16, 0);
8887               aopPut (result, zero, LSB);
8888             }
8889           else if (shCount == 1)
8890             shiftLLong (left, result, MSB16);
8891           else
8892             {
8893               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8894               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8895               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8896               aopPut (result, zero, LSB);
8897             }
8898         }
8899     }
8900
8901   /* 1 <= shCount <= 7 */
8902   else if (shCount <= 2)
8903     {
8904       shiftLLong (left, result, LSB);
8905       if (shCount == 2)
8906         shiftLLong (result, result, LSB);
8907     }
8908   /* 3 <= shCount <= 7, optimize */
8909   else
8910     {
8911       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8912       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8913       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8914     }
8915 }
8916
8917 /*-----------------------------------------------------------------*/
8918 /* genLeftShiftLiteral - left shifting by known count              */
8919 /*-----------------------------------------------------------------*/
8920 static void
8921 genLeftShiftLiteral (operand * left,
8922                      operand * right,
8923                      operand * result,
8924                      iCode * ic)
8925 {
8926   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8927   int size;
8928
8929   D (emitcode (";", "genLeftShiftLiteral"));
8930
8931   freeAsmop (right, NULL, ic, TRUE);
8932
8933   aopOp (left, ic, FALSE);
8934   aopOp (result, ic, FALSE);
8935
8936   size = getSize (operandType (result));
8937
8938 #if VIEW_SIZE
8939   emitcode ("; shift left ", "result %d, left %d", size,
8940             AOP_SIZE (left));
8941 #endif
8942
8943   /* I suppose that the left size >= result size */
8944   if (shCount == 0)
8945     {
8946       while (size--)
8947         {
8948           movLeft2Result (left, size, result, size, 0);
8949         }
8950     }
8951   else if (shCount >= (size * 8))
8952     {
8953       while (size--)
8954         {
8955           aopPut (result, zero, size);
8956         }
8957     }
8958   else
8959     {
8960       switch (size)
8961         {
8962         case 1:
8963           genlshOne (result, left, shCount);
8964           break;
8965
8966         case 2:
8967           genlshTwo (result, left, shCount);
8968           break;
8969
8970         case 4:
8971           genlshFour (result, left, shCount);
8972           break;
8973         default:
8974           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8975                   "*** ack! mystery literal shift!\n");
8976           break;
8977         }
8978     }
8979   freeAsmop (result, NULL, ic, TRUE);
8980   freeAsmop (left, NULL, ic, TRUE);
8981 }
8982
8983 /*-----------------------------------------------------------------*/
8984 /* genLeftShift - generates code for left shifting                 */
8985 /*-----------------------------------------------------------------*/
8986 static void
8987 genLeftShift (iCode * ic)
8988 {
8989   operand *left, *right, *result;
8990   int size, offset;
8991   char *l;
8992   symbol *tlbl, *tlbl1;
8993   bool pushedB;
8994
8995   D (emitcode (";", "genLeftShift"));
8996
8997   right = IC_RIGHT (ic);
8998   left = IC_LEFT (ic);
8999   result = IC_RESULT (ic);
9000
9001   aopOp (right, ic, FALSE);
9002
9003   /* if the shift count is known then do it
9004      as efficiently as possible */
9005   if (AOP_TYPE (right) == AOP_LIT)
9006     {
9007       genLeftShiftLiteral (left, right, result, ic);
9008       return;
9009     }
9010
9011   /* shift count is unknown then we have to form
9012      a loop get the loop count in B : Note: we take
9013      only the lower order byte since shifting
9014      more that 32 bits make no sense anyway, ( the
9015      largest size of an object can be only 32 bits ) */
9016
9017   pushedB = pushB ();
9018   MOVB (aopGet (right, 0, FALSE, FALSE));
9019   emitcode ("inc", "b");
9020   freeAsmop (right, NULL, ic, TRUE);
9021   aopOp (left, ic, FALSE);
9022   aopOp (result, ic, FALSE);
9023
9024   /* now move the left to the result if they are not the same */
9025   if (!sameRegs (AOP (left), AOP (result)) &&
9026       AOP_SIZE (result) > 1)
9027     {
9028
9029       size = AOP_SIZE (result);
9030       offset = 0;
9031       while (size--)
9032         {
9033           l = aopGet (left, offset, FALSE, TRUE);
9034           if (*l == '@' && (IS_AOP_PREG (result)))
9035             {
9036
9037               emitcode ("mov", "a,%s", l);
9038               aopPut (result, "a", offset);
9039             }
9040           else
9041             aopPut (result, l, offset);
9042           offset++;
9043         }
9044     }
9045
9046   tlbl = newiTempLabel (NULL);
9047   size = AOP_SIZE (result);
9048   offset = 0;
9049   tlbl1 = newiTempLabel (NULL);
9050
9051   /* if it is only one byte then */
9052   if (size == 1)
9053     {
9054       symbol *tlbl1 = newiTempLabel (NULL);
9055
9056       l = aopGet (left, 0, FALSE, FALSE);
9057       MOVA (l);
9058       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9059       emitLabel (tlbl);
9060       emitcode ("add", "a,acc");
9061       emitLabel (tlbl1);
9062       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9063       popB (pushedB);
9064       aopPut (result, "a", 0);
9065       goto release;
9066     }
9067
9068   reAdjustPreg (AOP (result));
9069
9070   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9071   emitLabel (tlbl);
9072   l = aopGet (result, offset, FALSE, FALSE);
9073   MOVA (l);
9074   emitcode ("add", "a,acc");
9075   aopPut (result, "a", offset++);
9076   while (--size)
9077     {
9078       l = aopGet (result, offset, FALSE, FALSE);
9079       MOVA (l);
9080       emitcode ("rlc", "a");
9081       aopPut (result, "a", offset++);
9082     }
9083   reAdjustPreg (AOP (result));
9084
9085   emitLabel (tlbl1);
9086   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9087   popB (pushedB);
9088 release:
9089   freeAsmop (result, NULL, ic, TRUE);
9090   freeAsmop (left, NULL, ic, TRUE);
9091 }
9092
9093 /*-----------------------------------------------------------------*/
9094 /* genrshOne - right shift a one byte quantity by known count      */
9095 /*-----------------------------------------------------------------*/
9096 static void
9097 genrshOne (operand * result, operand * left,
9098            int shCount, int sign)
9099 {
9100   D (emitcode (";", "genrshOne"));
9101
9102   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9103 }
9104
9105 /*-----------------------------------------------------------------*/
9106 /* genrshTwo - right shift two bytes by known amount != 0          */
9107 /*-----------------------------------------------------------------*/
9108 static void
9109 genrshTwo (operand * result, operand * left,
9110            int shCount, int sign)
9111 {
9112   D (emitcode (";", "genrshTwo"));
9113
9114   /* if shCount >= 8 */
9115   if (shCount >= 8)
9116     {
9117       shCount -= 8;
9118       if (shCount)
9119         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9120       else
9121         movLeft2Result (left, MSB16, result, LSB, sign);
9122       addSign (result, MSB16, sign);
9123     }
9124
9125   /*  1 <= shCount <= 7 */
9126   else
9127     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9128 }
9129
9130 /*-----------------------------------------------------------------*/
9131 /* shiftRLong - shift right one long from left to result           */
9132 /* offl = LSB or MSB16                                             */
9133 /*-----------------------------------------------------------------*/
9134 static void
9135 shiftRLong (operand * left, int offl,
9136             operand * result, int sign)
9137 {
9138   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9139
9140   if (overlapping && offl>1)
9141     {
9142       // we are in big trouble, but this shouldn't happen
9143       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9144     }
9145
9146   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9147
9148   if (offl==MSB16)
9149     {
9150       // shift is > 8
9151       if (sign)
9152         {
9153           emitcode ("rlc", "a");
9154           emitcode ("subb", "a,acc");
9155           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9156             {
9157               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9158             }
9159           else
9160             {
9161               aopPut (result, "a", MSB32);
9162               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9163             }
9164         }
9165       else
9166         {
9167           if (aopPutUsesAcc (result, zero, MSB32))
9168             {
9169               emitcode("xch", "a,b");
9170               aopPut (result, zero, MSB32);
9171               emitcode("xch", "a,b");
9172             }
9173           else
9174             {
9175               aopPut (result, zero, MSB32);
9176             }
9177         }
9178     }
9179
9180   if (!sign)
9181     {
9182       emitcode ("clr", "c");
9183     }
9184   else
9185     {
9186       emitcode ("mov", "c,acc.7");
9187     }
9188
9189   emitcode ("rrc", "a");
9190
9191   if (overlapping && offl==MSB16 &&
9192       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9193     {
9194       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9195     }
9196   else
9197     {
9198       aopPut (result, "a", MSB32 - offl);
9199       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9200     }
9201
9202   emitcode ("rrc", "a");
9203   if (overlapping && offl==MSB16 &&
9204       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9205     {
9206       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9207     }
9208   else
9209     {
9210       aopPut (result, "a", MSB24 - offl);
9211       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9212     }
9213
9214   emitcode ("rrc", "a");
9215   if (offl != LSB)
9216     {
9217       aopPut (result, "a", MSB16 - offl);
9218     }
9219   else
9220     {
9221       if (overlapping &&
9222           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9223         {
9224           xch_a_aopGet (left, LSB, FALSE, FALSE);
9225         }
9226       else
9227         {
9228           aopPut (result, "a", MSB16 - offl);
9229           MOVA (aopGet (left, LSB, FALSE, FALSE));
9230         }
9231       emitcode ("rrc", "a");
9232       aopPut (result, "a", LSB);
9233     }
9234 }
9235
9236 /*-----------------------------------------------------------------*/
9237 /* genrshFour - shift four byte by a known amount != 0             */
9238 /*-----------------------------------------------------------------*/
9239 static void
9240 genrshFour (operand * result, operand * left,
9241             int shCount, int sign)
9242 {
9243   D (emitcode (";", "genrshFour"));
9244
9245   /* if shifting more that 3 bytes */
9246   if (shCount >= 24)
9247     {
9248       shCount -= 24;
9249       if (shCount)
9250         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9251       else
9252         movLeft2Result (left, MSB32, result, LSB, sign);
9253       addSign (result, MSB16, sign);
9254     }
9255   else if (shCount >= 16)
9256     {
9257       shCount -= 16;
9258       if (shCount)
9259         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9260       else
9261         {
9262           movLeft2Result (left, MSB24, result, LSB, 0);
9263           movLeft2Result (left, MSB32, result, MSB16, sign);
9264         }
9265       addSign (result, MSB24, sign);
9266     }
9267   else if (shCount >= 8)
9268     {
9269       shCount -= 8;
9270       if (shCount == 1)
9271         {
9272           shiftRLong (left, MSB16, result, sign);
9273         }
9274       else if (shCount == 0)
9275         {
9276           movLeft2Result (left, MSB16, result, LSB, 0);
9277           movLeft2Result (left, MSB24, result, MSB16, 0);
9278           movLeft2Result (left, MSB32, result, MSB24, sign);
9279           addSign (result, MSB32, sign);
9280         }
9281       else
9282         {
9283           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9284           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9285           /* the last shift is signed */
9286           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9287           addSign (result, MSB32, sign);
9288         }
9289     }
9290   else
9291     {
9292       /* 1 <= shCount <= 7 */
9293       if (shCount <= 2)
9294         {
9295           shiftRLong (left, LSB, result, sign);
9296           if (shCount == 2)
9297             shiftRLong (result, LSB, result, sign);
9298         }
9299       else
9300         {
9301           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9302           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9303           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9304         }
9305     }
9306 }
9307
9308 /*-----------------------------------------------------------------*/
9309 /* genRightShiftLiteral - right shifting by known count            */
9310 /*-----------------------------------------------------------------*/
9311 static void
9312 genRightShiftLiteral (operand * left,
9313                       operand * right,
9314                       operand * result,
9315                       iCode * ic,
9316                       int sign)
9317 {
9318   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9319   int size;
9320
9321   D (emitcode (";", "genRightShiftLiteral"));
9322
9323   freeAsmop (right, NULL, ic, TRUE);
9324
9325   aopOp (left, ic, FALSE);
9326   aopOp (result, ic, FALSE);
9327
9328 #if VIEW_SIZE
9329   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9330             AOP_SIZE (left));
9331 #endif
9332
9333   size = getDataSize (left);
9334   /* test the LEFT size !!! */
9335
9336   /* I suppose that the left size >= result size */
9337   if (shCount == 0)
9338     {
9339       size = getDataSize (result);
9340       while (size--)
9341         movLeft2Result (left, size, result, size, 0);
9342     }
9343
9344   else if (shCount >= (size * 8))
9345     {
9346       if (sign)
9347         {
9348           /* get sign in acc.7 */
9349           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9350         }
9351       addSign (result, LSB, sign);
9352     }
9353   else
9354     {
9355       switch (size)
9356         {
9357         case 1:
9358           genrshOne (result, left, shCount, sign);
9359           break;
9360
9361         case 2:
9362           genrshTwo (result, left, shCount, sign);
9363           break;
9364
9365         case 4:
9366           genrshFour (result, left, shCount, sign);
9367           break;
9368         default:
9369           break;
9370         }
9371     }
9372   freeAsmop (result, NULL, ic, TRUE);
9373   freeAsmop (left, NULL, ic, TRUE);
9374 }
9375
9376 /*-----------------------------------------------------------------*/
9377 /* genSignedRightShift - right shift of signed number              */
9378 /*-----------------------------------------------------------------*/
9379 static void
9380 genSignedRightShift (iCode * ic)
9381 {
9382   operand *right, *left, *result;
9383   int size, offset;
9384   char *l;
9385   symbol *tlbl, *tlbl1;
9386   bool pushedB;
9387
9388   D (emitcode (";", "genSignedRightShift"));
9389
9390   /* we do it the hard way put the shift count in b
9391      and loop thru preserving the sign */
9392
9393   right = IC_RIGHT (ic);
9394   left = IC_LEFT (ic);
9395   result = IC_RESULT (ic);
9396
9397   aopOp (right, ic, FALSE);
9398
9399
9400   if (AOP_TYPE (right) == AOP_LIT)
9401     {
9402       genRightShiftLiteral (left, right, result, ic, 1);
9403       return;
9404     }
9405   /* shift count is unknown then we have to form
9406      a loop get the loop count in B : Note: we take
9407      only the lower order byte since shifting
9408      more that 32 bits make no sense anyway, ( the
9409      largest size of an object can be only 32 bits ) */
9410
9411   pushedB = pushB ();
9412   MOVB (aopGet (right, 0, FALSE, FALSE));
9413   emitcode ("inc", "b");
9414   freeAsmop (right, NULL, ic, TRUE);
9415   aopOp (left, ic, FALSE);
9416   aopOp (result, ic, FALSE);
9417
9418   /* now move the left to the result if they are not the
9419      same */
9420   if (!sameRegs (AOP (left), AOP (result)) &&
9421       AOP_SIZE (result) > 1)
9422     {
9423
9424       size = AOP_SIZE (result);
9425       offset = 0;
9426       while (size--)
9427         {
9428           l = aopGet (left, offset, FALSE, TRUE);
9429           if (*l == '@' && IS_AOP_PREG (result))
9430             {
9431
9432               emitcode ("mov", "a,%s", l);
9433               aopPut (result, "a", offset);
9434             }
9435           else
9436             aopPut (result, l, offset);
9437           offset++;
9438         }
9439     }
9440
9441   /* mov the highest order bit to OVR */
9442   tlbl = newiTempLabel (NULL);
9443   tlbl1 = newiTempLabel (NULL);
9444
9445   size = AOP_SIZE (result);
9446   offset = size - 1;
9447   MOVA (aopGet (left, offset, FALSE, FALSE));
9448   emitcode ("rlc", "a");
9449   emitcode ("mov", "ov,c");
9450   /* if it is only one byte then */
9451   if (size == 1)
9452     {
9453       l = aopGet (left, 0, FALSE, FALSE);
9454       MOVA (l);
9455       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9456       emitLabel (tlbl);
9457       emitcode ("mov", "c,ov");
9458       emitcode ("rrc", "a");
9459       emitLabel (tlbl1);
9460       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9461       popB (pushedB);
9462       aopPut (result, "a", 0);
9463       goto release;
9464     }
9465
9466   reAdjustPreg (AOP (result));
9467   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9468   emitLabel (tlbl);
9469   emitcode ("mov", "c,ov");
9470   while (size--)
9471     {
9472       l = aopGet (result, offset, FALSE, FALSE);
9473       MOVA (l);
9474       emitcode ("rrc", "a");
9475       aopPut (result, "a", offset--);
9476     }
9477   reAdjustPreg (AOP (result));
9478   emitLabel (tlbl1);
9479   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9480   popB (pushedB);
9481
9482 release:
9483   freeAsmop (result, NULL, ic, TRUE);
9484   freeAsmop (left, NULL, ic, TRUE);
9485 }
9486
9487 /*-----------------------------------------------------------------*/
9488 /* genRightShift - generate code for right shifting                */
9489 /*-----------------------------------------------------------------*/
9490 static void
9491 genRightShift (iCode * ic)
9492 {
9493   operand *right, *left, *result;
9494   sym_link *letype;
9495   int size, offset;
9496   char *l;
9497   symbol *tlbl, *tlbl1;
9498   bool pushedB;
9499
9500   D (emitcode (";", "genRightShift"));
9501
9502   /* if signed then we do it the hard way preserve the
9503      sign bit moving it inwards */
9504   letype = getSpec (operandType (IC_LEFT (ic)));
9505
9506   if (!SPEC_USIGN (letype))
9507     {
9508       genSignedRightShift (ic);
9509       return;
9510     }
9511
9512   /* signed & unsigned types are treated the same : i.e. the
9513      signed is NOT propagated inwards : quoting from the
9514      ANSI - standard : "for E1 >> E2, is equivalent to division
9515      by 2**E2 if unsigned or if it has a non-negative value,
9516      otherwise the result is implementation defined ", MY definition
9517      is that the sign does not get propagated */
9518
9519   right = IC_RIGHT (ic);
9520   left = IC_LEFT (ic);
9521   result = IC_RESULT (ic);
9522
9523   aopOp (right, ic, FALSE);
9524
9525   /* if the shift count is known then do it
9526      as efficiently as possible */
9527   if (AOP_TYPE (right) == AOP_LIT)
9528     {
9529       genRightShiftLiteral (left, right, result, ic, 0);
9530       return;
9531     }
9532
9533   /* shift count is unknown then we have to form
9534      a loop get the loop count in B : Note: we take
9535      only the lower order byte since shifting
9536      more that 32 bits make no sense anyway, ( the
9537      largest size of an object can be only 32 bits ) */
9538
9539   pushedB = pushB ();
9540   MOVB (aopGet (right, 0, FALSE, FALSE));
9541   emitcode ("inc", "b");
9542   freeAsmop (right, NULL, ic, TRUE);
9543   aopOp (left, ic, FALSE);
9544   aopOp (result, ic, FALSE);
9545
9546   /* now move the left to the result if they are not the
9547      same */
9548   if (!sameRegs (AOP (left), AOP (result)) &&
9549       AOP_SIZE (result) > 1)
9550     {
9551       size = AOP_SIZE (result);
9552       offset = 0;
9553       while (size--)
9554         {
9555           l = aopGet (left, offset, FALSE, TRUE);
9556           if (*l == '@' && IS_AOP_PREG (result))
9557             {
9558
9559               emitcode ("mov", "a,%s", l);
9560               aopPut (result, "a", offset);
9561             }
9562           else
9563             aopPut (result, l, offset);
9564           offset++;
9565         }
9566     }
9567
9568   tlbl = newiTempLabel (NULL);
9569   tlbl1 = newiTempLabel (NULL);
9570   size = AOP_SIZE (result);
9571   offset = size - 1;
9572
9573   /* if it is only one byte then */
9574   if (size == 1)
9575     {
9576       l = aopGet (left, 0, FALSE, FALSE);
9577       MOVA (l);
9578       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9579       emitLabel (tlbl);
9580       CLRC;
9581       emitcode ("rrc", "a");
9582       emitLabel (tlbl1);
9583       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9584       popB (pushedB);
9585       aopPut (result, "a", 0);
9586       goto release;
9587     }
9588
9589   reAdjustPreg (AOP (result));
9590   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9591   emitLabel (tlbl);
9592   CLRC;
9593   while (size--)
9594     {
9595       l = aopGet (result, offset, FALSE, FALSE);
9596       MOVA (l);
9597       emitcode ("rrc", "a");
9598       aopPut (result, "a", offset--);
9599     }
9600   reAdjustPreg (AOP (result));
9601
9602   emitLabel (tlbl1);
9603   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9604   popB (pushedB);
9605
9606 release:
9607   freeAsmop (result, NULL, ic, TRUE);
9608   freeAsmop (left, NULL, ic, TRUE);
9609 }
9610
9611 /*-----------------------------------------------------------------*/
9612 /* emitPtrByteGet - emits code to get a byte into A through a      */
9613 /*                  pointer register (R0, R1, or DPTR). The        */
9614 /*                  original value of A can be preserved in B.     */
9615 /*-----------------------------------------------------------------*/
9616 static void
9617 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9618 {
9619   switch (p_type)
9620     {
9621     case IPOINTER:
9622     case POINTER:
9623       if (preserveAinB)
9624         emitcode ("mov", "b,a");
9625       emitcode ("mov", "a,@%s", rname);
9626       break;
9627
9628     case PPOINTER:
9629       if (preserveAinB)
9630         emitcode ("mov", "b,a");
9631       emitcode ("movx", "a,@%s", rname);
9632       break;
9633
9634     case FPOINTER:
9635       if (preserveAinB)
9636         emitcode ("mov", "b,a");
9637       emitcode ("movx", "a,@dptr");
9638       break;
9639
9640     case CPOINTER:
9641       if (preserveAinB)
9642         emitcode ("mov", "b,a");
9643       emitcode ("clr", "a");
9644       emitcode ("movc", "a,@a+dptr");
9645       break;
9646
9647     case GPOINTER:
9648       if (preserveAinB)
9649         {
9650           emitcode ("push", "b");
9651           emitcode ("push", "acc");
9652         }
9653       emitcode ("lcall", "__gptrget");
9654       if (preserveAinB)
9655         emitcode ("pop", "b");
9656       break;
9657     }
9658 }
9659
9660 /*-----------------------------------------------------------------*/
9661 /* emitPtrByteSet - emits code to set a byte from src through a    */
9662 /*                  pointer register (R0, R1, or DPTR).            */
9663 /*-----------------------------------------------------------------*/
9664 static void
9665 emitPtrByteSet (char *rname, int p_type, char *src)
9666 {
9667   switch (p_type)
9668     {
9669     case IPOINTER:
9670     case POINTER:
9671       if (*src=='@')
9672         {
9673           MOVA (src);
9674           emitcode ("mov", "@%s,a", rname);
9675         }
9676       else
9677         emitcode ("mov", "@%s,%s", rname, src);
9678       break;
9679
9680     case PPOINTER:
9681       MOVA (src);
9682       emitcode ("movx", "@%s,a", rname);
9683       break;
9684
9685     case FPOINTER:
9686       MOVA (src);
9687       emitcode ("movx", "@dptr,a");
9688       break;
9689
9690     case GPOINTER:
9691       MOVA (src);
9692       emitcode ("lcall", "__gptrput");
9693       break;
9694     }
9695 }
9696
9697 /*-----------------------------------------------------------------*/
9698 /* genUnpackBits - generates code for unpacking bits               */
9699 /*-----------------------------------------------------------------*/
9700 static void
9701 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9702 {
9703   int offset = 0;       /* result byte offset */
9704   int rsize;            /* result size */
9705   int rlen = 0;         /* remaining bitfield length */
9706   sym_link *etype;      /* bitfield type information */
9707   int blen;             /* bitfield length */
9708   int bstr;             /* bitfield starting bit within byte */
9709   char buffer[10];
9710
9711   D(emitcode (";     genUnpackBits",""));
9712
9713   etype = getSpec (operandType (result));
9714   rsize = getSize (operandType (result));
9715   blen = SPEC_BLEN (etype);
9716   bstr = SPEC_BSTR (etype);
9717
9718   if (ifx && blen <= 8)
9719     {
9720       emitPtrByteGet (rname, ptype, FALSE);
9721       if (blen == 1)
9722         {
9723           SNPRINTF (buffer, sizeof(buffer),
9724                     "acc.%d", bstr);
9725           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9726         }
9727       else
9728         {
9729           if (blen < 8)
9730             emitcode ("anl", "a,#0x%02x",
9731                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9732           genIfxJump (ifx, "a", NULL, NULL, NULL);
9733         }
9734       return;
9735     }
9736   wassert (!ifx);
9737
9738   /* If the bitfield length is less than a byte */
9739   if (blen < 8)
9740     {
9741       emitPtrByteGet (rname, ptype, FALSE);
9742       AccRol (8 - bstr);
9743       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9744       if (!SPEC_USIGN (etype))
9745         {
9746           /* signed bitfield */
9747           symbol *tlbl = newiTempLabel (NULL);
9748
9749           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9750           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9751           emitLabel (tlbl);
9752         }
9753       aopPut (result, "a", offset++);
9754       goto finish;
9755     }
9756
9757   /* Bit field did not fit in a byte. Copy all
9758      but the partial byte at the end.  */
9759   for (rlen=blen;rlen>=8;rlen-=8)
9760     {
9761       emitPtrByteGet (rname, ptype, FALSE);
9762       aopPut (result, "a", offset++);
9763       if (rlen>8)
9764         emitcode ("inc", "%s", rname);
9765     }
9766
9767   /* Handle the partial byte at the end */
9768   if (rlen)
9769     {
9770       emitPtrByteGet (rname, ptype, FALSE);
9771       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9772       if (!SPEC_USIGN (etype))
9773         {
9774           /* signed bitfield */
9775           symbol *tlbl = newiTempLabel (NULL);
9776
9777           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9778           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9779           emitLabel (tlbl);
9780         }
9781       aopPut (result, "a", offset++);
9782     }
9783
9784 finish:
9785   if (offset < rsize)
9786     {
9787       char *source;
9788
9789       if (SPEC_USIGN (etype))
9790         source = zero;
9791       else
9792         {
9793           /* signed bitfield: sign extension with 0x00 or 0xff */
9794           emitcode ("rlc", "a");
9795           emitcode ("subb", "a,acc");
9796
9797           source = "a";
9798         }
9799       rsize -= offset;
9800       while (rsize--)
9801         aopPut (result, source, offset++);
9802     }
9803 }
9804
9805
9806 /*-----------------------------------------------------------------*/
9807 /* genDataPointerGet - generates code when ptr offset is known     */
9808 /*-----------------------------------------------------------------*/
9809 static void
9810 genDataPointerGet (operand * left,
9811                    operand * result,
9812                    iCode * ic)
9813 {
9814   char *l;
9815   char buffer[256];
9816   int size, offset = 0;
9817
9818   D (emitcode (";", "genDataPointerGet"));
9819
9820   aopOp (result, ic, TRUE);
9821
9822   /* get the string representation of the name */
9823   l = aopGet (left, 0, FALSE, TRUE);
9824   l++; // remove #
9825   size = AOP_SIZE (result);
9826   while (size--)
9827     {
9828       if (offset)
9829         {
9830           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9831         }
9832       else
9833         {
9834           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9835         }
9836       aopPut (result, buffer, offset++);
9837     }
9838
9839   freeAsmop (result, NULL, ic, TRUE);
9840   freeAsmop (left, NULL, ic, TRUE);
9841 }
9842
9843 /*-----------------------------------------------------------------*/
9844 /* genNearPointerGet - emitcode for near pointer fetch             */
9845 /*-----------------------------------------------------------------*/
9846 static void
9847 genNearPointerGet (operand * left,
9848                    operand * result,
9849                    iCode * ic,
9850                    iCode * pi,
9851                    iCode * ifx)
9852 {
9853   asmop *aop = NULL;
9854   regs *preg = NULL;
9855   char *rname;
9856   sym_link *rtype, *retype;
9857   sym_link *ltype = operandType (left);
9858   char buffer[80];
9859
9860   D (emitcode (";", "genNearPointerGet"));
9861
9862   rtype = operandType (result);
9863   retype = getSpec (rtype);
9864
9865   aopOp (left, ic, FALSE);
9866
9867   /* if left is rematerialisable and
9868      result is not bitfield variable type and
9869      the left is pointer to data space i.e
9870      lower 128 bytes of space */
9871   if (AOP_TYPE (left) == AOP_IMMD &&
9872       !IS_BITFIELD (retype) &&
9873       DCL_TYPE (ltype) == POINTER)
9874     {
9875       genDataPointerGet (left, result, ic);
9876       return;
9877     }
9878
9879  /* if the value is already in a pointer register
9880      then don't need anything more */
9881   if (!AOP_INPREG (AOP (left)))
9882     {
9883       if (IS_AOP_PREG (left))
9884         {
9885           // Aha, it is a pointer, just in disguise.
9886           rname = aopGet (left, 0, FALSE, FALSE);
9887           if (*rname != '@')
9888             {
9889               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9890                       __FILE__, __LINE__);
9891             }
9892           else
9893             {
9894               // Expected case.
9895               emitcode ("mov", "a%s,%s", rname + 1, rname);
9896               rname++;  // skip the '@'.
9897             }
9898         }
9899       else
9900         {
9901           /* otherwise get a free pointer register */
9902           aop = newAsmop (0);
9903           preg = getFreePtr (ic, &aop, FALSE);
9904           emitcode ("mov", "%s,%s",
9905                     preg->name,
9906                     aopGet (left, 0, FALSE, TRUE));
9907           rname = preg->name;
9908         }
9909     }
9910   else
9911     rname = aopGet (left, 0, FALSE, FALSE);
9912
9913   //aopOp (result, ic, FALSE);
9914   aopOp (result, ic, result?TRUE:FALSE);
9915
9916   /* if bitfield then unpack the bits */
9917   if (IS_BITFIELD (retype))
9918     genUnpackBits (result, rname, POINTER, ifx);
9919   else
9920     {
9921       /* we have can just get the values */
9922       int size = AOP_SIZE (result);
9923       int offset = 0;
9924
9925       while (size--)
9926         {
9927           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9928             {
9929
9930               emitcode ("mov", "a,@%s", rname);
9931               if (!ifx)
9932                 aopPut (result, "a", offset);
9933             }
9934           else
9935             {
9936               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9937               aopPut (result, buffer, offset);
9938             }
9939           offset++;
9940           if (size || pi)
9941             emitcode ("inc", "%s", rname);
9942         }
9943     }
9944
9945   /* now some housekeeping stuff */
9946   if (aop)       /* we had to allocate for this iCode */
9947     {
9948       if (pi) { /* post increment present */
9949         aopPut (left, rname, 0);
9950       }
9951       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9952     }
9953   else
9954     {
9955       /* we did not allocate which means left
9956          already in a pointer register, then
9957          if size > 0 && this could be used again
9958          we have to point it back to where it
9959          belongs */
9960       if ((AOP_SIZE (result) > 1 &&
9961            !OP_SYMBOL (left)->remat &&
9962            (OP_SYMBOL (left)->liveTo > ic->seq ||
9963             ic->depth)) &&
9964           !pi)
9965         {
9966           int size = AOP_SIZE (result) - 1;
9967           while (size--)
9968             emitcode ("dec", "%s", rname);
9969         }
9970     }
9971
9972   if (ifx && !ifx->generated)
9973     {
9974       genIfxJump (ifx, "a", left, NULL, result);
9975     }
9976
9977   /* done */
9978   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9979   freeAsmop (left, NULL, ic, TRUE);
9980   if (pi) pi->generated = 1;
9981 }
9982
9983 /*-----------------------------------------------------------------*/
9984 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9985 /*-----------------------------------------------------------------*/
9986 static void
9987 genPagedPointerGet (operand * left,
9988                     operand * result,
9989                     iCode * ic,
9990                     iCode *pi,
9991                     iCode *ifx)
9992 {
9993   asmop *aop = NULL;
9994   regs *preg = NULL;
9995   char *rname;
9996   sym_link *rtype, *retype;
9997
9998   D (emitcode (";", "genPagedPointerGet"));
9999
10000   rtype = operandType (result);
10001   retype = getSpec (rtype);
10002
10003   aopOp (left, ic, FALSE);
10004
10005   /* if the value is already in a pointer register
10006      then don't need anything more */
10007   if (!AOP_INPREG (AOP (left)))
10008     {
10009       /* otherwise get a free pointer register */
10010       aop = newAsmop (0);
10011       preg = getFreePtr (ic, &aop, FALSE);
10012       emitcode ("mov", "%s,%s",
10013                 preg->name,
10014                 aopGet (left, 0, FALSE, TRUE));
10015       rname = preg->name;
10016     }
10017   else
10018     rname = aopGet (left, 0, FALSE, FALSE);
10019
10020   aopOp (result, ic, FALSE);
10021
10022   /* if bitfield then unpack the bits */
10023   if (IS_BITFIELD (retype))
10024     genUnpackBits (result, rname, PPOINTER, ifx);
10025   else
10026     {
10027       /* we have can just get the values */
10028       int size = AOP_SIZE (result);
10029       int offset = 0;
10030
10031       while (size--)
10032         {
10033
10034           emitcode ("movx", "a,@%s", rname);
10035           if (!ifx)
10036             aopPut (result, "a", offset);
10037
10038           offset++;
10039
10040           if (size || pi)
10041             emitcode ("inc", "%s", rname);
10042         }
10043     }
10044
10045   /* now some housekeeping stuff */
10046   if (aop) /* we had to allocate for this iCode */
10047     {
10048       if (pi)
10049         aopPut (left, rname, 0);
10050       freeAsmop (NULL, aop, ic, TRUE);
10051     }
10052   else
10053     {
10054       /* we did not allocate which means left
10055          already in a pointer register, then
10056          if size > 0 && this could be used again
10057          we have to point it back to where it
10058          belongs */
10059       if ((AOP_SIZE (result) > 1 &&
10060            !OP_SYMBOL (left)->remat &&
10061            (OP_SYMBOL (left)->liveTo > ic->seq ||
10062             ic->depth)) &&
10063           !pi)
10064         {
10065           int size = AOP_SIZE (result) - 1;
10066           while (size--)
10067             emitcode ("dec", "%s", rname);
10068         }
10069     }
10070
10071   if (ifx && !ifx->generated)
10072     {
10073       genIfxJump (ifx, "a", left, NULL, result);
10074     }
10075
10076   /* done */
10077   freeAsmop (result, NULL, ic, TRUE);
10078   freeAsmop (left, NULL, ic, TRUE);
10079   if (pi) pi->generated = 1;
10080 }
10081
10082 /*--------------------------------------------------------------------*/
10083 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10084 /*--------------------------------------------------------------------*/
10085 static void
10086 loadDptrFromOperand (operand *op, bool loadBToo)
10087 {
10088   if (AOP_TYPE (op) != AOP_STR)
10089     {
10090       /* if this is rematerializable */
10091       if (AOP_TYPE (op) == AOP_IMMD)
10092         {
10093           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10094           if (loadBToo)
10095             {
10096               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10097                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10098               else
10099                 {
10100                   wassertl(FALSE, "need pointerCode");
10101                   emitcode ("", "; mov b,???");
10102                   /* genPointerGet and genPointerSet originally did different
10103                   ** things for this case. Both seem wrong.
10104                   ** from genPointerGet:
10105                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10106                   ** from genPointerSet:
10107                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10108                   */
10109                 }
10110             }
10111         }
10112       else if (AOP_TYPE (op) == AOP_DPTR)
10113         {
10114           if (loadBToo)
10115             {
10116               MOVA (aopGet (op, 0, FALSE, FALSE));
10117               emitcode ("push", "acc");
10118               MOVA (aopGet (op, 1, FALSE, FALSE));
10119               emitcode ("push", "acc");
10120               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10121               emitcode ("pop", "dph");
10122               emitcode ("pop", "dpl");
10123             }
10124           else
10125             {
10126               MOVA (aopGet (op, 0, FALSE, FALSE));
10127               emitcode ("push", "acc");
10128               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10129               emitcode ("pop", "dpl");
10130             }
10131         }
10132       else
10133         {                       /* we need to get it byte by byte */
10134           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10135           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10136           if (loadBToo)
10137             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10138         }
10139     }
10140 }
10141
10142 /*-----------------------------------------------------------------*/
10143 /* genFarPointerGet - get value from far space                     */
10144 /*-----------------------------------------------------------------*/
10145 static void
10146 genFarPointerGet (operand * left,
10147                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10148 {
10149   int size, offset;
10150   sym_link *retype = getSpec (operandType (result));
10151
10152   D (emitcode (";", "genFarPointerGet"));
10153
10154   aopOp (left, ic, FALSE);
10155   loadDptrFromOperand (left, FALSE);
10156
10157   /* so dptr now contains the address */
10158   aopOp (result, ic, FALSE);
10159
10160   /* if bit then unpack */
10161   if (IS_BITFIELD (retype))
10162     genUnpackBits (result, "dptr", FPOINTER, ifx);
10163   else
10164     {
10165       size = AOP_SIZE (result);
10166       offset = 0;
10167
10168       while (size--)
10169         {
10170           emitcode ("movx", "a,@dptr");
10171           if (!ifx)
10172             aopPut (result, "a", offset++);
10173           if (size || pi)
10174             emitcode ("inc", "dptr");
10175         }
10176     }
10177
10178   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10179     {
10180       aopPut (left, "dpl", 0);
10181       aopPut (left, "dph", 1);
10182       pi->generated = 1;
10183     }
10184
10185   if (ifx && !ifx->generated)
10186     {
10187       genIfxJump (ifx, "a", left, NULL, result);
10188     }
10189
10190   freeAsmop (result, NULL, ic, TRUE);
10191   freeAsmop (left, NULL, ic, TRUE);
10192 }
10193
10194 /*-----------------------------------------------------------------*/
10195 /* genCodePointerGet - get value from code space                   */
10196 /*-----------------------------------------------------------------*/
10197 static void
10198 genCodePointerGet (operand * left,
10199                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10200 {
10201   int size, offset;
10202   sym_link *retype = getSpec (operandType (result));
10203
10204   D (emitcode (";", "genCodePointerGet"));
10205
10206   aopOp (left, ic, FALSE);
10207   loadDptrFromOperand (left, FALSE);
10208
10209   /* so dptr now contains the address */
10210   aopOp (result, ic, FALSE);
10211
10212   /* if bit then unpack */
10213   if (IS_BITFIELD (retype))
10214     genUnpackBits (result, "dptr", CPOINTER, ifx);
10215   else
10216     {
10217       size = AOP_SIZE (result);
10218       offset = 0;
10219
10220       while (size--)
10221         {
10222           emitcode ("clr", "a");
10223           emitcode ("movc", "a,@a+dptr");
10224           if (!ifx)
10225             aopPut (result, "a", offset++);
10226           if (size || pi)
10227             emitcode ("inc", "dptr");
10228         }
10229     }
10230
10231   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10232     {
10233       aopPut (left, "dpl", 0);
10234       aopPut (left, "dph", 1);
10235       pi->generated = 1;
10236     }
10237
10238   if (ifx && !ifx->generated)
10239     {
10240       genIfxJump (ifx, "a", left, NULL, result);
10241     }
10242
10243   freeAsmop (result, NULL, ic, TRUE);
10244   freeAsmop (left, NULL, ic, TRUE);
10245 }
10246
10247 /*-----------------------------------------------------------------*/
10248 /* genGenPointerGet - get value from generic pointer space         */
10249 /*-----------------------------------------------------------------*/
10250 static void
10251 genGenPointerGet (operand * left,
10252                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10253 {
10254   int size, offset;
10255   sym_link *retype = getSpec (operandType (result));
10256
10257   D (emitcode (";", "genGenPointerGet"));
10258
10259   aopOp (left, ic, FALSE);
10260   loadDptrFromOperand (left, TRUE);
10261
10262   /* so dptr now contains the address */
10263   aopOp (result, ic, FALSE);
10264
10265   /* if bit then unpack */
10266   if (IS_BITFIELD (retype))
10267     {
10268       genUnpackBits (result, "dptr", GPOINTER, ifx);
10269     }
10270   else
10271     {
10272       size = AOP_SIZE (result);
10273       offset = 0;
10274
10275       while (size--)
10276         {
10277           emitcode ("lcall", "__gptrget");
10278           if (!ifx)
10279             aopPut (result, "a", offset++);
10280           if (size || pi)
10281             emitcode ("inc", "dptr");
10282         }
10283     }
10284
10285   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10286     {
10287       aopPut (left, "dpl", 0);
10288       aopPut (left, "dph", 1);
10289       pi->generated = 1;
10290     }
10291
10292   if (ifx && !ifx->generated)
10293     {
10294       genIfxJump (ifx, "a", left, NULL, result);
10295     }
10296
10297   freeAsmop (result, NULL, ic, TRUE);
10298   freeAsmop (left, NULL, ic, TRUE);
10299 }
10300
10301 /*-----------------------------------------------------------------*/
10302 /* genPointerGet - generate code for pointer get                   */
10303 /*-----------------------------------------------------------------*/
10304 static void
10305 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10306 {
10307   operand *left, *result;
10308   sym_link *type, *etype;
10309   int p_type;
10310
10311   D (emitcode (";", "genPointerGet"));
10312
10313   left = IC_LEFT (ic);
10314   result = IC_RESULT (ic);
10315
10316   if (getSize (operandType (result))>1)
10317     ifx = NULL;
10318
10319   /* depending on the type of pointer we need to
10320      move it to the correct pointer register */
10321   type = operandType (left);
10322   etype = getSpec (type);
10323   /* if left is of type of pointer then it is simple */
10324   if (IS_PTR (type) && !IS_FUNC (type->next))
10325     p_type = DCL_TYPE (type);
10326   else
10327     {
10328       /* we have to go by the storage class */
10329       p_type = PTR_TYPE (SPEC_OCLS (etype));
10330     }
10331
10332   /* special case when cast remat */
10333   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10334       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10335     {
10336       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10337       type = operandType (left);
10338       p_type = DCL_TYPE (type);
10339     }
10340   /* now that we have the pointer type we assign
10341      the pointer values */
10342   switch (p_type)
10343     {
10344
10345     case POINTER:
10346     case IPOINTER:
10347       genNearPointerGet (left, result, ic, pi, ifx);
10348       break;
10349
10350     case PPOINTER:
10351       genPagedPointerGet (left, result, ic, pi, ifx);
10352       break;
10353
10354     case FPOINTER:
10355       genFarPointerGet (left, result, ic, pi, ifx);
10356       break;
10357
10358     case CPOINTER:
10359       genCodePointerGet (left, result, ic, pi, ifx);
10360       break;
10361
10362     case GPOINTER:
10363       genGenPointerGet (left, result, ic, pi, ifx);
10364       break;
10365     }
10366 }
10367
10368
10369 /*-----------------------------------------------------------------*/
10370 /* genPackBits - generates code for packed bit storage             */
10371 /*-----------------------------------------------------------------*/
10372 static void
10373 genPackBits (sym_link * etype,
10374              operand * right,
10375              char *rname, int p_type)
10376 {
10377   int offset = 0;       /* source byte offset */
10378   int rlen = 0;         /* remaining bitfield length */
10379   int blen;             /* bitfield length */
10380   int bstr;             /* bitfield starting bit within byte */
10381   int litval;           /* source literal value (if AOP_LIT) */
10382   unsigned char mask;   /* bitmask within current byte */
10383
10384   D(emitcode (";     genPackBits",""));
10385
10386   blen = SPEC_BLEN (etype);
10387   bstr = SPEC_BSTR (etype);
10388
10389   /* If the bitfield length is less than a byte */
10390   if (blen < 8)
10391     {
10392       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10393               (unsigned char) (0xFF >> (8 - bstr)));
10394
10395       if (AOP_TYPE (right) == AOP_LIT)
10396         {
10397           /* Case with a bitfield length <8 and literal source
10398           */
10399           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10400           litval <<= bstr;
10401           litval &= (~mask) & 0xff;
10402           emitPtrByteGet (rname, p_type, FALSE);
10403           if ((mask|litval)!=0xff)
10404             emitcode ("anl","a,#0x%02x", mask);
10405           if (litval)
10406             emitcode ("orl","a,#0x%02x", litval);
10407         }
10408       else
10409         {
10410           if ((blen==1) && (p_type!=GPOINTER))
10411             {
10412               /* Case with a bitfield length == 1 and no generic pointer
10413               */
10414               if (AOP_TYPE (right) == AOP_CRY)
10415                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10416               else
10417                 {
10418                   MOVA (aopGet (right, 0, FALSE, FALSE));
10419                   emitcode ("rrc","a");
10420                 }
10421               emitPtrByteGet (rname, p_type, FALSE);
10422               emitcode ("mov","acc.%d,c",bstr);
10423             }
10424           else
10425             {
10426               bool pushedB;
10427               /* Case with a bitfield length < 8 and arbitrary source
10428               */
10429               MOVA (aopGet (right, 0, FALSE, FALSE));
10430               /* shift and mask source value */
10431               AccLsh (bstr);
10432               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10433
10434               pushedB = pushB ();
10435               /* transfer A to B and get next byte */
10436               emitPtrByteGet (rname, p_type, TRUE);
10437
10438               emitcode ("anl", "a,#0x%02x", mask);
10439               emitcode ("orl", "a,b");
10440               if (p_type == GPOINTER)
10441                 emitcode ("pop", "b");
10442
10443               popB (pushedB);
10444            }
10445         }
10446
10447       emitPtrByteSet (rname, p_type, "a");
10448       return;
10449     }
10450
10451   /* Bit length is greater than 7 bits. In this case, copy  */
10452   /* all except the partial byte at the end                 */
10453   for (rlen=blen;rlen>=8;rlen-=8)
10454     {
10455       emitPtrByteSet (rname, p_type,
10456                       aopGet (right, offset++, FALSE, TRUE) );
10457       if (rlen>8)
10458         emitcode ("inc", "%s", rname);
10459     }
10460
10461   /* If there was a partial byte at the end */
10462   if (rlen)
10463     {
10464       mask = (((unsigned char) -1 << rlen) & 0xff);
10465
10466       if (AOP_TYPE (right) == AOP_LIT)
10467         {
10468           /* Case with partial byte and literal source
10469           */
10470           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10471           litval >>= (blen-rlen);
10472           litval &= (~mask) & 0xff;
10473           emitPtrByteGet (rname, p_type, FALSE);
10474           if ((mask|litval)!=0xff)
10475             emitcode ("anl","a,#0x%02x", mask);
10476           if (litval)
10477             emitcode ("orl","a,#0x%02x", litval);
10478         }
10479       else
10480         {
10481           bool pushedB;
10482           /* Case with partial byte and arbitrary source
10483           */
10484           MOVA (aopGet (right, offset++, FALSE, FALSE));
10485           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10486
10487           pushedB = pushB ();
10488           /* transfer A to B and get next byte */
10489           emitPtrByteGet (rname, p_type, TRUE);
10490
10491           emitcode ("anl", "a,#0x%02x", mask);
10492           emitcode ("orl", "a,b");
10493           if (p_type == GPOINTER)
10494             emitcode ("pop", "b");
10495
10496           popB (pushedB);
10497         }
10498       emitPtrByteSet (rname, p_type, "a");
10499     }
10500 }
10501
10502
10503 /*-----------------------------------------------------------------*/
10504 /* genDataPointerSet - remat pointer to data space                 */
10505 /*-----------------------------------------------------------------*/
10506 static void
10507 genDataPointerSet (operand * right,
10508                    operand * result,
10509                    iCode * ic)
10510 {
10511   int size, offset = 0;
10512   char *l, buffer[256];
10513
10514   D (emitcode (";", "genDataPointerSet"));
10515
10516   aopOp (right, ic, FALSE);
10517
10518   l = aopGet (result, 0, FALSE, TRUE);
10519   l++; //remove #
10520   size = AOP_SIZE (right);
10521   while (size--)
10522     {
10523       if (offset)
10524         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10525       else
10526         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10527       emitcode ("mov", "%s,%s", buffer,
10528                 aopGet (right, offset++, FALSE, FALSE));
10529     }
10530
10531   freeAsmop (result, NULL, ic, TRUE);
10532   freeAsmop (right, NULL, ic, TRUE);
10533 }
10534
10535 /*-----------------------------------------------------------------*/
10536 /* genNearPointerSet - emitcode for near pointer put                */
10537 /*-----------------------------------------------------------------*/
10538 static void
10539 genNearPointerSet (operand * right,
10540                    operand * result,
10541                    iCode * ic,
10542                    iCode * pi)
10543 {
10544   asmop *aop = NULL;
10545   regs *preg = NULL;
10546   char *rname, *l;
10547   sym_link *retype, *letype;
10548   sym_link *ptype = operandType (result);
10549
10550   D (emitcode (";", "genNearPointerSet"));
10551
10552   retype = getSpec (operandType (right));
10553   letype = getSpec (ptype);
10554
10555   aopOp (result, ic, FALSE);
10556
10557   /* if the result is rematerializable &
10558      in data space & not a bit variable */
10559   if (AOP_TYPE (result) == AOP_IMMD &&
10560       DCL_TYPE (ptype) == POINTER &&
10561       !IS_BITVAR (retype) &&
10562       !IS_BITVAR (letype))
10563     {
10564       genDataPointerSet (right, result, ic);
10565       return;
10566     }
10567
10568   /* if the value is already in a pointer register
10569      then don't need anything more */
10570   if (!AOP_INPREG (AOP (result)))
10571     {
10572         if (
10573             //AOP_TYPE (result) == AOP_STK
10574             IS_AOP_PREG(result)
10575             )
10576         {
10577             // Aha, it is a pointer, just in disguise.
10578             rname = aopGet (result, 0, FALSE, FALSE);
10579             if (*rname != '@')
10580             {
10581                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10582                         __FILE__, __LINE__);
10583             }
10584             else
10585             {
10586                 // Expected case.
10587                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10588                 rname++;  // skip the '@'.
10589             }
10590         }
10591         else
10592         {
10593             /* otherwise get a free pointer register */
10594             aop = newAsmop (0);
10595             preg = getFreePtr (ic, &aop, FALSE);
10596             emitcode ("mov", "%s,%s",
10597                       preg->name,
10598                       aopGet (result, 0, FALSE, TRUE));
10599             rname = preg->name;
10600         }
10601     }
10602     else
10603     {
10604         rname = aopGet (result, 0, FALSE, FALSE);
10605     }
10606
10607   aopOp (right, ic, FALSE);
10608
10609   /* if bitfield then unpack the bits */
10610   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10611     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10612   else
10613     {
10614       /* we can just get the values */
10615       int size = AOP_SIZE (right);
10616       int offset = 0;
10617
10618       while (size--)
10619         {
10620           l = aopGet (right, offset, FALSE, TRUE);
10621           if ((*l == '@') || (strcmp (l, "acc") == 0))
10622             {
10623               MOVA (l);
10624               emitcode ("mov", "@%s,a", rname);
10625             }
10626           else
10627             emitcode ("mov", "@%s,%s", rname, l);
10628           if (size || pi)
10629             emitcode ("inc", "%s", rname);
10630           offset++;
10631         }
10632     }
10633
10634   /* now some housekeeping stuff */
10635   if (aop) /* we had to allocate for this iCode */
10636     {
10637       if (pi)
10638         aopPut (result, rname, 0);
10639       freeAsmop (NULL, aop, ic, TRUE);
10640     }
10641   else
10642     {
10643       /* we did not allocate which means left
10644          already in a pointer register, then
10645          if size > 0 && this could be used again
10646          we have to point it back to where it
10647          belongs */
10648       if ((AOP_SIZE (right) > 1 &&
10649            !OP_SYMBOL (result)->remat &&
10650            (OP_SYMBOL (result)->liveTo > ic->seq ||
10651             ic->depth)) &&
10652           !pi)
10653         {
10654           int size = AOP_SIZE (right) - 1;
10655           while (size--)
10656             emitcode ("dec", "%s", rname);
10657         }
10658     }
10659
10660   /* done */
10661   if (pi) pi->generated = 1;
10662   freeAsmop (result, NULL, ic, TRUE);
10663   freeAsmop (right, NULL, ic, TRUE);
10664 }
10665
10666 /*-----------------------------------------------------------------*/
10667 /* genPagedPointerSet - emitcode for Paged pointer put             */
10668 /*-----------------------------------------------------------------*/
10669 static void
10670 genPagedPointerSet (operand * right,
10671                     operand * result,
10672                     iCode * ic,
10673                     iCode * pi)
10674 {
10675   asmop *aop = NULL;
10676   regs *preg = NULL;
10677   char *rname, *l;
10678   sym_link *retype, *letype;
10679
10680   D (emitcode (";", "genPagedPointerSet"));
10681
10682   retype = getSpec (operandType (right));
10683   letype = getSpec (operandType (result));
10684
10685   aopOp (result, ic, FALSE);
10686
10687   /* if the value is already in a pointer register
10688      then don't need anything more */
10689   if (!AOP_INPREG (AOP (result)))
10690     {
10691       /* otherwise get a free pointer register */
10692       aop = newAsmop (0);
10693       preg = getFreePtr (ic, &aop, FALSE);
10694       emitcode ("mov", "%s,%s",
10695                 preg->name,
10696                 aopGet (result, 0, FALSE, TRUE));
10697       rname = preg->name;
10698     }
10699   else
10700     rname = aopGet (result, 0, FALSE, FALSE);
10701
10702   aopOp (right, ic, FALSE);
10703
10704   /* if bitfield then unpack the bits */
10705   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10706     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10707   else
10708     {
10709       /* we have can just get the values */
10710       int size = AOP_SIZE (right);
10711       int offset = 0;
10712
10713       while (size--)
10714         {
10715           l = aopGet (right, offset, FALSE, TRUE);
10716           MOVA (l);
10717           emitcode ("movx", "@%s,a", rname);
10718
10719           if (size || pi)
10720             emitcode ("inc", "%s", rname);
10721
10722           offset++;
10723         }
10724     }
10725
10726   /* now some housekeeping stuff */
10727   if (aop) /* we had to allocate for this iCode */
10728     {
10729       if (pi)
10730         aopPut (result, rname, 0);
10731       freeAsmop (NULL, aop, ic, TRUE);
10732     }
10733   else
10734     {
10735       /* we did not allocate which means left
10736          already in a pointer register, then
10737          if size > 0 && this could be used again
10738          we have to point it back to where it
10739          belongs */
10740       if (AOP_SIZE (right) > 1 &&
10741           !OP_SYMBOL (result)->remat &&
10742           (OP_SYMBOL (result)->liveTo > ic->seq ||
10743            ic->depth))
10744         {
10745           int size = AOP_SIZE (right) - 1;
10746           while (size--)
10747             emitcode ("dec", "%s", rname);
10748         }
10749     }
10750
10751   /* done */
10752   if (pi) pi->generated = 1;
10753   freeAsmop (result, NULL, ic, TRUE);
10754   freeAsmop (right, NULL, ic, TRUE);
10755 }
10756
10757 /*-----------------------------------------------------------------*/
10758 /* genFarPointerSet - set value from far space                     */
10759 /*-----------------------------------------------------------------*/
10760 static void
10761 genFarPointerSet (operand * right,
10762                   operand * result, iCode * ic, iCode * pi)
10763 {
10764   int size, offset;
10765   sym_link *retype = getSpec (operandType (right));
10766   sym_link *letype = getSpec (operandType (result));
10767
10768   D(emitcode (";     genFarPointerSet",""));
10769
10770   aopOp (result, ic, FALSE);
10771   loadDptrFromOperand (result, FALSE);
10772
10773   /* so dptr now contains the address */
10774   aopOp (right, ic, FALSE);
10775
10776   /* if bit then unpack */
10777   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10778     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10779   else
10780     {
10781       size = AOP_SIZE (right);
10782       offset = 0;
10783
10784       while (size--)
10785         {
10786           char *l = aopGet (right, offset++, FALSE, FALSE);
10787           MOVA (l);
10788           emitcode ("movx", "@dptr,a");
10789           if (size || pi)
10790             emitcode ("inc", "dptr");
10791         }
10792     }
10793   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10794     aopPut (result, "dpl", 0);
10795     aopPut (result, "dph", 1);
10796     pi->generated=1;
10797   }
10798   freeAsmop (result, NULL, ic, TRUE);
10799   freeAsmop (right, NULL, ic, TRUE);
10800 }
10801
10802 /*-----------------------------------------------------------------*/
10803 /* genGenPointerSet - set value from generic pointer space         */
10804 /*-----------------------------------------------------------------*/
10805 static void
10806 genGenPointerSet (operand * right,
10807                   operand * result, iCode * ic, iCode * pi)
10808 {
10809   int size, offset;
10810   sym_link *retype = getSpec (operandType (right));
10811   sym_link *letype = getSpec (operandType (result));
10812
10813   D (emitcode (";", "genGenPointerSet"));
10814
10815   aopOp (result, ic, FALSE);
10816   loadDptrFromOperand (result, TRUE);
10817
10818   /* so dptr now contains the address */
10819   aopOp (right, ic, FALSE);
10820
10821   /* if bit then unpack */
10822   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10823     {
10824       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10825     }
10826   else
10827     {
10828       size = AOP_SIZE (right);
10829       offset = 0;
10830
10831       while (size--)
10832         {
10833           char *l = aopGet (right, offset++, FALSE, FALSE);
10834           MOVA (l);
10835           emitcode ("lcall", "__gptrput");
10836           if (size || pi)
10837             emitcode ("inc", "dptr");
10838         }
10839     }
10840
10841   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10842     aopPut (result, "dpl", 0);
10843     aopPut (result, "dph", 1);
10844     pi->generated=1;
10845   }
10846   freeAsmop (result, NULL, ic, TRUE);
10847   freeAsmop (right, NULL, ic, TRUE);
10848 }
10849
10850 /*-----------------------------------------------------------------*/
10851 /* genPointerSet - stores the value into a pointer location        */
10852 /*-----------------------------------------------------------------*/
10853 static void
10854 genPointerSet (iCode * ic, iCode *pi)
10855 {
10856   operand *right, *result;
10857   sym_link *type, *etype;
10858   int p_type;
10859
10860   D (emitcode (";", "genPointerSet"));
10861
10862   right = IC_RIGHT (ic);
10863   result = IC_RESULT (ic);
10864
10865   /* depending on the type of pointer we need to
10866      move it to the correct pointer register */
10867   type = operandType (result);
10868   etype = getSpec (type);
10869   /* if left is of type of pointer then it is simple */
10870   if (IS_PTR (type) && !IS_FUNC (type->next))
10871     {
10872       p_type = DCL_TYPE (type);
10873     }
10874   else
10875     {
10876       /* we have to go by the storage class */
10877       p_type = PTR_TYPE (SPEC_OCLS (etype));
10878     }
10879
10880   /* special case when cast remat */
10881   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10882       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10883           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10884           type = operandType (result);
10885           p_type = DCL_TYPE (type);
10886   }
10887
10888   /* now that we have the pointer type we assign
10889      the pointer values */
10890   switch (p_type)
10891     {
10892
10893     case POINTER:
10894     case IPOINTER:
10895       genNearPointerSet (right, result, ic, pi);
10896       break;
10897
10898     case PPOINTER:
10899       genPagedPointerSet (right, result, ic, pi);
10900       break;
10901
10902     case FPOINTER:
10903       genFarPointerSet (right, result, ic, pi);
10904       break;
10905
10906     case GPOINTER:
10907       genGenPointerSet (right, result, ic, pi);
10908       break;
10909
10910     default:
10911       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10912               "genPointerSet: illegal pointer type");
10913     }
10914 }
10915
10916 /*-----------------------------------------------------------------*/
10917 /* genIfx - generate code for Ifx statement                        */
10918 /*-----------------------------------------------------------------*/
10919 static void
10920 genIfx (iCode * ic, iCode * popIc)
10921 {
10922   operand *cond = IC_COND (ic);
10923   int isbit = 0;
10924   char *dup = NULL;
10925
10926   D (emitcode (";", "genIfx"));
10927
10928   aopOp (cond, ic, FALSE);
10929
10930   /* get the value into acc */
10931   if (AOP_TYPE (cond) != AOP_CRY)
10932     {
10933       toBoolean (cond);
10934     }
10935   else
10936     {
10937       isbit = 1;
10938       if (AOP(cond)->aopu.aop_dir)
10939         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10940     }
10941
10942   /* the result is now in the accumulator or a directly addressable bit */
10943   freeAsmop (cond, NULL, ic, TRUE);
10944
10945   /* if there was something to be popped then do it */
10946   if (popIc)
10947     genIpop (popIc);
10948
10949   /* if the condition is a bit variable */
10950   if (isbit && dup)
10951     genIfxJump(ic, dup, NULL, NULL, NULL);
10952   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10953     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10954   else if (isbit && !IS_ITEMP (cond))
10955     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10956   else
10957     genIfxJump (ic, "a", NULL, NULL, NULL);
10958
10959   ic->generated = 1;
10960 }
10961
10962 /*-----------------------------------------------------------------*/
10963 /* genAddrOf - generates code for address of                       */
10964 /*-----------------------------------------------------------------*/
10965 static void
10966 genAddrOf (iCode * ic)
10967 {
10968   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10969   int size, offset;
10970
10971   D (emitcode (";", "genAddrOf"));
10972
10973   aopOp (IC_RESULT (ic), ic, FALSE);
10974
10975   /* if the operand is on the stack then we
10976      need to get the stack offset of this
10977      variable */
10978   if (sym->onStack)
10979     {
10980       /* if it has an offset then we need to compute it */
10981       if (sym->stack)
10982         {
10983           int stack_offset = ((sym->stack < 0) ?
10984                               ((char) (sym->stack - _G.nRegsSaved)) :
10985                               ((char) sym->stack)) & 0xff;
10986           if ((abs(stack_offset) == 1) &&
10987               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10988               !isOperandVolatile (IC_RESULT (ic), FALSE))
10989             {
10990               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10991               if (stack_offset > 0)
10992                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10993               else
10994                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10995             }
10996           else
10997             {
10998               emitcode ("mov", "a,%s", SYM_BP (sym));
10999               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11000               aopPut (IC_RESULT (ic), "a", 0);
11001             }
11002         }
11003       else
11004         {
11005           /* we can just move _bp */
11006           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11007         }
11008       /* fill the result with zero */
11009       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11010
11011       offset = 1;
11012       while (size--)
11013         {
11014           aopPut (IC_RESULT (ic), zero, offset++);
11015         }
11016       goto release;
11017     }
11018
11019   /* object not on stack then we need the name */
11020   size = AOP_SIZE (IC_RESULT (ic));
11021   offset = 0;
11022
11023   while (size--)
11024     {
11025       char s[SDCC_NAME_MAX];
11026       if (offset)
11027         sprintf (s, "#(%s >> %d)",
11028                  sym->rname,
11029                  offset * 8);
11030       else
11031         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11032       aopPut (IC_RESULT (ic), s, offset++);
11033     }
11034
11035 release:
11036   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11037
11038 }
11039
11040 /*-----------------------------------------------------------------*/
11041 /* genFarFarAssign - assignment when both are in far space         */
11042 /*-----------------------------------------------------------------*/
11043 static void
11044 genFarFarAssign (operand * result, operand * right, iCode * ic)
11045 {
11046   int size = AOP_SIZE (right);
11047   int offset = 0;
11048   char *l;
11049
11050   D (emitcode (";", "genFarFarAssign"));
11051
11052   /* first push the right side on to the stack */
11053   while (size--)
11054     {
11055       l = aopGet (right, offset++, FALSE, FALSE);
11056       MOVA (l);
11057       emitcode ("push", "acc");
11058     }
11059
11060   freeAsmop (right, NULL, ic, FALSE);
11061   /* now assign DPTR to result */
11062   aopOp (result, ic, FALSE);
11063   size = AOP_SIZE (result);
11064   while (size--)
11065     {
11066       emitcode ("pop", "acc");
11067       aopPut (result, "a", --offset);
11068     }
11069   freeAsmop (result, NULL, ic, FALSE);
11070 }
11071
11072 /*-----------------------------------------------------------------*/
11073 /* genAssign - generate code for assignment                        */
11074 /*-----------------------------------------------------------------*/
11075 static void
11076 genAssign (iCode * ic)
11077 {
11078   operand *result, *right;
11079   int size, offset;
11080   unsigned long lit = 0L;
11081
11082   D (emitcode (";", "genAssign"));
11083
11084   result = IC_RESULT (ic);
11085   right = IC_RIGHT (ic);
11086
11087   /* if they are the same */
11088   if (operandsEqu (result, right) &&
11089       !isOperandVolatile (result, FALSE) &&
11090       !isOperandVolatile (right, FALSE))
11091     return;
11092
11093   aopOp (right, ic, FALSE);
11094
11095   /* special case both in far space */
11096   if (AOP_TYPE (right) == AOP_DPTR &&
11097       IS_TRUE_SYMOP (result) &&
11098       isOperandInFarSpace (result))
11099     {
11100       genFarFarAssign (result, right, ic);
11101       return;
11102     }
11103
11104   aopOp (result, ic, TRUE);
11105
11106   /* if they are the same registers */
11107   if (sameRegs (AOP (right), AOP (result)) &&
11108       !isOperandVolatile (result, FALSE) &&
11109       !isOperandVolatile (right, FALSE))
11110     goto release;
11111
11112   /* if the result is a bit */
11113   if (AOP_TYPE (result) == AOP_CRY)
11114     {
11115       assignBit (result, right);
11116       goto release;
11117     }
11118
11119   /* bit variables done */
11120   /* general case */
11121   size = AOP_SIZE (result);
11122   offset = 0;
11123   if (AOP_TYPE (right) == AOP_LIT)
11124     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11125
11126   if ((size > 1) &&
11127       (AOP_TYPE (result) != AOP_REG) &&
11128       (AOP_TYPE (right) == AOP_LIT) &&
11129       !IS_FLOAT (operandType (right)) &&
11130       (lit < 256L))
11131     {
11132       while ((size) && (lit))
11133         {
11134           aopPut (result,
11135                   aopGet (right, offset, FALSE, FALSE),
11136                   offset);
11137           lit >>= 8;
11138           offset++;
11139           size--;
11140         }
11141       /* And now fill the rest with zeros. */
11142       if (size)
11143         {
11144           emitcode ("clr", "a");
11145         }
11146       while (size--)
11147         {
11148           aopPut (result, "a", offset);
11149           offset++;
11150         }
11151     }
11152   else
11153     {
11154       while (size--)
11155         {
11156           aopPut (result,
11157                   aopGet (right, offset, FALSE, FALSE),
11158                   offset);
11159           offset++;
11160         }
11161     }
11162
11163 release:
11164   freeAsmop (result, NULL, ic, TRUE);
11165   freeAsmop (right, NULL, ic, TRUE);
11166 }
11167
11168 /*-----------------------------------------------------------------*/
11169 /* genJumpTab - generates code for jump table                      */
11170 /*-----------------------------------------------------------------*/
11171 static void
11172 genJumpTab (iCode * ic)
11173 {
11174   symbol *jtab,*jtablo,*jtabhi;
11175   char *l;
11176   unsigned int count;
11177
11178   D (emitcode (";", "genJumpTab"));
11179
11180   count = elementsInSet( IC_JTLABELS (ic) );
11181
11182   if( count <= 16 )
11183     {
11184       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11185          if the switch argument is in a register.
11186          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11187       /* Peephole may not convert ljmp to sjmp or ret
11188          labelIsReturnOnly & labelInRange must check
11189          currPl->ic->op != JUMPTABLE */
11190       aopOp (IC_JTCOND (ic), ic, FALSE);
11191       /* get the condition into accumulator */
11192       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11193       MOVA (l);
11194       /* multiply by three */
11195       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11196         {
11197           emitcode ("mov", "b,#3");
11198           emitcode ("mul", "ab");
11199         }
11200       else
11201         {
11202           emitcode ("add", "a,acc");
11203           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11204         }
11205       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11206
11207       jtab = newiTempLabel (NULL);
11208       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11209       emitcode ("jmp", "@a+dptr");
11210       emitLabel (jtab);
11211       /* now generate the jump labels */
11212       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11213            jtab = setNextItem (IC_JTLABELS (ic)))
11214         emitcode ("ljmp", "%05d$", jtab->key + 100);
11215     }
11216   else
11217     {
11218       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11219          if the switch argument is in a register.
11220          For n>6 this algorithm may be more compact */
11221       jtablo = newiTempLabel (NULL);
11222       jtabhi = newiTempLabel (NULL);
11223
11224       /* get the condition into accumulator.
11225          Using b as temporary storage, if register push/pop is needed */
11226       aopOp (IC_JTCOND (ic), ic, FALSE);
11227       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11228       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11229           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11230         {
11231           // (MB) what if B is in use???
11232           wassertl(!BINUSE, "B was in use");
11233           emitcode ("mov", "b,%s", l);
11234           l = "b";
11235         }
11236       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11237       MOVA (l);
11238       if( count <= 112 )
11239         {
11240           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11241           emitcode ("movc", "a,@a+pc");
11242           emitcode ("push", "acc");
11243
11244           MOVA (l);
11245           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11246           emitcode ("movc", "a,@a+pc");
11247           emitcode ("push", "acc");
11248         }
11249       else
11250         {
11251           /* this scales up to n<=255, but needs two more bytes
11252              and changes dptr */
11253           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11254           emitcode ("movc", "a,@a+dptr");
11255           emitcode ("push", "acc");
11256
11257           MOVA (l);
11258           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11259           emitcode ("movc", "a,@a+dptr");
11260           emitcode ("push", "acc");
11261         }
11262
11263       emitcode ("ret", "");
11264
11265       /* now generate jump table, LSB */
11266       emitLabel (jtablo);
11267       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11268            jtab = setNextItem (IC_JTLABELS (ic)))
11269         emitcode (".db", "%05d$", jtab->key + 100);
11270
11271       /* now generate jump table, MSB */
11272       emitLabel (jtabhi);
11273       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11274            jtab = setNextItem (IC_JTLABELS (ic)))
11275          emitcode (".db", "%05d$>>8", jtab->key + 100);
11276     }
11277 }
11278
11279 /*-----------------------------------------------------------------*/
11280 /* genCast - gen code for casting                                  */
11281 /*-----------------------------------------------------------------*/
11282 static void
11283 genCast (iCode * ic)
11284 {
11285   operand *result = IC_RESULT (ic);
11286   sym_link *ctype = operandType (IC_LEFT (ic));
11287   sym_link *rtype = operandType (IC_RIGHT (ic));
11288   operand *right = IC_RIGHT (ic);
11289   int size, offset;
11290
11291   D (emitcode (";", "genCast"));
11292
11293   /* if they are equivalent then do nothing */
11294   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11295     return;
11296
11297   aopOp (right, ic, FALSE);
11298   aopOp (result, ic, FALSE);
11299
11300   /* if the result is a bit (and not a bitfield) */
11301   if (IS_BIT (OP_SYMBOL (result)->type))
11302     {
11303       assignBit (result, right);
11304       goto release;
11305     }
11306
11307   /* if they are the same size : or less */
11308   if (AOP_SIZE (result) <= AOP_SIZE (right))
11309     {
11310
11311       /* if they are in the same place */
11312       if (sameRegs (AOP (right), AOP (result)))
11313         goto release;
11314
11315       /* if they in different places then copy */
11316       size = AOP_SIZE (result);
11317       offset = 0;
11318       while (size--)
11319         {
11320           aopPut (result,
11321                   aopGet (right, offset, FALSE, FALSE),
11322                   offset);
11323           offset++;
11324         }
11325       goto release;
11326     }
11327
11328   /* if the result is of type pointer */
11329   if (IS_PTR (ctype))
11330     {
11331
11332       int p_type;
11333       sym_link *type = operandType (right);
11334       sym_link *etype = getSpec (type);
11335
11336       /* pointer to generic pointer */
11337       if (IS_GENPTR (ctype))
11338         {
11339           if (IS_PTR (type))
11340             {
11341               p_type = DCL_TYPE (type);
11342             }
11343           else
11344             {
11345               if (SPEC_SCLS(etype)==S_REGISTER) {
11346                 // let's assume it is a generic pointer
11347                 p_type=GPOINTER;
11348               } else {
11349                 /* we have to go by the storage class */
11350                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11351               }
11352             }
11353
11354           /* the first two bytes are known */
11355           size = GPTRSIZE - 1;
11356           offset = 0;
11357           while (size--)
11358             {
11359               aopPut (result,
11360                       aopGet (right, offset, FALSE, FALSE),
11361                       offset);
11362               offset++;
11363             }
11364           /* the last byte depending on type */
11365             {
11366                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11367                 char gpValStr[10];
11368
11369                 if (gpVal == -1)
11370                 {
11371                     // pointerTypeToGPByte will have bitched.
11372                     exit(1);
11373                 }
11374
11375                 sprintf(gpValStr, "#0x%x", gpVal);
11376                 aopPut (result, gpValStr, GPTRSIZE - 1);
11377             }
11378           goto release;
11379         }
11380
11381       /* just copy the pointers */
11382       size = AOP_SIZE (result);
11383       offset = 0;
11384       while (size--)
11385         {
11386           aopPut (result,
11387                   aopGet (right, offset, FALSE, FALSE),
11388                   offset);
11389           offset++;
11390         }
11391       goto release;
11392     }
11393
11394   /* so we now know that the size of destination is greater
11395      than the size of the source */
11396   /* we move to result for the size of source */
11397   size = AOP_SIZE (right);
11398   offset = 0;
11399   while (size--)
11400     {
11401       aopPut (result,
11402               aopGet (right, offset, FALSE, FALSE),
11403               offset);
11404       offset++;
11405     }
11406
11407   /* now depending on the sign of the source && destination */
11408   size = AOP_SIZE (result) - AOP_SIZE (right);
11409   /* if unsigned or not an integral type */
11410   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11411     {
11412       while (size--)
11413         aopPut (result, zero, offset++);
11414     }
11415   else
11416     {
11417       /* we need to extend the sign :{ */
11418       char *l = aopGet (right, AOP_SIZE (right) - 1,
11419                         FALSE, FALSE);
11420       MOVA (l);
11421       emitcode ("rlc", "a");
11422       emitcode ("subb", "a,acc");
11423       while (size--)
11424         aopPut (result, "a", offset++);
11425     }
11426
11427   /* we are done hurray !!!! */
11428
11429 release:
11430   freeAsmop (result, NULL, ic, TRUE);
11431   freeAsmop (right, NULL, ic, TRUE);
11432 }
11433
11434 /*-----------------------------------------------------------------*/
11435 /* genDjnz - generate decrement & jump if not zero instrucion      */
11436 /*-----------------------------------------------------------------*/
11437 static int
11438 genDjnz (iCode * ic, iCode * ifx)
11439 {
11440   symbol *lbl, *lbl1;
11441   if (!ifx)
11442     return 0;
11443
11444   /* if the if condition has a false label
11445      then we cannot save */
11446   if (IC_FALSE (ifx))
11447     return 0;
11448
11449   /* if the minus is not of the form a = a - 1 */
11450   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11451       !IS_OP_LITERAL (IC_RIGHT (ic)))
11452     return 0;
11453
11454   if (operandLitValue (IC_RIGHT (ic)) != 1)
11455     return 0;
11456
11457   /* if the size of this greater than one then no
11458      saving */
11459   if (getSize (operandType (IC_RESULT (ic))) > 1)
11460     return 0;
11461
11462   /* otherwise we can save BIG */
11463
11464   D (emitcode (";", "genDjnz"));
11465
11466   lbl = newiTempLabel (NULL);
11467   lbl1 = newiTempLabel (NULL);
11468
11469   aopOp (IC_RESULT (ic), ic, FALSE);
11470
11471   if (AOP_NEEDSACC(IC_RESULT(ic)))
11472   {
11473       /* If the result is accessed indirectly via
11474        * the accumulator, we must explicitly write
11475        * it back after the decrement.
11476        */
11477       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11478
11479       if (strcmp(rByte, "a"))
11480       {
11481            /* Something is hopelessly wrong */
11482            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11483                    __FILE__, __LINE__);
11484            /* We can just give up; the generated code will be inefficient,
11485             * but what the hey.
11486             */
11487            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11488            return 0;
11489       }
11490       emitcode ("dec", "%s", rByte);
11491       aopPut (IC_RESULT (ic), rByte, 0);
11492       emitcode ("jnz", "%05d$", lbl->key + 100);
11493   }
11494   else if (IS_AOP_PREG (IC_RESULT (ic)))
11495     {
11496       emitcode ("dec", "%s",
11497                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11498       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11499       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11500       ifx->generated = 1;
11501       emitcode ("jnz", "%05d$", lbl->key + 100);
11502     }
11503   else
11504     {
11505       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11506                 lbl->key + 100);
11507     }
11508   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11509   emitLabel (lbl);
11510   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11511   emitLabel (lbl1);
11512
11513   if (!ifx->generated)
11514       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11515   ifx->generated = 1;
11516   return 1;
11517 }
11518
11519 /*-----------------------------------------------------------------*/
11520 /* genReceive - generate code for a receive iCode                  */
11521 /*-----------------------------------------------------------------*/
11522 static void
11523 genReceive (iCode * ic)
11524 {
11525   int size = getSize (operandType (IC_RESULT (ic)));
11526   int offset = 0;
11527
11528   D (emitcode (";", "genReceive"));
11529
11530   if (ic->argreg == 1)
11531     { /* first parameter */
11532       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11533            isOperandInPagedSpace (IC_RESULT (ic))) &&
11534           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11535            IS_TRUE_SYMOP (IC_RESULT (ic))))
11536         {
11537           regs *tempRegs[4];
11538           int receivingA = 0;
11539           int roffset = 0;
11540
11541           for (offset = 0; offset<size; offset++)
11542             if (!strcmp (fReturn[offset], "a"))
11543               receivingA = 1;
11544
11545           if (!receivingA)
11546             {
11547               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11548                 {
11549                   for (offset = size-1; offset>0; offset--)
11550                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11551                   emitcode("mov","a,%s", fReturn[0]);
11552                   _G.accInUse++;
11553                   aopOp (IC_RESULT (ic), ic, FALSE);
11554                   _G.accInUse--;
11555                   aopPut (IC_RESULT (ic), "a", offset);
11556                   for (offset = 1; offset<size; offset++)
11557                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11558                   goto release;
11559                 }
11560             }
11561           else
11562             {
11563               if (getTempRegs(tempRegs, size, ic))
11564                 {
11565                   for (offset = 0; offset<size; offset++)
11566                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11567                   aopOp (IC_RESULT (ic), ic, FALSE);
11568                   for (offset = 0; offset<size; offset++)
11569                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11570                   goto release;
11571                 }
11572             }
11573
11574           offset = fReturnSizeMCS51 - size;
11575           while (size--)
11576             {
11577               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11578                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11579               offset++;
11580             }
11581           aopOp (IC_RESULT (ic), ic, FALSE);
11582           size = AOP_SIZE (IC_RESULT (ic));
11583           offset = 0;
11584           while (size--)
11585             {
11586               emitcode ("pop", "acc");
11587               aopPut (IC_RESULT (ic), "a", offset++);
11588             }
11589         }
11590       else
11591         {
11592           _G.accInUse++;
11593           aopOp (IC_RESULT (ic), ic, FALSE);
11594           _G.accInUse--;
11595           assignResultValue (IC_RESULT (ic), NULL);
11596         }
11597     }
11598   else if (ic->argreg > 12)
11599     { /* bit parameters */
11600       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11601         {
11602           aopOp (IC_RESULT (ic), ic, FALSE);
11603           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11604           outBitC(IC_RESULT (ic));
11605         }
11606     }
11607   else
11608     { /* other parameters */
11609       int rb1off ;
11610       aopOp (IC_RESULT (ic), ic, FALSE);
11611       rb1off = ic->argreg;
11612       while (size--)
11613         {
11614           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11615         }
11616     }
11617
11618 release:
11619   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11620 }
11621
11622 /*-----------------------------------------------------------------*/
11623 /* genDummyRead - generate code for dummy read of volatiles        */
11624 /*-----------------------------------------------------------------*/
11625 static void
11626 genDummyRead (iCode * ic)
11627 {
11628   operand *op;
11629   int size, offset;
11630
11631   D (emitcode(";", "genDummyRead"));
11632
11633   op = IC_RIGHT (ic);
11634   if (op && IS_SYMOP (op))
11635     {
11636       aopOp (op, ic, FALSE);
11637
11638       /* if the result is a bit */
11639       if (AOP_TYPE (op) == AOP_CRY)
11640         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11641       else
11642         {
11643           /* bit variables done */
11644           /* general case */
11645           size = AOP_SIZE (op);
11646           offset = 0;
11647           while (size--)
11648           {
11649             MOVA (aopGet (op, offset, FALSE, FALSE));
11650             offset++;
11651           }
11652         }
11653
11654       freeAsmop (op, NULL, ic, TRUE);
11655     }
11656
11657   op = IC_LEFT (ic);
11658   if (op && IS_SYMOP (op))
11659     {
11660       aopOp (op, ic, FALSE);
11661
11662       /* if the result is a bit */
11663       if (AOP_TYPE (op) == AOP_CRY)
11664         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11665       else
11666         {
11667           /* bit variables done */
11668           /* general case */
11669           size = AOP_SIZE (op);
11670           offset = 0;
11671           while (size--)
11672           {
11673             MOVA (aopGet (op, offset, FALSE, FALSE));
11674             offset++;
11675           }
11676         }
11677
11678       freeAsmop (op, NULL, ic, TRUE);
11679     }
11680 }
11681
11682 /*-----------------------------------------------------------------*/
11683 /* genCritical - generate code for start of a critical sequence    */
11684 /*-----------------------------------------------------------------*/
11685 static void
11686 genCritical (iCode *ic)
11687 {
11688   symbol *tlbl = newiTempLabel (NULL);
11689
11690   D (emitcode(";", "genCritical"));
11691
11692   if (IC_RESULT (ic))
11693     {
11694       aopOp (IC_RESULT (ic), ic, TRUE);
11695       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11696       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11697       aopPut (IC_RESULT (ic), zero, 0);
11698       emitLabel (tlbl);
11699       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11700     }
11701   else
11702     {
11703       emitcode ("setb", "c");
11704       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11705       emitcode ("clr", "c");
11706       emitLabel (tlbl);
11707       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11708     }
11709 }
11710
11711 /*-----------------------------------------------------------------*/
11712 /* genEndCritical - generate code for end of a critical sequence   */
11713 /*-----------------------------------------------------------------*/
11714 static void
11715 genEndCritical (iCode *ic)
11716 {
11717   D(emitcode(";     genEndCritical",""));
11718
11719   if (IC_RIGHT (ic))
11720     {
11721       aopOp (IC_RIGHT (ic), ic, FALSE);
11722       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11723         {
11724           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11725           emitcode ("mov", "ea,c");
11726         }
11727       else
11728         {
11729           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11730             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11731           emitcode ("rrc", "a");
11732           emitcode ("mov", "ea,c");
11733         }
11734       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11735     }
11736   else
11737     {
11738       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11739       emitcode ("mov", "ea,c");
11740     }
11741 }
11742
11743 /*-----------------------------------------------------------------*/
11744 /* gen51Code - generate code for 8051 based controllers            */
11745 /*-----------------------------------------------------------------*/
11746 void
11747 gen51Code (iCode * lic)
11748 {
11749   iCode *ic;
11750   int cln = 0;
11751   /* int cseq = 0; */
11752
11753   _G.currentFunc = NULL;
11754   lineHead = lineCurr = NULL;
11755
11756   /* print the allocation information */
11757   if (allocInfo && currFunc)
11758     printAllocInfo (currFunc, codeOutBuf);
11759   /* if debug information required */
11760   if (options.debug && currFunc)
11761     {
11762       debugFile->writeFunction (currFunc, lic);
11763     }
11764   /* stack pointer name */
11765   if (options.useXstack)
11766     spname = "_spx";
11767   else
11768     spname = "sp";
11769
11770
11771   for (ic = lic; ic; ic = ic->next)
11772     {
11773       _G.current_iCode = ic;
11774
11775       if (ic->lineno && cln != ic->lineno)
11776         {
11777           if (options.debug)
11778             {
11779               debugFile->writeCLine (ic);
11780             }
11781           if (!options.noCcodeInAsm) {
11782             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
11783                       printCLine(ic->filename, ic->lineno));
11784           }
11785           cln = ic->lineno;
11786         }
11787       #if 0
11788       if (ic->seqPoint && ic->seqPoint != cseq)
11789         {
11790           emitcode ("", "; sequence point %d", ic->seqPoint);
11791           cseq = ic->seqPoint;
11792         }
11793       #endif
11794       if (options.iCodeInAsm) {
11795         char regsInUse[80];
11796         int i;
11797         char *iLine;
11798
11799         #if 0
11800         for (i=0; i<8; i++) {
11801           sprintf (&regsInUse[i],
11802                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11803         regsInUse[i]=0;
11804         #else
11805         strcpy (regsInUse, "--------");
11806         for (i=0; i < 8; i++) {
11807           if (bitVectBitValue (ic->rMask, i))
11808             {
11809               int offset = regs8051[i].offset;
11810               regsInUse[offset] = offset + '0'; /* show rMask */
11811             }
11812         #endif
11813         }
11814         iLine = printILine(ic);
11815         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11816         dbuf_free(iLine);
11817       }
11818       /* if the result is marked as
11819          spilt and rematerializable or code for
11820          this has already been generated then
11821          do nothing */
11822       if (resultRemat (ic) || ic->generated)
11823         continue;
11824
11825       /* depending on the operation */
11826       switch (ic->op)
11827         {
11828         case '!':
11829           genNot (ic);
11830           break;
11831
11832         case '~':
11833           genCpl (ic);
11834           break;
11835
11836         case UNARYMINUS:
11837           genUminus (ic);
11838           break;
11839
11840         case IPUSH:
11841           genIpush (ic);
11842           break;
11843
11844         case IPOP:
11845           /* IPOP happens only when trying to restore a
11846              spilt live range, if there is an ifx statement
11847              following this pop then the if statement might
11848              be using some of the registers being popped which
11849              would destory the contents of the register so
11850              we need to check for this condition and handle it */
11851           if (ic->next &&
11852               ic->next->op == IFX &&
11853               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11854             genIfx (ic->next, ic);
11855           else
11856             genIpop (ic);
11857           break;
11858
11859         case CALL:
11860           genCall (ic);
11861           break;
11862
11863         case PCALL:
11864           genPcall (ic);
11865           break;
11866
11867         case FUNCTION:
11868           genFunction (ic);
11869           break;
11870
11871         case ENDFUNCTION:
11872           genEndFunction (ic);
11873           break;
11874
11875         case RETURN:
11876           genRet (ic);
11877           break;
11878
11879         case LABEL:
11880           genLabel (ic);
11881           break;
11882
11883         case GOTO:
11884           genGoto (ic);
11885           break;
11886
11887         case '+':
11888           genPlus (ic);
11889           break;
11890
11891         case '-':
11892           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11893             genMinus (ic);
11894           break;
11895
11896         case '*':
11897           genMult (ic);
11898           break;
11899
11900         case '/':
11901           genDiv (ic);
11902           break;
11903
11904         case '%':
11905           genMod (ic);
11906           break;
11907
11908         case '>':
11909           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11910           break;
11911
11912         case '<':
11913           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11914           break;
11915
11916         case LE_OP:
11917         case GE_OP:
11918         case NE_OP:
11919
11920           /* note these two are xlated by algebraic equivalence
11921              in decorateType() in SDCCast.c */
11922           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11923                   "got '>=' or '<=' shouldn't have come here");
11924           break;
11925
11926         case EQ_OP:
11927           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11928           break;
11929
11930         case AND_OP:
11931           genAndOp (ic);
11932           break;
11933
11934         case OR_OP:
11935           genOrOp (ic);
11936           break;
11937
11938         case '^':
11939           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11940           break;
11941
11942         case '|':
11943           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11944           break;
11945
11946         case BITWISEAND:
11947           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11948           break;
11949
11950         case INLINEASM:
11951           genInline (ic);
11952           break;
11953
11954         case RRC:
11955           genRRC (ic);
11956           break;
11957
11958         case RLC:
11959           genRLC (ic);
11960           break;
11961
11962         case GETHBIT:
11963           genGetHbit (ic);
11964           break;
11965
11966         case GETABIT:
11967           genGetAbit (ic);
11968           break;
11969
11970         case GETBYTE:
11971           genGetByte (ic);
11972           break;
11973
11974         case GETWORD:
11975           genGetWord (ic);
11976           break;
11977
11978         case LEFT_OP:
11979           genLeftShift (ic);
11980           break;
11981
11982         case RIGHT_OP:
11983           genRightShift (ic);
11984           break;
11985
11986         case GET_VALUE_AT_ADDRESS:
11987           genPointerGet (ic,
11988                          hasInc (IC_LEFT (ic), ic,
11989                                  getSize (operandType (IC_RESULT (ic)))),
11990                          ifxForOp (IC_RESULT (ic), ic) );
11991           break;
11992
11993         case '=':
11994           if (POINTER_SET (ic))
11995             genPointerSet (ic,
11996                            hasInc (IC_RESULT (ic), ic,
11997                                    getSize (operandType (IC_RIGHT (ic)))));
11998           else
11999             genAssign (ic);
12000           break;
12001
12002         case IFX:
12003           genIfx (ic, NULL);
12004           break;
12005
12006         case ADDRESS_OF:
12007           genAddrOf (ic);
12008           break;
12009
12010         case JUMPTABLE:
12011           genJumpTab (ic);
12012           break;
12013
12014         case CAST:
12015           genCast (ic);
12016           break;
12017
12018         case RECEIVE:
12019           genReceive (ic);
12020           break;
12021
12022         case SEND:
12023           addSet (&_G.sendSet, ic);
12024           break;
12025
12026         case DUMMY_READ_VOLATILE:
12027           genDummyRead (ic);
12028           break;
12029
12030         case CRITICAL:
12031           genCritical (ic);
12032           break;
12033
12034         case ENDCRITICAL:
12035           genEndCritical (ic);
12036           break;
12037
12038         case SWAP:
12039           genSwap (ic);
12040           break;
12041
12042         default:
12043           ic = ic;
12044         }
12045     }
12046
12047   _G.current_iCode = NULL;
12048
12049   /* now we are ready to call the
12050      peep hole optimizer */
12051   if (!options.nopeep)
12052     peepHole (&lineHead);
12053
12054   /* now do the actual printing */
12055   printLine (lineHead, codeOutBuf);
12056   return;
12057 }