* doc/sdccman.lyx: documented sfr16/sfr32,
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.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 "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0x00";
55 static char *one = "#0x01";
56 static char *spname;
57
58 char *fReturn8051[] =
59 {"dpl", "dph", "b", "a"};
60 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
61 char **fReturn = fReturn8051;
62 static char *accUse[] =
63 {"a", "b"};
64
65 static unsigned short rbank = -1;
66
67 #define AOP(op) op->aop
68 #define AOP_TYPE(op) AOP(op)->type
69 #define AOP_SIZE(op) AOP(op)->size
70 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
71                        AOP_TYPE(x) == AOP_R0))
72
73 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
74                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
75
76 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
77                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
78                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
79
80
81 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
82
83 #define R0INB   _G.bu.bs.r0InB
84 #define R1INB   _G.bu.bs.r1InB
85 #define OPINB   _G.bu.bs.OpInB
86 #define BINUSE  _G.bu.BInUse
87
88 static struct
89   {
90     short r0Pushed;
91     short r1Pushed;
92     union
93       {
94         struct
95           {
96             short r0InB : 2;//2 so we can see it overflow
97             short r1InB : 2;//2 so we can see it overflow
98             short OpInB : 2;//2 so we can see it overflow
99           } bs;
100         short BInUse;
101       } bu;
102     short accInUse;
103     short inLine;
104     short debugLine;
105     short nRegsSaved;
106     set *sendSet;
107     iCode *current_iCode;
108     symbol *currentFunc;
109   }
110 _G;
111
112 static char *rb1regs[] = {
113     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
114 };
115
116 extern int mcs51_ptrRegReq;
117 extern int mcs51_nRegs;
118 extern FILE *codeOutFile;
119 static void saveRBank (int, iCode *, bool);
120
121 #define RESULTONSTACK(x) \
122                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
123                          IC_RESULT(x)->aop->type == AOP_STK )
124
125 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
126 #define CLRC     emitcode("clr","c")
127 #define SETC     emitcode("setb","c")
128
129 static lineNode *lineHead = NULL;
130 static lineNode *lineCurr = NULL;
131
132 static unsigned char SLMask[] =
133 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
134  0xE0, 0xC0, 0x80, 0x00};
135 static unsigned char SRMask[] =
136 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
137  0x07, 0x03, 0x01, 0x00};
138
139 #define LSB     0
140 #define MSB16   1
141 #define MSB24   2
142 #define MSB32   3
143
144 /*-----------------------------------------------------------------*/
145 /* emitcode - writes the code into a file : for now it is simple    */
146 /*-----------------------------------------------------------------*/
147 static void
148 emitcode (char *inst, const char *fmt,...)
149 {
150   va_list ap;
151   char lb[INITIAL_INLINEASM];
152   char *lbp = lb;
153
154   va_start (ap, fmt);
155
156   if (inst && *inst)
157     {
158       if (fmt && *fmt)
159           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
160       else
161           SNPRINTF (lb, sizeof(lb), "%s", inst);
162       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
163     }
164   else
165       tvsprintf (lb, sizeof(lb), fmt, ap);
166
167   while (isspace (*lbp))
168       lbp++;
169
170   if (lbp && *lbp)
171       lineCurr = (lineCurr ?
172                   connectLine (lineCurr, newLineNode (lb)) :
173                   (lineHead = newLineNode (lb)));
174   lineCurr->isInline = _G.inLine;
175   lineCurr->isDebug = _G.debugLine;
176   lineCurr->ic = _G.current_iCode;
177   lineCurr->isComment = (*lbp==';');
178   va_end (ap);
179 }
180
181 /*-----------------------------------------------------------------*/
182 /* mcs51_emitDebuggerSymbol - associate the current code location  */
183 /*   with a debugger symbol                                        */
184 /*-----------------------------------------------------------------*/
185 void
186 mcs51_emitDebuggerSymbol (char * debugSym)
187 {
188   _G.debugLine = 1;
189   emitcode ("", "%s ==.", debugSym);
190   _G.debugLine = 0;
191 }
192
193 /*-----------------------------------------------------------------*/
194 /* mova - moves specified value into accumulator                   */
195 /*-----------------------------------------------------------------*/
196 static void
197 mova (const char *x)
198 {
199   /* do some early peephole optimization */
200   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
201     return;
202
203   emitcode("mov","a,%s", x);
204 }
205
206 /*-----------------------------------------------------------------*/
207 /* pushB - saves register B if necessary                           */
208 /*-----------------------------------------------------------------*/
209 static bool
210 pushB (void)
211 {
212   bool pushedB = FALSE;
213
214   if (BINUSE)
215     {
216       emitcode ("push", "b");
217 //    printf("B was in use !\n");
218       pushedB = TRUE;
219     }
220   else
221     {
222       OPINB++;
223     }
224   return pushedB;
225 }
226
227 /*-----------------------------------------------------------------*/
228 /* popB - restores value of register B if necessary                */
229 /*-----------------------------------------------------------------*/
230 static void
231 popB (bool pushedB)
232 {
233   if (pushedB)
234     {
235       emitcode ("pop", "b");
236     }
237   else
238     {
239       OPINB--;
240     }
241 }
242
243 /*-----------------------------------------------------------------*/
244 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
245 /*-----------------------------------------------------------------*/
246 static regs *
247 getFreePtr (iCode * ic, asmop ** aopp, bool result)
248 {
249   bool r0iu, r1iu;
250   bool r0ou, r1ou;
251
252   /* the logic: if r0 & r1 used in the instruction
253      then we are in trouble otherwise */
254
255   /* first check if r0 & r1 are used by this
256      instruction, in which case we are in trouble */
257   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
258   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
259   if (r0iu && r1iu) {
260       goto endOfWorld;
261     }
262
263   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
264   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
265
266   /* if no usage of r0 then return it */
267   if (!r0iu && !r0ou)
268     {
269       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
270       (*aopp)->type = AOP_R0;
271
272       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
273     }
274
275   /* if no usage of r1 then return it */
276   if (!r1iu && !r1ou)
277     {
278       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
279       (*aopp)->type = AOP_R1;
280
281       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
282     }
283
284   /* now we know they both have usage */
285   /* if r0 not used in this instruction */
286   if (!r0iu)
287     {
288       /* push it if not already pushed */
289       if (ic->op == IPUSH)
290         {
291           emitcode ("mov", "b,%s",
292                     mcs51_regWithIdx (R0_IDX)->dname);
293           R0INB++;
294         }
295       else if (!_G.r0Pushed)
296         {
297           emitcode ("push", "%s",
298                     mcs51_regWithIdx (R0_IDX)->dname);
299           _G.r0Pushed++;
300         }
301
302       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
303       (*aopp)->type = AOP_R0;
304
305       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
306     }
307
308   /* if r1 not used then */
309
310   if (!r1iu)
311     {
312       /* push it if not already pushed */
313       if (ic->op == IPUSH)
314         {
315           emitcode ("mov", "b,%s",
316                     mcs51_regWithIdx (R1_IDX)->dname);
317           R1INB++;
318         }
319       else if (!_G.r1Pushed)
320         {
321           emitcode ("push", "%s",
322                     mcs51_regWithIdx (R1_IDX)->dname);
323           _G.r1Pushed++;
324         }
325
326       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
327       (*aopp)->type = AOP_R1;
328       return mcs51_regWithIdx (R1_IDX);
329     }
330 endOfWorld:
331   /* I said end of world, but not quite end of world yet */
332   if (result) {
333     /* we can push it on the stack */
334     (*aopp)->type = AOP_STK;
335     return NULL;
336   } else {
337     /* in the case that result AND left AND right needs a pointer reg
338        we can safely use the result's */
339     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
340       (*aopp)->type = AOP_R0;
341       return mcs51_regWithIdx (R0_IDX);
342     }
343     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
344       (*aopp)->type = AOP_R1;
345       return mcs51_regWithIdx (R1_IDX);
346     }
347   }
348
349   /* now this is REALLY the end of the world */
350   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
351           "getFreePtr should never reach here");
352   exit (1);
353 }
354
355
356 /*-----------------------------------------------------------------*/
357 /* getTempRegs - initialize an array of pointers to GPR registers */
358 /*               that are not in use. Returns 1 if the requested   */
359 /*               number of registers were available, 0 otherwise.  */
360 /*-----------------------------------------------------------------*/
361 int
362 getTempRegs(regs **tempRegs, int size, iCode *ic)
363 {
364   bitVect * freeRegs;
365   int i;
366   int offset;
367
368   if (!ic)
369     ic = _G.current_iCode;
370   if (!ic)
371     return 0;
372   if (!_G.currentFunc)
373     return 0;
374
375   freeRegs = newBitVect(8);
376   bitVectSetBit (freeRegs, R2_IDX);
377   bitVectSetBit (freeRegs, R3_IDX);
378   bitVectSetBit (freeRegs, R4_IDX);
379   bitVectSetBit (freeRegs, R5_IDX);
380   bitVectSetBit (freeRegs, R6_IDX);
381   bitVectSetBit (freeRegs, R7_IDX);
382
383   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
384     {
385       bitVect * newfreeRegs;
386       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
387       freeBitVect(freeRegs);
388       freeRegs = newfreeRegs;
389     }
390   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
391
392   offset = 0;
393   for (i=0; i<freeRegs->size; i++)
394     {
395       if (bitVectBitValue(freeRegs,i))
396         tempRegs[offset++] = mcs51_regWithIdx(i);
397       if (offset>=size)
398         {
399           freeBitVect(freeRegs);
400           return 1;
401         }
402     }
403
404   freeBitVect(freeRegs);
405   return 1;
406 }
407
408
409 /*-----------------------------------------------------------------*/
410 /* newAsmop - creates a new asmOp                                  */
411 /*-----------------------------------------------------------------*/
412 static asmop *
413 newAsmop (short type)
414 {
415   asmop *aop;
416
417   aop = Safe_calloc (1, sizeof (asmop));
418   aop->type = type;
419   return aop;
420 }
421
422 /*-----------------------------------------------------------------*/
423 /* pointerCode - returns the code for a pointer type               */
424 /*-----------------------------------------------------------------*/
425 static int
426 pointerCode (sym_link * etype)
427 {
428
429   return PTR_TYPE (SPEC_OCLS (etype));
430
431 }
432
433 /*-----------------------------------------------------------------*/
434 /* leftRightUseAcc - returns size of accumulator use by operands   */
435 /*-----------------------------------------------------------------*/
436 static int
437 leftRightUseAcc(iCode *ic)
438 {
439   operand *op;
440   int size;
441   int accuseSize = 0;
442   int accuse = 0;
443
444   if (!ic)
445     {
446       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
447               "null iCode pointer");
448       return 0;
449     }
450
451   if (ic->op == IFX)
452     {
453       op = IC_COND (ic);
454       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
455         {
456           accuse = 1;
457           size = getSize (OP_SYMBOL (op)->type);
458           if (size>accuseSize)
459             accuseSize = size;
460         }
461     }
462   else if (ic->op == JUMPTABLE)
463     {
464       op = IC_JTCOND (ic);
465       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
466         {
467           accuse = 1;
468           size = getSize (OP_SYMBOL (op)->type);
469           if (size>accuseSize)
470             accuseSize = size;
471         }
472     }
473   else
474     {
475       op = IC_LEFT (ic);
476       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
477         {
478           accuse = 1;
479           size = getSize (OP_SYMBOL (op)->type);
480           if (size>accuseSize)
481             accuseSize = size;
482         }
483       op = IC_RIGHT (ic);
484       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
485         {
486           accuse = 1;
487           size = getSize (OP_SYMBOL (op)->type);
488           if (size>accuseSize)
489             accuseSize = size;
490         }
491     }
492
493   if (accuseSize)
494     return accuseSize;
495   else
496     return accuse;
497 }
498
499 /*-----------------------------------------------------------------*/
500 /* aopForSym - for a true symbol                                   */
501 /*-----------------------------------------------------------------*/
502 static asmop *
503 aopForSym (iCode * ic, symbol * sym, bool result)
504 {
505   asmop *aop;
506   memmap *space;
507
508   wassertl (ic != NULL, "Got a null iCode");
509   wassertl (sym != NULL, "Got a null symbol");
510
511   space = SPEC_OCLS (sym->etype);
512
513   /* if already has one */
514   if (sym->aop)
515     return sym->aop;
516
517   /* assign depending on the storage class */
518   /* if it is on the stack or indirectly addressable */
519   /* space we need to assign either r0 or r1 to it   */
520   if (sym->onStack || sym->iaccess)
521     {
522       sym->aop = aop = newAsmop (0);
523       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
524       aop->size = getSize (sym->type);
525
526       /* now assign the address of the variable to
527          the pointer register */
528       if (aop->type != AOP_STK)
529         {
530
531           if (sym->onStack)
532             {
533               char offset = ((sym->stack < 0) ?
534                          ((char) (sym->stack - _G.nRegsSaved)) :
535                          ((char) sym->stack)) & 0xff;
536
537               if ((offset >= -3) && (offset <= 3))
538                 {
539                   emitcode ("mov", "%s,%s",
540                             aop->aopu.aop_ptr->name, SYM_BP (sym));
541                   while (offset < 0)
542                     {
543                       emitcode ("dec", aop->aopu.aop_ptr->name);
544                       offset++;
545                     }
546                   while (offset > 0)
547                     {
548                       emitcode ("inc", aop->aopu.aop_ptr->name);
549                       offset--;
550                     }
551                 }
552               else
553                 {
554                   if (_G.accInUse || leftRightUseAcc (ic))
555                     emitcode ("push", "acc");
556                   emitcode ("mov", "a,%s", SYM_BP (sym));
557                   emitcode ("add", "a,#0x%02x", offset);
558                   emitcode ("mov", "%s,a",
559                             aop->aopu.aop_ptr->name);
560                   if (_G.accInUse || leftRightUseAcc (ic))
561                     emitcode ("pop", "acc");
562                 }
563             }
564           else
565             emitcode ("mov", "%s,#%s",
566                       aop->aopu.aop_ptr->name,
567                       sym->rname);
568           aop->paged = space->paged;
569         }
570       else
571         aop->aopu.aop_stk = sym->stack;
572       return aop;
573     }
574
575   /* if in bit space */
576   if (IN_BITSPACE (space))
577     {
578       sym->aop = aop = newAsmop (AOP_CRY);
579       aop->aopu.aop_dir = sym->rname;
580       aop->size = getSize (sym->type);
581       return aop;
582     }
583   /* if it is in direct space */
584   if (IN_DIRSPACE (space))
585     {
586       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
587       //printTypeChainRaw(sym->type, NULL);
588       //printf("space = %s\n", space ? space->sname : "NULL");
589       sym->aop = aop = newAsmop (AOP_DIR);
590       aop->aopu.aop_dir = sym->rname;
591       aop->size = getSize (sym->type);
592       return aop;
593     }
594
595   /* special case for a function */
596   if (IS_FUNC (sym->type))
597     {
598       sym->aop = aop = newAsmop (AOP_IMMD);
599       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
600       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
601       aop->size = FPTRSIZE;
602       return aop;
603     }
604
605   /* only remaining is far space */
606   /* in which case DPTR gets the address */
607   sym->aop = aop = newAsmop (AOP_DPTR);
608   emitcode ("mov", "dptr,#%s", sym->rname);
609   aop->size = getSize (sym->type);
610
611   /* if it is in code space */
612   if (IN_CODESPACE (space))
613     aop->code = 1;
614
615   return aop;
616 }
617
618 /*-----------------------------------------------------------------*/
619 /* aopForRemat - rematerialzes an object                           */
620 /*-----------------------------------------------------------------*/
621 static asmop *
622 aopForRemat (symbol * sym)
623 {
624   iCode *ic = sym->rematiCode;
625   asmop *aop = newAsmop (AOP_IMMD);
626   int ptr_type = 0;
627   int val = 0;
628
629   for (;;)
630     {
631       if (ic->op == '+')
632         val += (int) operandLitValue (IC_RIGHT (ic));
633       else if (ic->op == '-')
634         val -= (int) operandLitValue (IC_RIGHT (ic));
635       else if (IS_CAST_ICODE(ic)) {
636               sym_link *from_type = operandType(IC_RIGHT(ic));
637               aop->aopu.aop_immd.from_cast_remat = 1;
638               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
639               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
640               continue ;
641       } else break;
642
643       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
644     }
645
646   if (val)
647     sprintf (buffer, "(%s %c 0x%04x)",
648              OP_SYMBOL (IC_LEFT (ic))->rname,
649              val >= 0 ? '+' : '-',
650              abs (val) & 0xffff);
651   else
652     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
653
654   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
655   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
656   /* set immd2 field if required */
657   if (aop->aopu.aop_immd.from_cast_remat) {
658           sprintf(buffer,"#0x%02x",ptr_type);
659           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
660           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
661   }
662
663   return aop;
664 }
665
666 /*-----------------------------------------------------------------*/
667 /* regsInCommon - two operands have some registers in common       */
668 /*-----------------------------------------------------------------*/
669 static bool
670 regsInCommon (operand * op1, operand * op2)
671 {
672   symbol *sym1, *sym2;
673   int i;
674
675   /* if they have registers in common */
676   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
677     return FALSE;
678
679   sym1 = OP_SYMBOL (op1);
680   sym2 = OP_SYMBOL (op2);
681
682   if (sym1->nRegs == 0 || sym2->nRegs == 0)
683     return FALSE;
684
685   for (i = 0; i < sym1->nRegs; i++)
686     {
687       int j;
688       if (!sym1->regs[i])
689         continue;
690
691       for (j = 0; j < sym2->nRegs; j++)
692         {
693           if (!sym2->regs[j])
694             continue;
695
696           if (sym2->regs[j] == sym1->regs[i])
697             return TRUE;
698         }
699     }
700
701   return FALSE;
702 }
703
704 /*-----------------------------------------------------------------*/
705 /* operandsEqu - equivalent                                        */
706 /*-----------------------------------------------------------------*/
707 static bool
708 operandsEqu (operand * op1, operand * op2)
709 {
710   symbol *sym1, *sym2;
711
712   /* if they're not symbols */
713   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
714     return FALSE;
715
716   sym1 = OP_SYMBOL (op1);
717   sym2 = OP_SYMBOL (op2);
718
719   /* if both are itemps & one is spilt
720      and the other is not then false */
721   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
722       sym1->isspilt != sym2->isspilt)
723     return FALSE;
724
725   /* if they are the same */
726   if (sym1 == sym2)
727     return TRUE;
728
729   /* if they have the same rname */
730   if (sym1->rname[0] && sym2->rname[0]
731       && strcmp (sym1->rname, sym2->rname) == 0)
732     return TRUE;
733
734   /* if left is a tmp & right is not */
735   if (IS_ITEMP (op1) &&
736       !IS_ITEMP (op2) &&
737       sym1->isspilt &&
738       (sym1->usl.spillLoc == sym2))
739     return TRUE;
740
741   if (IS_ITEMP (op2) &&
742       !IS_ITEMP (op1) &&
743       sym2->isspilt &&
744       sym1->level > 0 &&
745       (sym2->usl.spillLoc == sym1))
746     return TRUE;
747
748   return FALSE;
749 }
750
751 /*-----------------------------------------------------------------*/
752 /* sameRegs - two asmops have the same registers                   */
753 /*-----------------------------------------------------------------*/
754 static bool
755 sameRegs (asmop * aop1, asmop * aop2)
756 {
757   int i;
758
759   if (aop1 == aop2)
760     return TRUE;
761
762   if (aop1->type != AOP_REG ||
763       aop2->type != AOP_REG)
764     return FALSE;
765
766   if (aop1->size != aop2->size)
767     return FALSE;
768
769   for (i = 0; i < aop1->size; i++)
770     if (aop1->aopu.aop_reg[i] !=
771         aop2->aopu.aop_reg[i])
772       return FALSE;
773
774   return TRUE;
775 }
776
777 /*-----------------------------------------------------------------*/
778 /* aopOp - allocates an asmop for an operand  :                    */
779 /*-----------------------------------------------------------------*/
780 static void
781 aopOp (operand * op, iCode * ic, bool result)
782 {
783   asmop *aop;
784   symbol *sym;
785   int i;
786
787   if (!op)
788     return;
789
790   /* if this a literal */
791   if (IS_OP_LITERAL (op))
792     {
793       op->aop = aop = newAsmop (AOP_LIT);
794       aop->aopu.aop_lit = op->operand.valOperand;
795       aop->size = getSize (operandType (op));
796       return;
797     }
798
799   /* if already has a asmop then continue */
800   if (op->aop )
801     return;
802
803   /* if the underlying symbol has a aop */
804   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
805     {
806       op->aop = OP_SYMBOL (op)->aop;
807       return;
808     }
809
810   /* if this is a true symbol */
811   if (IS_TRUE_SYMOP (op))
812     {
813       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
814       return;
815     }
816
817   /* this is a temporary : this has
818      only five choices :
819      a) register
820      b) spillocation
821      c) rematerialize
822      d) conditional
823      e) can be a return use only */
824
825   sym = OP_SYMBOL (op);
826
827   /* if the type is a conditional */
828   if (sym->regType == REG_CND)
829     {
830       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
831       aop->size = 0;
832       return;
833     }
834
835   /* if it is spilt then two situations
836      a) is rematerialize
837      b) has a spill location */
838   if (sym->isspilt || sym->nRegs == 0)
839     {
840
841       /* rematerialize it NOW */
842       if (sym->remat)
843         {
844           sym->aop = op->aop = aop =
845             aopForRemat (sym);
846           aop->size = getSize (sym->type);
847           return;
848         }
849
850       if (sym->accuse)
851         {
852           int i;
853           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
854           aop->size = getSize (sym->type);
855           for (i = 0; i < 2; i++)
856             aop->aopu.aop_str[i] = accUse[i];
857           return;
858         }
859
860       if (sym->ruonly)
861         {
862           unsigned i;
863
864           aop = op->aop = sym->aop = newAsmop (AOP_STR);
865           aop->size = getSize (sym->type);
866           for (i = 0; i < fReturnSizeMCS51; i++)
867             aop->aopu.aop_str[i] = fReturn[i];
868           return;
869         }
870
871       if (sym->usl.spillLoc)
872         {
873           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
874             {
875               /* force a new aop if sizes differ */
876               sym->usl.spillLoc->aop = NULL;
877             }
878           sym->aop = op->aop = aop =
879                      aopForSym (ic, sym->usl.spillLoc, result);
880           aop->size = getSize (sym->type);
881           return;
882         }
883
884       /* else must be a dummy iTemp */
885       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
886       aop->size = getSize (sym->type);
887       return;
888     }
889
890   /* must be in a register */
891   sym->aop = op->aop = aop = newAsmop (AOP_REG);
892   aop->size = sym->nRegs;
893   for (i = 0; i < sym->nRegs; i++)
894     aop->aopu.aop_reg[i] = sym->regs[i];
895 }
896
897 /*-----------------------------------------------------------------*/
898 /* freeAsmop - free up the asmop given to an operand               */
899 /*----------------------------------------------------------------*/
900 static void
901 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
902 {
903   asmop *aop;
904
905   if (!op)
906     aop = aaop;
907   else
908     aop = op->aop;
909
910   if (!aop)
911     return;
912
913   if (aop->freed)
914     goto dealloc;
915
916   aop->freed = 1;
917
918   /* depending on the asmop type only three cases need work AOP_RO
919      , AOP_R1 && AOP_STK */
920   switch (aop->type)
921     {
922     case AOP_R0:
923       if (R0INB)
924         {
925           emitcode ("mov", "r0,b");
926           R0INB--;
927         }
928       else if (_G.r0Pushed)
929         {
930           if (pop)
931             {
932               emitcode ("pop", "ar0");
933               _G.r0Pushed--;
934             }
935         }
936       bitVectUnSetBit (ic->rUsed, R0_IDX);
937       break;
938
939     case AOP_R1:
940       if (R1INB)
941         {
942           emitcode ("mov", "r1,b");
943           R1INB--;
944         }
945       if (_G.r1Pushed)
946         {
947           if (pop)
948             {
949               emitcode ("pop", "ar1");
950               _G.r1Pushed--;
951             }
952         }
953       bitVectUnSetBit (ic->rUsed, R1_IDX);
954       break;
955
956     case AOP_STK:
957       {
958         int sz = aop->size;
959         int stk = aop->aopu.aop_stk + aop->size - 1;
960         bitVectUnSetBit (ic->rUsed, R0_IDX);
961         bitVectUnSetBit (ic->rUsed, R1_IDX);
962
963         getFreePtr (ic, &aop, FALSE);
964
965         if (stk)
966           {
967             emitcode ("mov", "a,_bp");
968             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
969             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
970           }
971         else
972           {
973             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
974           }
975
976         while (sz--)
977           {
978             emitcode ("pop", "acc");
979             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
980             if (!sz)
981               break;
982             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
983           }
984         op->aop = aop;
985         freeAsmop (op, NULL, ic, TRUE);
986         if (_G.r1Pushed)
987           {
988             emitcode ("pop", "ar1");
989             _G.r1Pushed--;
990           }
991
992         if (_G.r0Pushed)
993           {
994             emitcode ("pop", "ar0");
995             _G.r0Pushed--;
996           }
997       }
998     }
999
1000 dealloc:
1001   /* all other cases just dealloc */
1002   if (op)
1003     {
1004       op->aop = NULL;
1005       if (IS_SYMOP (op))
1006         {
1007           OP_SYMBOL (op)->aop = NULL;
1008           /* if the symbol has a spill */
1009           if (SPIL_LOC (op))
1010             SPIL_LOC (op)->aop = NULL;
1011         }
1012     }
1013 }
1014
1015 /*------------------------------------------------------------------*/
1016 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1017 /*                      pop r0 or r1 off stack if pushed            */
1018 /*------------------------------------------------------------------*/
1019 static void
1020 freeForBranchAsmop (operand * op)
1021 {
1022   asmop *aop;
1023
1024   if (!op)
1025     return;
1026
1027   aop = op->aop;
1028
1029   if (!aop)
1030     return;
1031
1032   if (aop->freed)
1033     return;
1034
1035   switch (aop->type)
1036     {
1037     case AOP_R0:
1038       if (R0INB)
1039         {
1040           emitcode ("mov", "r0,b");
1041         }
1042       else if (_G.r0Pushed)
1043         {
1044           emitcode ("pop", "ar0");
1045         }
1046       break;
1047
1048     case AOP_R1:
1049       if (R1INB)
1050         {
1051           emitcode ("mov", "r1,b");
1052         }
1053       else if (_G.r1Pushed)
1054         {
1055           emitcode ("pop", "ar1");
1056         }
1057       break;
1058
1059     case AOP_STK:
1060       {
1061         int sz = aop->size;
1062         int stk = aop->aopu.aop_stk + aop->size - 1;
1063
1064         emitcode ("mov", "b,r0");
1065         if (stk)
1066           {
1067             emitcode ("mov", "a,_bp");
1068             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1069             emitcode ("mov", "r0,a");
1070           }
1071         else
1072           {
1073             emitcode ("mov", "r0,_bp");
1074           }
1075
1076         while (sz--)
1077           {
1078             emitcode ("pop", "acc");
1079             emitcode ("mov", "@r0,a");
1080             if (!sz)
1081               break;
1082             emitcode ("dec", "r0");
1083           }
1084         emitcode ("mov", "r0,b");
1085       }
1086     }
1087
1088 }
1089
1090 /*-----------------------------------------------------------------*/
1091 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1092 /*                 clobber the accumulator                         */
1093 /*-----------------------------------------------------------------*/
1094 static bool
1095 aopGetUsesAcc (operand * oper, int offset)
1096 {
1097   asmop * aop = AOP (oper);
1098
1099   if (offset > (aop->size - 1))
1100     return FALSE;
1101
1102   switch (aop->type)
1103     {
1104
1105     case AOP_R0:
1106     case AOP_R1:
1107       if (aop->paged)
1108         return TRUE;
1109       return FALSE;
1110     case AOP_DPTR:
1111       return TRUE;
1112     case AOP_IMMD:
1113       return FALSE;
1114     case AOP_DIR:
1115       return FALSE;
1116     case AOP_REG:
1117       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1118       return FALSE;
1119     case AOP_CRY:
1120       return TRUE;
1121     case AOP_ACC:
1122       if (offset)
1123         return FALSE;
1124       return TRUE;
1125     case AOP_LIT:
1126       return FALSE;
1127     case AOP_STR:
1128       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1129         return TRUE;
1130       return FALSE;
1131     case AOP_DUMMY:
1132       return FALSE;
1133     default:
1134       /* Error case --- will have been caught already */
1135       wassert(0);
1136       return FALSE;
1137     }
1138 }
1139
1140 /*-----------------------------------------------------------------*/
1141 /* aopGet - for fetching value of the aop                          */
1142 /*-----------------------------------------------------------------*/
1143 static char *
1144 aopGet (operand * oper, int offset, bool bit16, bool dname)
1145 {
1146   char *s = buffer;
1147   char *rs;
1148   asmop * aop = AOP (oper);
1149
1150   /* offset is greater than
1151      size then zero */
1152   if (offset > (aop->size - 1) &&
1153       aop->type != AOP_LIT)
1154     return zero;
1155
1156   /* depending on type */
1157   switch (aop->type)
1158     {
1159     case AOP_DUMMY:
1160       return zero;
1161
1162     case AOP_R0:
1163     case AOP_R1:
1164       /* if we need to increment it */
1165       while (offset > aop->coff)
1166         {
1167           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1168           aop->coff++;
1169         }
1170
1171       while (offset < aop->coff)
1172         {
1173           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1174           aop->coff--;
1175         }
1176
1177       aop->coff = offset;
1178       if (aop->paged)
1179         {
1180           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1181           return (dname ? "acc" : "a");
1182         }
1183       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1184       rs = Safe_calloc (1, strlen (s) + 1);
1185       strcpy (rs, s);
1186       return rs;
1187
1188     case AOP_DPTR:
1189       if (aop->code && aop->coff==0 && offset>=1) {
1190         emitcode ("mov", "a,#0x%02x", offset);
1191         emitcode ("movc", "a,@a+dptr");
1192         return (dname ? "acc" : "a");
1193       }
1194
1195       while (offset > aop->coff)
1196         {
1197           emitcode ("inc", "dptr");
1198           aop->coff++;
1199         }
1200
1201       while (offset < aop->coff)
1202         {
1203           emitcode ("lcall", "__decdptr");
1204           aop->coff--;
1205         }
1206
1207       aop->coff = offset;
1208       if (aop->code)
1209         {
1210           emitcode ("clr", "a");
1211           emitcode ("movc", "a,@a+dptr");
1212         }
1213       else
1214         {
1215           emitcode ("movx", "a,@dptr");
1216         }
1217       return (dname ? "acc" : "a");
1218
1219
1220     case AOP_IMMD:
1221       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1222               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1223       } else if (bit16)
1224         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1225       else if (offset)
1226         sprintf (s, "#(%s >> %d)",
1227                  aop->aopu.aop_immd.aop_immd1,
1228                  offset * 8);
1229       else
1230         sprintf (s, "#%s",
1231                  aop->aopu.aop_immd.aop_immd1);
1232       rs = Safe_calloc (1, strlen (s) + 1);
1233       strcpy (rs, s);
1234       return rs;
1235
1236     case AOP_DIR:
1237       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1238         sprintf (s, "(%s >> %d)",
1239                  aop->aopu.aop_dir, offset * 8);
1240       else if (offset)
1241         sprintf (s, "(%s + %d)",
1242                  aop->aopu.aop_dir,
1243                  offset);
1244       else
1245         sprintf (s, "%s", aop->aopu.aop_dir);
1246       rs = Safe_calloc (1, strlen (s) + 1);
1247       strcpy (rs, s);
1248       return rs;
1249
1250     case AOP_REG:
1251       if (dname)
1252         return aop->aopu.aop_reg[offset]->dname;
1253       else
1254         return aop->aopu.aop_reg[offset]->name;
1255
1256     case AOP_CRY:
1257       emitcode ("clr", "a");
1258       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1259       emitcode ("rlc", "a");
1260       return (dname ? "acc" : "a");
1261
1262     case AOP_ACC:
1263       if (!offset && dname)
1264         return "acc";
1265       return aop->aopu.aop_str[offset];
1266
1267     case AOP_LIT:
1268       return aopLiteral (aop->aopu.aop_lit, offset);
1269
1270     case AOP_STR:
1271       aop->coff = offset;
1272       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1273           dname)
1274         return "acc";
1275
1276       return aop->aopu.aop_str[offset];
1277
1278     }
1279
1280   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1281           "aopget got unsupported aop->type");
1282   exit (1);
1283 }
1284 /*-----------------------------------------------------------------*/
1285 /* aopPut - puts a string for a aop and indicates if acc is in use */
1286 /*-----------------------------------------------------------------*/
1287 static bool
1288 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1289 {
1290   char *d = buffer;
1291   bool accuse = FALSE;
1292   asmop * aop = AOP (result);
1293
1294   if (aop->size && offset > (aop->size - 1))
1295     {
1296       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1297               "aopPut got offset > aop->size");
1298       exit (1);
1299     }
1300
1301   /* will assign value to value */
1302   /* depending on where it is ofcourse */
1303   switch (aop->type)
1304     {
1305     case AOP_DUMMY:
1306       MOVA (s);         /* read s in case it was volatile */
1307       accuse = TRUE;
1308       break;
1309
1310     case AOP_DIR:
1311       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1312         sprintf (d, "(%s >> %d)",
1313                  aop->aopu.aop_dir, offset * 8);
1314       else if (offset)
1315         sprintf (d, "(%s + %d)",
1316                  aop->aopu.aop_dir, offset);
1317       else
1318         sprintf (d, "%s", aop->aopu.aop_dir);
1319
1320       if (strcmp (d, s) ||
1321           bvolatile)
1322           emitcode ("mov", "%s,%s", d, s);
1323       if (!strcmp (d, "acc"))
1324           accuse = TRUE;
1325
1326       break;
1327
1328     case AOP_REG:
1329       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1330           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1331         {
1332           if (*s == '@' ||
1333               strcmp (s, "r0") == 0 ||
1334               strcmp (s, "r1") == 0 ||
1335               strcmp (s, "r2") == 0 ||
1336               strcmp (s, "r3") == 0 ||
1337               strcmp (s, "r4") == 0 ||
1338               strcmp (s, "r5") == 0 ||
1339               strcmp (s, "r6") == 0 ||
1340               strcmp (s, "r7") == 0)
1341             emitcode ("mov", "%s,%s",
1342                       aop->aopu.aop_reg[offset]->dname, s);
1343           else
1344             emitcode ("mov", "%s,%s",
1345                       aop->aopu.aop_reg[offset]->name, s);
1346         }
1347       break;
1348
1349     case AOP_DPTR:
1350       if (aop->code)
1351         {
1352           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1353                   "aopPut writing to code space");
1354           exit (1);
1355         }
1356
1357       while (offset > aop->coff)
1358         {
1359           aop->coff++;
1360           emitcode ("inc", "dptr");
1361         }
1362
1363       while (offset < aop->coff)
1364         {
1365           aop->coff--;
1366           emitcode ("lcall", "__decdptr");
1367         }
1368
1369       aop->coff = offset;
1370
1371       /* if not in accumulator */
1372       MOVA (s);
1373
1374       emitcode ("movx", "@dptr,a");
1375       break;
1376
1377     case AOP_R0:
1378     case AOP_R1:
1379       while (offset > aop->coff)
1380         {
1381           aop->coff++;
1382           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1383         }
1384       while (offset < aop->coff)
1385         {
1386           aop->coff--;
1387           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1388         }
1389       aop->coff = offset;
1390
1391       if (aop->paged)
1392         {
1393           MOVA (s);
1394           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1395
1396         }
1397       else if (*s == '@')
1398         {
1399           MOVA (s);
1400           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1401         }
1402       else if (strcmp (s, "r0") == 0 ||
1403                strcmp (s, "r1") == 0 ||
1404                strcmp (s, "r2") == 0 ||
1405                strcmp (s, "r3") == 0 ||
1406                strcmp (s, "r4") == 0 ||
1407                strcmp (s, "r5") == 0 ||
1408                strcmp (s, "r6") == 0 ||
1409                strcmp (s, "r7") == 0)
1410         {
1411           char buffer[10];
1412           sprintf (buffer, "a%s", s);
1413           emitcode ("mov", "@%s,%s",
1414                     aop->aopu.aop_ptr->name, buffer);
1415         }
1416       else
1417         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1418
1419       break;
1420
1421     case AOP_STK:
1422       if (strcmp (s, "a") == 0)
1423         emitcode ("push", "acc");
1424       else
1425         if (*s=='@') {
1426           MOVA(s);
1427           emitcode ("push", "acc");
1428         } else {
1429           emitcode ("push", s);
1430         }
1431
1432       break;
1433
1434     case AOP_CRY:
1435       /* if not bit variable */
1436       if (!aop->aopu.aop_dir)
1437         {
1438           /* inefficient: move carry into A and use jz/jnz */
1439           emitcode ("clr", "a");
1440           emitcode ("rlc", "a");
1441           accuse = TRUE;
1442         }
1443       else
1444         {
1445           if (s == zero)
1446             emitcode ("clr", "%s", aop->aopu.aop_dir);
1447           else if (s == one)
1448             emitcode ("setb", "%s", aop->aopu.aop_dir);
1449           else if (!strcmp (s, "c"))
1450             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1451           else
1452             {
1453               MOVA (s);
1454               /* set C, if a >= 1 */
1455               emitcode ("add", "a,#0xff");
1456               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1457             }
1458         }
1459       break;
1460
1461     case AOP_STR:
1462       aop->coff = offset;
1463       if (strcmp (aop->aopu.aop_str[offset], s) ||
1464           bvolatile)
1465         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1466       break;
1467
1468     case AOP_ACC:
1469       accuse = TRUE;
1470       aop->coff = offset;
1471       if (!offset && (strcmp (s, "acc") == 0) &&
1472           !bvolatile)
1473         break;
1474
1475       if (strcmp (aop->aopu.aop_str[offset], s) &&
1476           !bvolatile)
1477         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1478       break;
1479
1480     default:
1481       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1482               "aopPut got unsupported aop->type");
1483       exit (1);
1484     }
1485
1486     return accuse;
1487 }
1488
1489
1490 #if 0
1491 /*-----------------------------------------------------------------*/
1492 /* pointToEnd :- points to the last byte of the operand            */
1493 /*-----------------------------------------------------------------*/
1494 static void
1495 pointToEnd (asmop * aop)
1496 {
1497   int count;
1498   if (!aop)
1499     return;
1500
1501   aop->coff = count = (aop->size - 1);
1502   switch (aop->type)
1503     {
1504     case AOP_R0:
1505     case AOP_R1:
1506       while (count--)
1507         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1508       break;
1509     case AOP_DPTR:
1510       while (count--)
1511         emitcode ("inc", "dptr");
1512       break;
1513     }
1514
1515 }
1516 #endif
1517
1518 /*-----------------------------------------------------------------*/
1519 /* reAdjustPreg - points a register back to where it should        */
1520 /*-----------------------------------------------------------------*/
1521 static void
1522 reAdjustPreg (asmop * aop)
1523 {
1524   if ((aop->coff==0) || aop->size <= 1)
1525     return;
1526
1527   switch (aop->type)
1528     {
1529     case AOP_R0:
1530     case AOP_R1:
1531       while (aop->coff--)
1532         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1533       break;
1534     case AOP_DPTR:
1535       while (aop->coff--)
1536         {
1537           emitcode ("lcall", "__decdptr");
1538         }
1539       break;
1540     }
1541   aop->coff = 0;
1542 }
1543
1544 /*-----------------------------------------------------------------*/
1545 /* opIsGptr: returns non-zero if the passed operand is       */
1546 /* a generic pointer type.             */
1547 /*-----------------------------------------------------------------*/
1548 static int
1549 opIsGptr (operand * op)
1550 {
1551   sym_link *type = operandType (op);
1552
1553   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1554     {
1555       return 1;
1556     }
1557   return 0;
1558 }
1559
1560 /*-----------------------------------------------------------------*/
1561 /* getDataSize - get the operand data size                         */
1562 /*-----------------------------------------------------------------*/
1563 static int
1564 getDataSize (operand * op)
1565 {
1566   int size;
1567   size = AOP_SIZE (op);
1568   if (size == GPTRSIZE)
1569     {
1570       sym_link *type = operandType (op);
1571       if (IS_GENPTR (type))
1572         {
1573           /* generic pointer; arithmetic operations
1574            * should ignore the high byte (pointer type).
1575            */
1576           size--;
1577         }
1578     }
1579   return size;
1580 }
1581
1582 /*-----------------------------------------------------------------*/
1583 /* outAcc - output Acc                                             */
1584 /*-----------------------------------------------------------------*/
1585 static void
1586 outAcc (operand * result)
1587 {
1588   int size, offset;
1589   size = getDataSize (result);
1590   if (size)
1591     {
1592       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1593       size--;
1594       offset = 1;
1595       /* unsigned or positive */
1596       while (size--)
1597         {
1598           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1599         }
1600     }
1601 }
1602
1603 /*-----------------------------------------------------------------*/
1604 /* outBitC - output a bit C                                        */
1605 /*-----------------------------------------------------------------*/
1606 static void
1607 outBitC (operand * result)
1608 {
1609   /* if the result is bit */
1610   if (AOP_TYPE (result) == AOP_CRY)
1611     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1612   else
1613     {
1614       emitcode ("clr", "a");
1615       emitcode ("rlc", "a");
1616       outAcc (result);
1617     }
1618 }
1619
1620 /*-----------------------------------------------------------------*/
1621 /* toBoolean - emit code for orl a,operator(sizeop)                */
1622 /*-----------------------------------------------------------------*/
1623 static void
1624 toBoolean (operand * oper)
1625 {
1626   int size = AOP_SIZE (oper) - 1;
1627   int offset = 1;
1628   bool AccUsed = FALSE;
1629   bool pushedB;
1630
1631   while (!AccUsed && size--)
1632     {
1633       AccUsed |= aopGetUsesAcc(oper, offset++);
1634     }
1635
1636   size = AOP_SIZE (oper) - 1;
1637   offset = 1;
1638   MOVA (aopGet (oper, 0, FALSE, FALSE));
1639   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1640     {
1641       pushedB = pushB ();
1642       emitcode("mov", "b,a");
1643       while (--size)
1644         {
1645           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1646           emitcode ("orl", "b,a");
1647         }
1648       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1649       emitcode ("orl", "a,b");
1650       popB (pushedB);
1651     }
1652   else
1653     {
1654       while (size--)
1655         {
1656           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1657         }
1658     }
1659 }
1660
1661
1662 /*-----------------------------------------------------------------*/
1663 /* genNot - generate code for ! operation                          */
1664 /*-----------------------------------------------------------------*/
1665 static void
1666 genNot (iCode * ic)
1667 {
1668   symbol *tlbl;
1669
1670   D(emitcode (";     genNot",""));
1671
1672   /* assign asmOps to operand & result */
1673   aopOp (IC_LEFT (ic), ic, FALSE);
1674   aopOp (IC_RESULT (ic), ic, TRUE);
1675
1676   /* if in bit space then a special case */
1677   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1678     {
1679       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1680       emitcode ("cpl", "c");
1681       outBitC (IC_RESULT (ic));
1682       goto release;
1683     }
1684
1685   toBoolean (IC_LEFT (ic));
1686
1687   tlbl = newiTempLabel (NULL);
1688   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1689   emitcode ("", "%05d$:", tlbl->key + 100);
1690   outBitC (IC_RESULT (ic));
1691
1692 release:
1693   /* release the aops */
1694   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1695   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1696 }
1697
1698
1699 /*-----------------------------------------------------------------*/
1700 /* genCpl - generate code for complement                           */
1701 /*-----------------------------------------------------------------*/
1702 static void
1703 genCpl (iCode * ic)
1704 {
1705   int offset = 0;
1706   int size;
1707   symbol *tlbl;
1708   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1709
1710   D(emitcode (";", "genCpl"));
1711
1712   /* assign asmOps to operand & result */
1713   aopOp (IC_LEFT (ic), ic, FALSE);
1714   aopOp (IC_RESULT (ic), ic, TRUE);
1715
1716   /* special case if in bit space */
1717   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1718     {
1719       char *l;
1720
1721       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1722           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1723         {
1724           /* promotion rules are responsible for this strange result:
1725              bit -> int -> ~int -> bit
1726              uchar -> int -> ~int -> bit
1727           */
1728           werror(W_COMPLEMENT);
1729           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1730           goto release;
1731         }
1732
1733       tlbl=newiTempLabel(NULL);
1734       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1735       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1736           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1737           IS_AOP_PREG (IC_LEFT (ic)))
1738         {
1739           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1740         }
1741       else
1742         {
1743           MOVA (l);
1744           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1745         }
1746       emitcode ("", "%05d$:", tlbl->key + 100);
1747       outBitC (IC_RESULT(ic));
1748       goto release;
1749     }
1750
1751   size = AOP_SIZE (IC_RESULT (ic));
1752   while (size--)
1753     {
1754       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1755       MOVA (l);
1756       emitcode ("cpl", "a");
1757       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1758     }
1759
1760
1761 release:
1762   /* release the aops */
1763   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1764   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1765 }
1766
1767 /*-----------------------------------------------------------------*/
1768 /* genUminusFloat - unary minus for floating points                */
1769 /*-----------------------------------------------------------------*/
1770 static void
1771 genUminusFloat (operand * op, operand * result)
1772 {
1773   int size, offset = 0;
1774   char *l;
1775
1776   D(emitcode (";     genUminusFloat",""));
1777
1778   /* for this we just copy and then flip the bit */
1779
1780   size = AOP_SIZE (op) - 1;
1781
1782   while (size--)
1783     {
1784       aopPut (result,
1785               aopGet (op, offset, FALSE, FALSE),
1786               offset,
1787               isOperandVolatile (result, FALSE));
1788       offset++;
1789     }
1790
1791   l = aopGet (op, offset, FALSE, FALSE);
1792
1793   MOVA (l);
1794
1795   emitcode ("cpl", "acc.7");
1796   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1797 }
1798
1799 /*-----------------------------------------------------------------*/
1800 /* genUminus - unary minus code generation                         */
1801 /*-----------------------------------------------------------------*/
1802 static void
1803 genUminus (iCode * ic)
1804 {
1805   int offset, size;
1806   sym_link *optype, *rtype;
1807
1808
1809   D(emitcode (";     genUminus",""));
1810
1811   /* assign asmops */
1812   aopOp (IC_LEFT (ic), ic, FALSE);
1813   aopOp (IC_RESULT (ic), ic, TRUE);
1814
1815   /* if both in bit space then special
1816      case */
1817   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1818       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1819     {
1820
1821       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1822       emitcode ("cpl", "c");
1823       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1824       goto release;
1825     }
1826
1827   optype = operandType (IC_LEFT (ic));
1828   rtype = operandType (IC_RESULT (ic));
1829
1830   /* if float then do float stuff */
1831   if (IS_FLOAT (optype))
1832     {
1833       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1834       goto release;
1835     }
1836
1837   /* otherwise subtract from zero */
1838   size = AOP_SIZE (IC_LEFT (ic));
1839   offset = 0;
1840   //CLRC ;
1841   while (size--)
1842     {
1843       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1844       if (!strcmp (l, "a"))
1845         {
1846           if (offset == 0)
1847             SETC;
1848           emitcode ("cpl", "a");
1849           emitcode ("addc", "a,#0");
1850         }
1851       else
1852         {
1853           if (offset == 0)
1854             CLRC;
1855           emitcode ("clr", "a");
1856           emitcode ("subb", "a,%s", l);
1857         }
1858       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1859     }
1860
1861   /* if any remaining bytes in the result */
1862   /* we just need to propagate the sign   */
1863   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1864     {
1865       emitcode ("rlc", "a");
1866       emitcode ("subb", "a,acc");
1867       while (size--)
1868         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1869     }
1870
1871 release:
1872   /* release the aops */
1873   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1874   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1875 }
1876
1877 /*-----------------------------------------------------------------*/
1878 /* saveRegisters - will look for a call and save the registers     */
1879 /*-----------------------------------------------------------------*/
1880 static void
1881 saveRegisters (iCode * lic)
1882 {
1883   int i;
1884   iCode *ic;
1885   bitVect *rsave;
1886
1887   /* look for call */
1888   for (ic = lic; ic; ic = ic->next)
1889     if (ic->op == CALL || ic->op == PCALL)
1890       break;
1891
1892   if (!ic)
1893     {
1894       fprintf (stderr, "found parameter push with no function call\n");
1895       return;
1896     }
1897
1898   /* if the registers have been saved already or don't need to be then
1899      do nothing */
1900   if (ic->regsSaved)
1901     return;
1902   if (IS_SYMOP(IC_LEFT(ic)) &&
1903       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1904        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1905     return;
1906
1907   /* save the registers in use at this time but skip the
1908      ones for the result */
1909   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1910                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1911
1912   ic->regsSaved = 1;
1913   if (options.useXstack)
1914     {
1915       int count = bitVectnBitsOn (rsave);
1916
1917       if (count == 1)
1918         {
1919           i = bitVectFirstBit (rsave);
1920           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1921           emitcode ("mov", "r0,%s", spname);
1922           emitcode ("inc", "%s", spname);// allocate before use
1923           emitcode ("movx", "@r0,a");
1924           if (bitVectBitValue (rsave, R0_IDX))
1925             emitcode ("mov", "r0,a");
1926         }
1927       else if (count != 0)
1928         {
1929           if (bitVectBitValue (rsave, R0_IDX))
1930             {
1931               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1932             }
1933           emitcode ("mov", "r0,%s", spname);
1934           MOVA ("r0");
1935           emitcode ("add", "a,#%d", count);
1936           emitcode ("mov", "%s,a", spname);
1937           for (i = 0; i < mcs51_nRegs; i++)
1938             {
1939               if (bitVectBitValue (rsave, i))
1940                 {
1941                   if (i == R0_IDX)
1942                     {
1943                       emitcode ("pop", "acc");
1944                       emitcode ("push", "acc");
1945                     }
1946                   else
1947                     {
1948                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1949                     }
1950                   emitcode ("movx", "@r0,a");
1951                   if (--count)
1952                     {
1953                       emitcode ("inc", "r0");
1954                     }
1955                 }
1956             }
1957           if (bitVectBitValue (rsave, R0_IDX))
1958             {
1959               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1960             }
1961         }
1962     }
1963   else
1964     for (i = 0; i < mcs51_nRegs; i++)
1965       {
1966         if (bitVectBitValue (rsave, i))
1967           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1968       }
1969 }
1970
1971 /*-----------------------------------------------------------------*/
1972 /* unsaveRegisters - pop the pushed registers                      */
1973 /*-----------------------------------------------------------------*/
1974 static void
1975 unsaveRegisters (iCode * ic)
1976 {
1977   int i;
1978   bitVect *rsave;
1979
1980   /* restore the registers in use at this time but skip the
1981      ones for the result */
1982   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1983                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1984
1985   if (options.useXstack)
1986     {
1987       int count = bitVectnBitsOn (rsave);
1988
1989       if (count == 1)
1990         {
1991           emitcode ("mov", "r0,%s", spname);
1992           emitcode ("dec", "r0");
1993           emitcode ("movx", "a,@r0");
1994           i = bitVectFirstBit (rsave);
1995           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1996           emitcode ("dec", "%s", spname);
1997         }
1998       else if (count != 0)
1999         {
2000           emitcode ("mov", "r0,%s", spname);
2001           for (i = mcs51_nRegs; i >= 0; i--)
2002             {
2003               if (bitVectBitValue (rsave, i))
2004                 {
2005                   emitcode ("dec", "r0");
2006                   emitcode ("movx", "a,@r0");
2007                   if (i != R0_IDX)
2008                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
2009                   else
2010                     emitcode ("push", "acc");
2011                 }
2012             }
2013           emitcode ("mov", "%s,r0", spname);
2014           if (bitVectBitValue (rsave, R0_IDX))
2015             {
2016               emitcode ("pop", "ar0");
2017             }
2018         }
2019     }
2020   else
2021     for (i = mcs51_nRegs; i >= 0; i--)
2022       {
2023         if (bitVectBitValue (rsave, i))
2024           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2025       }
2026 }
2027
2028
2029 /*-----------------------------------------------------------------*/
2030 /* pushSide -                */
2031 /*-----------------------------------------------------------------*/
2032 static void
2033 pushSide (operand * oper, int size)
2034 {
2035   int offset = 0;
2036   while (size--)
2037     {
2038       char *l = aopGet (oper, offset++, FALSE, TRUE);
2039       if (AOP_TYPE (oper) != AOP_REG &&
2040           AOP_TYPE (oper) != AOP_DIR &&
2041           strcmp (l, "a"))
2042         {
2043           MOVA (l);
2044           emitcode ("push", "acc");
2045         }
2046       else
2047           emitcode ("push", "%s", l);
2048         }
2049     }
2050
2051 /*-----------------------------------------------------------------*/
2052 /* assignResultValue - also indicates if acc is in use afterwards  */
2053 /*-----------------------------------------------------------------*/
2054 static bool
2055 assignResultValue (operand * oper)
2056 {
2057   int offset = 0;
2058   int size = AOP_SIZE (oper);
2059   bool accuse = FALSE;
2060
2061   while (size--)
2062     {
2063       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2064       offset++;
2065     }
2066   return accuse;
2067 }
2068
2069
2070 /*-----------------------------------------------------------------*/
2071 /* genXpush - pushes onto the external stack                       */
2072 /*-----------------------------------------------------------------*/
2073 static void
2074 genXpush (iCode * ic)
2075 {
2076   asmop *aop = newAsmop (0);
2077   regs *r;
2078   int size, offset = 0;
2079
2080   D(emitcode (";     genXpush",""));
2081
2082   aopOp (IC_LEFT (ic), ic, FALSE);
2083   r = getFreePtr (ic, &aop, FALSE);
2084
2085   size = AOP_SIZE (IC_LEFT (ic));
2086
2087   if (size == 1)
2088     {
2089       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2090       emitcode ("mov", "%s,%s", r->name, spname);
2091       emitcode ("inc", "%s", spname); // allocate space first
2092       emitcode ("movx", "@%s,a", r->name);
2093     }
2094   else
2095     {
2096       // allocate space first
2097       emitcode ("mov", "%s,%s", r->name, spname);
2098       MOVA (r->name);
2099       emitcode ("add", "a,#%d", size);
2100       emitcode ("mov", "%s,a", spname);
2101
2102       while (size--)
2103         {
2104           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2105           emitcode ("movx", "@%s,a", r->name);
2106           emitcode ("inc", "%s", r->name);
2107         }
2108     }
2109
2110   freeAsmop (NULL, aop, ic, TRUE);
2111   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2112 }
2113
2114 /*-----------------------------------------------------------------*/
2115 /* genIpush - generate code for pushing this gets a little complex */
2116 /*-----------------------------------------------------------------*/
2117 static void
2118 genIpush (iCode * ic)
2119 {
2120   int size, offset = 0;
2121   char *l;
2122
2123   D(emitcode (";     genIpush",""));
2124
2125   /* if this is not a parm push : ie. it is spill push
2126      and spill push is always done on the local stack */
2127   if (!ic->parmPush)
2128     {
2129
2130       /* and the item is spilt then do nothing */
2131       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2132         return;
2133
2134       aopOp (IC_LEFT (ic), ic, FALSE);
2135       size = AOP_SIZE (IC_LEFT (ic));
2136       /* push it on the stack */
2137       while (size--)
2138         {
2139           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2140           if (*l == '#')
2141             {
2142               MOVA (l);
2143               l = "acc";
2144             }
2145           emitcode ("push", "%s", l);
2146         }
2147       return;
2148     }
2149
2150   /* this is a paramter push: in this case we call
2151      the routine to find the call and save those
2152      registers that need to be saved */
2153   saveRegisters (ic);
2154
2155   /* if use external stack then call the external
2156      stack pushing routine */
2157   if (options.useXstack)
2158     {
2159       genXpush (ic);
2160       return;
2161     }
2162
2163   /* then do the push */
2164   aopOp (IC_LEFT (ic), ic, FALSE);
2165
2166   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2167   size = AOP_SIZE (IC_LEFT (ic));
2168
2169   while (size--)
2170     {
2171       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2172       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2173           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2174           strcmp (l, "a"))
2175         {
2176           MOVA (l);
2177           emitcode ("push", "acc");
2178         }
2179       else
2180           emitcode ("push", "%s", l);
2181     }
2182
2183   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2184 }
2185
2186 /*-----------------------------------------------------------------*/
2187 /* genIpop - recover the registers: can happen only for spilling   */
2188 /*-----------------------------------------------------------------*/
2189 static void
2190 genIpop (iCode * ic)
2191 {
2192   int size, offset;
2193
2194   D(emitcode (";     genIpop",""));
2195
2196   /* if the temp was not pushed then */
2197   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2198     return;
2199
2200   aopOp (IC_LEFT (ic), ic, FALSE);
2201   size = AOP_SIZE (IC_LEFT (ic));
2202   offset = (size - 1);
2203   while (size--)
2204     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2205                                    FALSE, TRUE));
2206
2207   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2208 }
2209
2210 /*-----------------------------------------------------------------*/
2211 /* saveRBank - saves an entire register bank on the stack          */
2212 /*-----------------------------------------------------------------*/
2213 static void
2214 saveRBank (int bank, iCode * ic, bool pushPsw)
2215 {
2216   int i;
2217   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2218   asmop *aop = NULL;
2219   regs *r = NULL;
2220
2221   if (options.useXstack)
2222     {
2223       if (!ic)
2224       {
2225           /* Assume r0 is available for use. */
2226           r = mcs51_regWithIdx (R0_IDX);;
2227       }
2228       else
2229       {
2230           aop = newAsmop (0);
2231           r = getFreePtr (ic, &aop, FALSE);
2232       }
2233       // allocate space first
2234       emitcode ("mov", "%s,%s", r->name, spname);
2235       MOVA (r->name);
2236       emitcode ("add", "a,#%d", count);
2237       emitcode ("mov", "%s,a", spname);
2238     }
2239
2240   for (i = 0; i < mcs51_nRegs; i++)
2241     {
2242       if (options.useXstack)
2243         {
2244           emitcode ("mov", "a,(%s+%d)",
2245                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2246           emitcode ("movx", "@%s,a", r->name);
2247           if (--count)
2248             emitcode ("inc", "%s", r->name);
2249         }
2250       else
2251         emitcode ("push", "(%s+%d)",
2252                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2253     }
2254
2255   if (pushPsw)
2256     {
2257       if (options.useXstack)
2258         {
2259           emitcode ("mov", "a,psw");
2260           emitcode ("movx", "@%s,a", r->name);
2261
2262         }
2263       else
2264         {
2265           emitcode ("push", "psw");
2266         }
2267
2268       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2269     }
2270
2271   if (aop)
2272     {
2273       freeAsmop (NULL, aop, ic, TRUE);
2274     }
2275
2276   if (ic)
2277   {
2278     ic->bankSaved = 1;
2279   }
2280 }
2281
2282 /*-----------------------------------------------------------------*/
2283 /* unsaveRBank - restores the register bank from stack             */
2284 /*-----------------------------------------------------------------*/
2285 static void
2286 unsaveRBank (int bank, iCode * ic, bool popPsw)
2287 {
2288   int i;
2289   asmop *aop = NULL;
2290   regs *r = NULL;
2291
2292   if (options.useXstack)
2293     {
2294       if (!ic)
2295         {
2296           /* Assume r0 is available for use. */
2297           r = mcs51_regWithIdx (R0_IDX);;
2298         }
2299       else
2300         {
2301           aop = newAsmop (0);
2302           r = getFreePtr (ic, &aop, FALSE);
2303         }
2304       emitcode ("mov", "%s,%s", r->name, spname);
2305     }
2306
2307   if (popPsw)
2308     {
2309       if (options.useXstack)
2310         {
2311           emitcode ("dec", "%s", r->name);
2312           emitcode ("movx", "a,@%s", r->name);
2313           emitcode ("mov", "psw,a");
2314         }
2315       else
2316         {
2317           emitcode ("pop", "psw");
2318         }
2319     }
2320
2321   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2322     {
2323       if (options.useXstack)
2324         {
2325           emitcode ("dec", "%s", r->name);
2326           emitcode ("movx", "a,@%s", r->name);
2327           emitcode ("mov", "(%s+%d),a",
2328                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2329         }
2330       else
2331         {
2332           emitcode ("pop", "(%s+%d)",
2333                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2334         }
2335     }
2336
2337   if (options.useXstack)
2338     {
2339       emitcode ("mov", "%s,%s", spname, r->name);
2340     }
2341
2342   if (aop)
2343     {
2344       freeAsmop (NULL, aop, ic, TRUE);
2345     }
2346 }
2347
2348 /*-----------------------------------------------------------------*/
2349 /* genSend - gen code for SEND                                     */
2350 /*-----------------------------------------------------------------*/
2351 static void genSend(set *sendSet)
2352 {
2353     iCode *sic;
2354     int rb1_count = 0 ;
2355
2356     for (sic = setFirstItem (sendSet); sic;
2357          sic = setNextItem (sendSet)) {
2358           int size, offset = 0;
2359           aopOp (IC_LEFT (sic), sic, FALSE);
2360           size = AOP_SIZE (IC_LEFT (sic));
2361
2362           if (sic->argreg == 1) {
2363               while (size--) {
2364                   char *l = aopGet (IC_LEFT (sic), offset,
2365                                     FALSE, FALSE);
2366                   if (strcmp (l, fReturn[offset]))
2367                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2368                   offset++;
2369               }
2370               rb1_count = 0;
2371           } else {
2372               while (size--) {
2373                   emitcode ("mov","b1_%d,%s",rb1_count++,
2374                             aopGet (IC_LEFT (sic), offset++,FALSE, FALSE));
2375               }
2376           }
2377           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2378     }
2379 }
2380
2381 /*-----------------------------------------------------------------*/
2382 /* genCall - generates a call statement                            */
2383 /*-----------------------------------------------------------------*/
2384 static void
2385 genCall (iCode * ic)
2386 {
2387   sym_link *dtype;
2388 //  bool restoreBank = FALSE;
2389   bool swapBanks = FALSE;
2390   bool accuse = FALSE;
2391   bool accPushed = FALSE;
2392
2393   D(emitcode(";     genCall",""));
2394
2395   dtype = operandType (IC_LEFT (ic));
2396   /* if send set is not empty then assign */
2397   if (_G.sendSet)
2398     {
2399         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2400             genSend(reverseSet(_G.sendSet));
2401         } else {
2402             genSend(_G.sendSet);
2403         }
2404
2405       _G.sendSet = NULL;
2406     }
2407
2408   /* if we are calling a not _naked function that is not using
2409      the same register bank then we need to save the
2410      destination registers on the stack */
2411   dtype = operandType (IC_LEFT (ic));
2412   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2413       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2414        !IFFUNC_ISISR (dtype))
2415   {
2416       swapBanks = TRUE;
2417   }
2418
2419   /* if caller saves & we have not saved then */
2420   if (!ic->regsSaved)
2421       saveRegisters (ic);
2422
2423   if (swapBanks)
2424   {
2425         emitcode ("mov", "psw,#0x%02x",
2426            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2427   }
2428
2429   /* make the call */
2430   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2431                             OP_SYMBOL (IC_LEFT (ic))->rname :
2432                             OP_SYMBOL (IC_LEFT (ic))->name));
2433
2434   if (swapBanks)
2435   {
2436        emitcode ("mov", "psw,#0x%02x",
2437           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2438   }
2439
2440   /* if we need assign a result value */
2441   if ((IS_ITEMP (IC_RESULT (ic)) &&
2442        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2443         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2444         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2445       IS_TRUE_SYMOP (IC_RESULT (ic)))
2446     {
2447
2448       _G.accInUse++;
2449       aopOp (IC_RESULT (ic), ic, FALSE);
2450       _G.accInUse--;
2451
2452       accuse = assignResultValue (IC_RESULT (ic));
2453
2454       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2455     }
2456
2457   /* adjust the stack for parameters if required */
2458   if (ic->parmBytes)
2459     {
2460       int i;
2461       if (ic->parmBytes > 3)
2462         {
2463           if (accuse)
2464             {
2465               emitcode ("push", "acc");
2466               accPushed = TRUE;
2467             }
2468
2469           emitcode ("mov", "a,%s", spname);
2470           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2471           emitcode ("mov", "%s,a", spname);
2472
2473           /* unsaveRegisters from xstack needs acc, but */
2474           /* unsaveRegisters from stack needs this popped */
2475           if (accPushed && !options.useXstack)
2476             {
2477               emitcode ("pop", "acc");
2478               accPushed = FALSE;
2479             }
2480         }
2481       else
2482         for (i = 0; i < ic->parmBytes; i++)
2483           emitcode ("dec", "%s", spname);
2484     }
2485
2486   /* if we hade saved some registers then unsave them */
2487   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2488     {
2489       if (accuse && !accPushed && options.useXstack)
2490         {
2491           /* xstack needs acc, but doesn't touch normal stack */
2492           emitcode ("push", "acc");
2493           accPushed = TRUE;
2494         }
2495       unsaveRegisters (ic);
2496     }
2497
2498 //  /* if register bank was saved then pop them */
2499 //  if (restoreBank)
2500 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2501
2502   if (accPushed)
2503     emitcode ("pop", "acc");
2504 }
2505
2506 /*-----------------------------------------------------------------*/
2507 /* -10l - generates a call by pointer statement                */
2508 /*-----------------------------------------------------------------*/
2509 static void
2510 genPcall (iCode * ic)
2511 {
2512   sym_link *dtype;
2513   symbol *rlbl = newiTempLabel (NULL);
2514 //  bool restoreBank=FALSE;
2515   bool swapBanks = FALSE;
2516
2517   D(emitcode(";     genPCall",""));
2518
2519   /* if caller saves & we have not saved then */
2520   if (!ic->regsSaved)
2521     saveRegisters (ic);
2522
2523   /* if we are calling a not _naked function that is not using
2524      the same register bank then we need to save the
2525      destination registers on the stack */
2526   dtype = operandType (IC_LEFT (ic))->next;
2527   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2528       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2529       !IFFUNC_ISISR (dtype))
2530   {
2531 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2532 //    restoreBank=TRUE;
2533       swapBanks = TRUE;
2534       // need caution message to user here
2535   }
2536
2537   /* push the return address on to the stack */
2538   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2539   emitcode ("push", "acc");
2540   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2541   emitcode ("push", "acc");
2542
2543   /* now push the calling address */
2544   aopOp (IC_LEFT (ic), ic, FALSE);
2545
2546   pushSide (IC_LEFT (ic), FPTRSIZE);
2547
2548   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2549
2550   /* if send set is not empty the assign */
2551   if (_G.sendSet)
2552     {
2553         genSend(reverseSet(_G.sendSet));
2554         _G.sendSet = NULL;
2555     }
2556
2557   if (swapBanks)
2558   {
2559         emitcode ("mov", "psw,#0x%02x",
2560            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2561   }
2562
2563   /* make the call */
2564   emitcode ("ret", "");
2565   emitcode ("", "%05d$:", (rlbl->key + 100));
2566
2567
2568   if (swapBanks)
2569   {
2570        emitcode ("mov", "psw,#0x%02x",
2571           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2572   }
2573
2574   /* if we need assign a result value */
2575   if ((IS_ITEMP (IC_RESULT (ic)) &&
2576        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2577         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2578       IS_TRUE_SYMOP (IC_RESULT (ic)))
2579     {
2580
2581       _G.accInUse++;
2582       aopOp (IC_RESULT (ic), ic, FALSE);
2583       _G.accInUse--;
2584
2585       assignResultValue (IC_RESULT (ic));
2586
2587       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2588     }
2589
2590   /* adjust the stack for parameters if
2591      required */
2592   if (ic->parmBytes)
2593     {
2594       int i;
2595       if (ic->parmBytes > 3)
2596         {
2597           emitcode ("mov", "a,%s", spname);
2598           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2599           emitcode ("mov", "%s,a", spname);
2600         }
2601       else
2602         for (i = 0; i < ic->parmBytes; i++)
2603           emitcode ("dec", "%s", spname);
2604
2605     }
2606
2607 //  /* if register bank was saved then unsave them */
2608 //  if (restoreBank)
2609 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2610
2611   /* if we hade saved some registers then
2612      unsave them */
2613   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2614     unsaveRegisters (ic);
2615 }
2616
2617 /*-----------------------------------------------------------------*/
2618 /* resultRemat - result  is rematerializable                       */
2619 /*-----------------------------------------------------------------*/
2620 static int
2621 resultRemat (iCode * ic)
2622 {
2623   if (SKIP_IC (ic) || ic->op == IFX)
2624     return 0;
2625
2626   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2627     {
2628       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2629       if (sym->remat && !POINTER_SET (ic))
2630         return 1;
2631     }
2632
2633   return 0;
2634 }
2635
2636 #if defined(__BORLANDC__) || defined(_MSC_VER)
2637 #define STRCASECMP stricmp
2638 #else
2639 #define STRCASECMP strcasecmp
2640 #endif
2641
2642 /*-----------------------------------------------------------------*/
2643 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2644 /*-----------------------------------------------------------------*/
2645 static int
2646 regsCmp(void *p1, void *p2)
2647 {
2648   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2649 }
2650
2651 static bool
2652 inExcludeList (char *s)
2653 {
2654   const char *p = setFirstItem(options.excludeRegsSet);
2655
2656   if (p == NULL || STRCASECMP(p, "none") == 0)
2657     return FALSE;
2658
2659
2660   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2661 }
2662
2663 /*-----------------------------------------------------------------*/
2664 /* genFunction - generated code for function entry                 */
2665 /*-----------------------------------------------------------------*/
2666 static void
2667 genFunction (iCode * ic)
2668 {
2669   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2670   sym_link *ftype;
2671   bool     switchedPSW = FALSE;
2672   int      calleesaves_saved_register = -1;
2673   int      stackAdjust = sym->stack;
2674   int      accIsFree = sym->recvSize < 4;
2675   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2676   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2677
2678   _G.nRegsSaved = 0;
2679   /* create the function header */
2680   emitcode (";", "-----------------------------------------");
2681   emitcode (";", " function %s", sym->name);
2682   emitcode (";", "-----------------------------------------");
2683
2684   emitcode ("", "%s:", sym->rname);
2685   ftype = operandType (IC_LEFT (ic));
2686   _G.currentFunc = sym;
2687
2688   if (IFFUNC_ISNAKED(ftype))
2689   {
2690       emitcode(";", "naked function: no prologue.");
2691       return;
2692   }
2693
2694   /* here we need to generate the equates for the
2695      register bank if required */
2696   if (FUNC_REGBANK (ftype) != rbank)
2697     {
2698       int i;
2699
2700       rbank = FUNC_REGBANK (ftype);
2701       for (i = 0; i < mcs51_nRegs; i++)
2702         {
2703           if (strcmp (regs8051[i].base, "0") == 0)
2704             emitcode ("", "%s = 0x%02x",
2705                       regs8051[i].dname,
2706                       8 * rbank + regs8051[i].offset);
2707           else
2708             emitcode ("", "%s = %s + 0x%02x",
2709                       regs8051[i].dname,
2710                       regs8051[i].base,
2711                       8 * rbank + regs8051[i].offset);
2712         }
2713     }
2714
2715   /* if this is an interrupt service routine then
2716      save acc, b, dpl, dph  */
2717   if (IFFUNC_ISISR (sym->type))
2718     {
2719
2720       if (!inExcludeList ("acc"))
2721         emitcode ("push", "acc");
2722       if (!inExcludeList ("b"))
2723         emitcode ("push", "b");
2724       if (!inExcludeList ("dpl"))
2725         emitcode ("push", "dpl");
2726       if (!inExcludeList ("dph"))
2727         emitcode ("push", "dph");
2728       /* if this isr has no bank i.e. is going to
2729          run with bank 0 , then we need to save more
2730          registers :-) */
2731       if (!FUNC_REGBANK (sym->type))
2732         {
2733
2734           /* if this function does not call any other
2735              function then we can be economical and
2736              save only those registers that are used */
2737           if (!IFFUNC_HASFCALL(sym->type))
2738             {
2739               int i;
2740
2741               /* if any registers used */
2742               if (sym->regsUsed)
2743                 {
2744                   /* save the registers used */
2745                   for (i = 0; i < sym->regsUsed->size; i++)
2746                     {
2747                       if (bitVectBitValue (sym->regsUsed, i))
2748                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2749                     }
2750                 }
2751             }
2752           else
2753             {
2754
2755               /* this function has a function call. We cannot
2756                  determines register usage so we will have to push the
2757                  entire bank */
2758                 saveRBank (0, ic, FALSE);
2759                 if (options.parms_in_bank1) {
2760                     int i;
2761                     for (i=0; i < 8 ; i++ ) {
2762                         emitcode ("push","%s",rb1regs[i]);
2763                     }
2764                 }
2765             }
2766         }
2767         else
2768         {
2769             /* This ISR uses a non-zero bank.
2770              *
2771              * We assume that the bank is available for our
2772              * exclusive use.
2773              *
2774              * However, if this ISR calls a function which uses some
2775              * other bank, we must save that bank entirely.
2776              */
2777             unsigned long banksToSave = 0;
2778
2779             if (IFFUNC_HASFCALL(sym->type))
2780             {
2781
2782 #define MAX_REGISTER_BANKS 4
2783
2784                 iCode *i;
2785                 int ix;
2786
2787                 for (i = ic; i; i = i->next)
2788                 {
2789                     if (i->op == ENDFUNCTION)
2790                     {
2791                         /* we got to the end OK. */
2792                         break;
2793                     }
2794
2795                     if (i->op == CALL)
2796                     {
2797                         sym_link *dtype;
2798
2799                         dtype = operandType (IC_LEFT(i));
2800                         if (dtype
2801                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2802                         {
2803                              /* Mark this bank for saving. */
2804                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2805                              {
2806                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2807                              }
2808                              else
2809                              {
2810                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2811                              }
2812
2813                              /* And note that we don't need to do it in
2814                               * genCall.
2815                               */
2816                              i->bankSaved = 1;
2817                         }
2818                     }
2819                     if (i->op == PCALL)
2820                     {
2821                         /* This is a mess; we have no idea what
2822                          * register bank the called function might
2823                          * use.
2824                          *
2825                          * The only thing I can think of to do is
2826                          * throw a warning and hope.
2827                          */
2828                         werror(W_FUNCPTR_IN_USING_ISR);
2829                     }
2830                 }
2831
2832                 if (banksToSave && options.useXstack)
2833                 {
2834                     /* Since we aren't passing it an ic,
2835                      * saveRBank will assume r0 is available to abuse.
2836                      *
2837                      * So switch to our (trashable) bank now, so
2838                      * the caller's R0 isn't trashed.
2839                      */
2840                     emitcode ("push", "psw");
2841                     emitcode ("mov", "psw,#0x%02x",
2842                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2843                     switchedPSW = TRUE;
2844                 }
2845
2846                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2847                 {
2848                      if (banksToSave & (1 << ix))
2849                      {
2850                          saveRBank(ix, NULL, FALSE);
2851                      }
2852                 }
2853             }
2854             // TODO: this needs a closer look
2855             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2856         }
2857
2858       /* Set the register bank to the desired value if nothing else */
2859       /* has done so yet. */
2860       if (!switchedPSW)
2861         {
2862           emitcode ("push", "psw");
2863           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2864         }
2865     }
2866   else
2867     {
2868       /* This is a non-ISR function. The caller has already switched register */
2869       /* banks, if necessary, so just handle the callee-saves option. */
2870
2871       /* if callee-save to be used for this function
2872          then save the registers being used in this function */
2873       if (IFFUNC_CALLEESAVES(sym->type))
2874         {
2875           int i;
2876
2877           /* if any registers used */
2878           if (sym->regsUsed)
2879             {
2880               /* save the registers used */
2881               for (i = 0; i < sym->regsUsed->size; i++)
2882                 {
2883                   if (bitVectBitValue (sym->regsUsed, i))
2884                     {
2885                       /* remember one saved register for later usage */
2886                       if (calleesaves_saved_register < 0)
2887                         calleesaves_saved_register = i;
2888                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2889                       _G.nRegsSaved++;
2890                     }
2891                 }
2892             }
2893         }
2894     }
2895
2896
2897   if (fReentrant)
2898     {
2899       if (options.useXstack)
2900         {
2901           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
2902             {
2903               emitcode ("mov", "r0,%s", spname);
2904               emitcode ("inc", "%s", spname);
2905               emitcode ("xch", "a,_bpx");
2906               emitcode ("movx", "@r0,a");
2907               emitcode ("inc", "r0");
2908               emitcode ("mov", "a,r0");
2909               emitcode ("xch", "a,_bpx");
2910             }
2911           if (sym->stack)
2912             {
2913               emitcode ("push", "_bp");     /* save the callers stack  */
2914               emitcode ("mov", "_bp,sp");
2915             }
2916         }
2917       else
2918         {
2919           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
2920             {
2921               /* set up the stack */
2922               emitcode ("push", "_bp");     /* save the callers stack  */
2923               emitcode ("mov", "_bp,sp");
2924             }
2925         }
2926     }
2927
2928   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2929   /* before setting up the stack frame completely. */
2930   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2931     {
2932       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2933
2934       if (rsym->isitmp)
2935         {
2936           if (rsym && rsym->regType == REG_CND)
2937             rsym = NULL;
2938           if (rsym && (rsym->accuse || rsym->ruonly))
2939             rsym = NULL;
2940           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2941             rsym = rsym->usl.spillLoc;
2942         }
2943
2944       /* If the RECEIVE operand immediately spills to the first entry on the */
2945       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2946       /* rather than the usual @r0/r1 machinations. */
2947       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2948         {
2949           int ofs;
2950
2951           _G.current_iCode = ric;
2952           D(emitcode (";     genReceive",""));
2953           for (ofs=0; ofs < sym->recvSize; ofs++)
2954             {
2955               if (!strcmp (fReturn[ofs], "a"))
2956                 emitcode ("push", "acc");
2957               else
2958                 emitcode ("push", fReturn[ofs]);
2959             }
2960           stackAdjust -= sym->recvSize;
2961           if (stackAdjust<0)
2962             {
2963               assert (stackAdjust>=0);
2964               stackAdjust = 0;
2965             }
2966           _G.current_iCode = ic;
2967           ric->generated = 1;
2968           accIsFree = 1;
2969         }
2970       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2971       /* to free up the accumulator. */
2972       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2973         {
2974           int ofs;
2975
2976           _G.current_iCode = ric;
2977           D(emitcode (";     genReceive",""));
2978           for (ofs=0; ofs < sym->recvSize; ofs++)
2979             {
2980               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2981             }
2982           _G.current_iCode = ic;
2983           ric->generated = 1;
2984           accIsFree = 1;
2985         }
2986     }
2987
2988   /* adjust the stack for the function */
2989   if (stackAdjust)
2990     {
2991       int i = stackAdjust;
2992       if (i > 256)
2993         werror (W_STACK_OVERFLOW, sym->name);
2994
2995       if (i > 3 && accIsFree)
2996         {
2997           emitcode ("mov", "a,sp");
2998           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2999           emitcode ("mov", "sp,a");
3000         }
3001       else if (i > 5)
3002         {
3003           /* The accumulator is not free, so we will need another register */
3004           /* to clobber. No need to worry about a possible conflict with */
3005           /* the above early RECEIVE optimizations since they would have */
3006           /* freed the accumulator if they were generated. */
3007
3008           if (IFFUNC_CALLEESAVES(sym->type))
3009             {
3010               /* if it's a callee-saves function we need a saved register */
3011               if (calleesaves_saved_register >= 0)
3012                 {
3013                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3014                   emitcode ("mov", "a,sp");
3015                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3016                   emitcode ("mov", "sp,a");
3017                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3018                 }
3019               else
3020                 /* do it the hard way */
3021                 while (i--)
3022                   emitcode ("inc", "sp");
3023             }
3024           else
3025             {
3026               /* not callee-saves, we can clobber r0 */
3027               emitcode ("mov", "r0,a");
3028               emitcode ("mov", "a,sp");
3029               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3030               emitcode ("mov", "sp,a");
3031               emitcode ("mov", "a,r0");
3032             }
3033         }
3034       else
3035         while (i--)
3036           emitcode ("inc", "sp");
3037     }
3038
3039   if (sym->xstack)
3040     {
3041       char i = ((char) sym->xstack & 0xff);
3042
3043       if (i > 3 && accIsFree)
3044         {
3045           emitcode ("mov", "a,_spx");
3046           emitcode ("add", "a,#0x%02x", i);
3047           emitcode ("mov", "_spx,a");
3048         }
3049       else if (i > 5)
3050         {
3051           emitcode ("push", "acc");
3052           emitcode ("mov", "a,_spx");
3053           emitcode ("add", "a,#0x%02x", i);
3054           emitcode ("mov", "_spx,a");
3055           emitcode ("pop", "acc");
3056         }
3057       else
3058         {
3059           while (i--)
3060             emitcode ("inc", "_spx");
3061         }
3062     }
3063
3064   /* if critical function then turn interrupts off */
3065   if (IFFUNC_ISCRITICAL (ftype))
3066     {
3067       symbol *tlbl = newiTempLabel (NULL);
3068       emitcode ("setb", "c");
3069       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3070       emitcode ("clr", "c");
3071       emitcode ("", "%05d$:", (tlbl->key + 100));
3072       emitcode ("push", "psw"); /* save old ea via c in psw */
3073     }
3074 }
3075
3076 /*-----------------------------------------------------------------*/
3077 /* genEndFunction - generates epilogue for functions               */
3078 /*-----------------------------------------------------------------*/
3079 static void
3080 genEndFunction (iCode * ic)
3081 {
3082   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3083   lineNode *lnp = lineCurr;
3084   bitVect  *regsUsed;
3085   bitVect  *regsUsedPrologue;
3086   bitVect  *regsUnneeded;
3087   int      idx;
3088
3089   _G.currentFunc = NULL;
3090   if (IFFUNC_ISNAKED(sym->type))
3091   {
3092       emitcode(";", "naked function: no epilogue.");
3093       if (options.debug && currFunc)
3094         debugFile->writeEndFunction (currFunc, ic, 0);
3095       return;
3096   }
3097
3098   if (IFFUNC_ISCRITICAL (sym->type))
3099     {
3100       emitcode ("pop", "psw"); /* restore ea via c in psw */
3101       emitcode ("mov", "ea,c");
3102     }
3103
3104   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3105     {
3106       if (options.useXstack)
3107         {
3108           if (sym->stack)
3109             {
3110               emitcode ("mov", "sp,_bp");
3111               emitcode ("pop", "_bp");
3112             }
3113           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3114             {
3115               emitcode ("xch", "a,_bpx");
3116               emitcode ("mov", "r0,a");
3117               emitcode ("dec", "r0");
3118               emitcode ("movx", "a,@r0");
3119               emitcode ("xch", "a,_bpx");
3120               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3121             }
3122         }
3123       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3124         {
3125           emitcode ("mov", "sp,_bp");
3126           emitcode ("pop", "_bp");
3127         }
3128     }
3129
3130   /* restore the register bank  */
3131   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3132   {
3133     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3134      || !options.useXstack)
3135     {
3136         /* Special case of ISR using non-zero bank with useXstack
3137          * is handled below.
3138          */
3139         emitcode ("pop", "psw");
3140     }
3141   }
3142
3143   if (IFFUNC_ISISR (sym->type))
3144     {
3145
3146       /* now we need to restore the registers */
3147       /* if this isr has no bank i.e. is going to
3148          run with bank 0 , then we need to save more
3149          registers :-) */
3150       if (!FUNC_REGBANK (sym->type))
3151         {
3152           /* if this function does not call any other
3153              function then we can be economical and
3154              save only those registers that are used */
3155           if (!IFFUNC_HASFCALL(sym->type))
3156             {
3157               int i;
3158
3159               /* if any registers used */
3160               if (sym->regsUsed)
3161                 {
3162                   /* save the registers used */
3163                   for (i = sym->regsUsed->size; i >= 0; i--)
3164                     {
3165                       if (bitVectBitValue (sym->regsUsed, i))
3166                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3167                     }
3168                 }
3169             }
3170           else
3171             {
3172               if (options.parms_in_bank1) {
3173                   int i;
3174                   for (i = 7 ; i >= 0 ; i-- ) {
3175                       emitcode ("pop","%s",rb1regs[i]);
3176                   }
3177               }
3178               /* this function has  a function call cannot
3179                  determines register usage so we will have to pop the
3180                  entire bank */
3181               unsaveRBank (0, ic, FALSE);
3182             }
3183         }
3184         else
3185         {
3186             /* This ISR uses a non-zero bank.
3187              *
3188              * Restore any register banks saved by genFunction
3189              * in reverse order.
3190              */
3191             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3192             int ix;
3193
3194             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3195             {
3196                 if (savedBanks & (1 << ix))
3197                 {
3198                     unsaveRBank(ix, NULL, FALSE);
3199                 }
3200             }
3201
3202             if (options.useXstack)
3203             {
3204                 /* Restore bank AFTER calling unsaveRBank,
3205                  * since it can trash r0.
3206                  */
3207                 emitcode ("pop", "psw");
3208             }
3209         }
3210
3211       if (!inExcludeList ("dph"))
3212         emitcode ("pop", "dph");
3213       if (!inExcludeList ("dpl"))
3214         emitcode ("pop", "dpl");
3215       if (!inExcludeList ("b"))
3216         emitcode ("pop", "b");
3217       if (!inExcludeList ("acc"))
3218         emitcode ("pop", "acc");
3219
3220       /* if debug then send end of function */
3221       if (options.debug && currFunc)
3222         {
3223           debugFile->writeEndFunction (currFunc, ic, 1);
3224         }
3225
3226       emitcode ("reti", "");
3227     }
3228   else
3229     {
3230       if (IFFUNC_CALLEESAVES(sym->type))
3231         {
3232           int i;
3233
3234           /* if any registers used */
3235           if (sym->regsUsed)
3236             {
3237               /* save the registers used */
3238               for (i = sym->regsUsed->size; i >= 0; i--)
3239                 {
3240                   if (bitVectBitValue (sym->regsUsed, i) ||
3241                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3242                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3243                 }
3244             }
3245           else if (mcs51_ptrRegReq)
3246             {
3247               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3248               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3249             }
3250
3251         }
3252
3253       /* if debug then send end of function */
3254       if (options.debug && currFunc)
3255         {
3256           debugFile->writeEndFunction (currFunc, ic, 1);
3257         }
3258
3259       emitcode ("ret", "");
3260     }
3261
3262   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3263     return;
3264
3265   /* If this was an interrupt handler using bank 0 that called another */
3266   /* function, then all registers must be saved; nothing to optimized. */
3267   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3268       && !FUNC_REGBANK(sym->type))
3269     return;
3270
3271   /* There are no push/pops to optimize if not callee-saves or ISR */
3272   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3273     return;
3274
3275   /* If there were stack parameters, we cannot optimize without also    */
3276   /* fixing all of the stack offsets; this is too dificult to consider. */
3277   if (FUNC_HASSTACKPARM(sym->type))
3278     return;
3279
3280   /* Compute the registers actually used */
3281   regsUsed = newBitVect (mcs51_nRegs);
3282   regsUsedPrologue = newBitVect (mcs51_nRegs);
3283   while (lnp)
3284     {
3285       if (lnp->ic && lnp->ic->op == FUNCTION)
3286         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3287       else
3288         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3289
3290       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3291           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3292         break;
3293       if (!lnp->prev)
3294         break;
3295       lnp = lnp->prev;
3296     }
3297
3298   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3299       && !bitVectBitValue (regsUsed, CND_IDX))
3300     {
3301       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3302       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3303           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3304         bitVectUnSetBit (regsUsed, CND_IDX);
3305     }
3306   else
3307     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3308
3309   /* If this was an interrupt handler that called another function */
3310   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3311   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3312     {
3313       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3314       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3315       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3316       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3317       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3318     }
3319
3320   /* Remove the unneeded push/pops */
3321   regsUnneeded = newBitVect (mcs51_nRegs);
3322   while (lnp)
3323     {
3324       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3325         {
3326           if (!strncmp(lnp->line, "push", 4))
3327             {
3328               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3329               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3330                 {
3331                   connectLine (lnp->prev, lnp->next);
3332                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3333                 }
3334             }
3335           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3336             {
3337               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3338               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3339                 {
3340                   connectLine (lnp->prev, lnp->next);
3341                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3342                 }
3343             }
3344         }
3345       lnp = lnp->next;
3346     }
3347
3348   for (idx = 0; idx < regsUnneeded->size; idx++)
3349     if (bitVectBitValue (regsUnneeded, idx))
3350       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3351
3352   freeBitVect (regsUnneeded);
3353   freeBitVect (regsUsed);
3354   freeBitVect (regsUsedPrologue);
3355 }
3356
3357 /*-----------------------------------------------------------------*/
3358 /* genRet - generate code for return statement                     */
3359 /*-----------------------------------------------------------------*/
3360 static void
3361 genRet (iCode * ic)
3362 {
3363   int size, offset = 0, pushed = 0;
3364
3365   D(emitcode (";     genRet",""));
3366
3367   /* if we have no return value then
3368      just generate the "ret" */
3369   if (!IC_LEFT (ic))
3370     goto jumpret;
3371
3372   /* we have something to return then
3373      move the return value into place */
3374   aopOp (IC_LEFT (ic), ic, FALSE);
3375   size = AOP_SIZE (IC_LEFT (ic));
3376
3377   while (size--)
3378     {
3379       char *l;
3380       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3381         {
3382           /* #NOCHANGE */
3383           l = aopGet (IC_LEFT (ic), offset++,
3384                       FALSE, TRUE);
3385           emitcode ("push", "%s", l);
3386           pushed++;
3387         }
3388       else
3389         {
3390           l = aopGet (IC_LEFT (ic), offset,
3391                       FALSE, FALSE);
3392           if (strcmp (fReturn[offset], l))
3393             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3394         }
3395     }
3396
3397   if (pushed)
3398     {
3399       while (pushed)
3400         {
3401           pushed--;
3402           if (strcmp (fReturn[pushed], "a"))
3403             emitcode ("pop", fReturn[pushed]);
3404           else
3405             emitcode ("pop", "acc");
3406         }
3407     }
3408   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3409
3410 jumpret:
3411   /* generate a jump to the return label
3412      if the next is not the return statement */
3413   if (!(ic->next && ic->next->op == LABEL &&
3414         IC_LABEL (ic->next) == returnLabel))
3415
3416     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3417
3418 }
3419
3420 /*-----------------------------------------------------------------*/
3421 /* genLabel - generates a label                                    */
3422 /*-----------------------------------------------------------------*/
3423 static void
3424 genLabel (iCode * ic)
3425 {
3426   /* special case never generate */
3427   if (IC_LABEL (ic) == entryLabel)
3428     return;
3429
3430   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3431 }
3432
3433 /*-----------------------------------------------------------------*/
3434 /* genGoto - generates a ljmp                                      */
3435 /*-----------------------------------------------------------------*/
3436 static void
3437 genGoto (iCode * ic)
3438 {
3439   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3440 }
3441
3442 /*-----------------------------------------------------------------*/
3443 /* findLabelBackwards: walks back through the iCode chain looking  */
3444 /* for the given label. Returns number of iCode instructions     */
3445 /* between that label and given ic.          */
3446 /* Returns zero if label not found.          */
3447 /*-----------------------------------------------------------------*/
3448 static int
3449 findLabelBackwards (iCode * ic, int key)
3450 {
3451   int count = 0;
3452
3453   while (ic->prev)
3454     {
3455       ic = ic->prev;
3456       count++;
3457
3458       /* If we have any pushes or pops, we cannot predict the distance.
3459          I don't like this at all, this should be dealt with in the
3460          back-end */
3461       if (ic->op == IPUSH || ic->op == IPOP) {
3462         return 0;
3463       }
3464
3465       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3466         {
3467           return count;
3468         }
3469     }
3470
3471   return 0;
3472 }
3473
3474 /*-----------------------------------------------------------------*/
3475 /* genPlusIncr :- does addition with increment if possible         */
3476 /*-----------------------------------------------------------------*/
3477 static bool
3478 genPlusIncr (iCode * ic)
3479 {
3480   unsigned int icount;
3481   unsigned int size = getDataSize (IC_RESULT (ic));
3482
3483   /* will try to generate an increment */
3484   /* if the right side is not a literal
3485      we cannot */
3486   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3487     return FALSE;
3488
3489   /* if the literal value of the right hand side
3490      is greater than 4 then it is not worth it */
3491   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3492     return FALSE;
3493
3494   D(emitcode (";     genPlusIncr",""));
3495
3496   /* if increment >=16 bits in register or direct space */
3497   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3498       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3499       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3500       (size > 1) &&
3501       (icount == 1))
3502     {
3503       symbol *tlbl;
3504       int emitTlbl;
3505       int labelRange;
3506
3507       /* If the next instruction is a goto and the goto target
3508        * is < 10 instructions previous to this, we can generate
3509        * jumps straight to that target.
3510        */
3511       if (ic->next && ic->next->op == GOTO
3512           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3513           && labelRange <= 10)
3514         {
3515           emitcode (";", "tail increment optimized");
3516           tlbl = IC_LABEL (ic->next);
3517           emitTlbl = 0;
3518         }
3519       else
3520         {
3521           tlbl = newiTempLabel (NULL);
3522           emitTlbl = 1;
3523         }
3524       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3525       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3526           IS_AOP_PREG (IC_RESULT (ic)))
3527         emitcode ("cjne", "%s,#0x00,%05d$",
3528                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3529                   tlbl->key + 100);
3530       else
3531         {
3532           emitcode ("clr", "a");
3533           emitcode ("cjne", "a,%s,%05d$",
3534                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3535                     tlbl->key + 100);
3536         }
3537
3538       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3539       if (size > 2)
3540         {
3541           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3542               IS_AOP_PREG (IC_RESULT (ic)))
3543             emitcode ("cjne", "%s,#0x00,%05d$",
3544                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3545                       tlbl->key + 100);
3546           else
3547             emitcode ("cjne", "a,%s,%05d$",
3548                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3549                       tlbl->key + 100);
3550
3551           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3552         }
3553       if (size > 3)
3554         {
3555           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3556               IS_AOP_PREG (IC_RESULT (ic)))
3557             emitcode ("cjne", "%s,#0x00,%05d$",
3558                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3559                       tlbl->key + 100);
3560           else
3561             {
3562               emitcode ("cjne", "a,%s,%05d$",
3563                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3564                         tlbl->key + 100);
3565             }
3566           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3567         }
3568
3569       if (emitTlbl)
3570         {
3571           emitcode ("", "%05d$:", tlbl->key + 100);
3572         }
3573       return TRUE;
3574     }
3575
3576   /* if result is dptr */
3577   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
3578       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
3579       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
3580       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
3581     {
3582       if (aopGetUsesAcc (IC_LEFT (ic), 0))
3583         return FALSE;
3584
3585       if (icount > 9)
3586         return FALSE;
3587
3588       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
3589         return FALSE;
3590
3591       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
3592       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
3593       while (icount--)
3594         emitcode ("inc", "dptr");
3595
3596       return TRUE;
3597     }
3598
3599   /* if the sizes are greater than 1 then we cannot */
3600   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3601       AOP_SIZE (IC_LEFT (ic)) > 1)
3602     return FALSE;
3603
3604   /* we can if the aops of the left & result match or
3605      if they are in registers and the registers are the
3606      same */
3607   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3608     {
3609
3610       if (icount > 3)
3611         {
3612           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3613           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3614           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3615         }
3616       else
3617         {
3618
3619           while (icount--)
3620             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3621         }
3622
3623       return TRUE;
3624     }
3625
3626   return FALSE;
3627 }
3628
3629 /*-----------------------------------------------------------------*/
3630 /* outBitAcc - output a bit in acc                                 */
3631 /*-----------------------------------------------------------------*/
3632 static void
3633 outBitAcc (operand * result)
3634 {
3635   symbol *tlbl = newiTempLabel (NULL);
3636   /* if the result is a bit */
3637   if (AOP_TYPE (result) == AOP_CRY)
3638     {
3639       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
3640     }
3641   else
3642     {
3643       emitcode ("jz", "%05d$", tlbl->key + 100);
3644       emitcode ("mov", "a,%s", one);
3645       emitcode ("", "%05d$:", tlbl->key + 100);
3646       outAcc (result);
3647     }
3648 }
3649
3650 /*-----------------------------------------------------------------*/
3651 /* genPlusBits - generates code for addition of two bits           */
3652 /*-----------------------------------------------------------------*/
3653 static void
3654 genPlusBits (iCode * ic)
3655 {
3656   D(emitcode (";     genPlusBits",""));
3657
3658   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3659     {
3660       symbol *lbl = newiTempLabel (NULL);
3661       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3662       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3663       emitcode ("cpl", "c");
3664       emitcode ("", "%05d$:", (lbl->key + 100));
3665       outBitC (IC_RESULT (ic));
3666     }
3667   else
3668     {
3669       emitcode ("clr", "a");
3670       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3671       emitcode ("rlc", "a");
3672       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3673       emitcode ("addc", "a,#0x00");
3674       outAcc (IC_RESULT (ic));
3675     }
3676 }
3677
3678 #if 0
3679 /* This is the original version of this code.
3680
3681  * This is being kept around for reference,
3682  * because I am not entirely sure I got it right...
3683  */
3684 static void
3685 adjustArithmeticResult (iCode * ic)
3686 {
3687   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3688       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3689       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3690     aopPut (IC_RESULT (ic),
3691             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
3692             2,
3693             isOperandVolatile (IC_RESULT (ic), FALSE));
3694
3695   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3696       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3697       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3698     aopPut (IC_RESULT (ic),
3699             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
3700             2,
3701             isOperandVolatile (IC_RESULT (ic), FALSE));
3702
3703   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3704       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3705       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3706       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3707       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3708     {
3709       char buffer[5];
3710       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3711       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3712     }
3713 }
3714 #else
3715 /* This is the pure and virtuous version of this code.
3716  * I'm pretty certain it's right, but not enough to toss the old
3717  * code just yet...
3718  */
3719 static void
3720 adjustArithmeticResult (iCode * ic)
3721 {
3722   if (opIsGptr (IC_RESULT (ic)) &&
3723       opIsGptr (IC_LEFT (ic)) &&
3724       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3725     {
3726       aopPut (IC_RESULT (ic),
3727               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
3728               GPTRSIZE - 1,
3729               isOperandVolatile (IC_RESULT (ic), FALSE));
3730     }
3731
3732   if (opIsGptr (IC_RESULT (ic)) &&
3733       opIsGptr (IC_RIGHT (ic)) &&
3734       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3735     {
3736       aopPut (IC_RESULT (ic),
3737               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
3738               GPTRSIZE - 1,
3739               isOperandVolatile (IC_RESULT (ic), FALSE));
3740     }
3741
3742   if (opIsGptr (IC_RESULT (ic)) &&
3743       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3744       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3745       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3746       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3747     {
3748       char buffer[5];
3749       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3750       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3751     }
3752 }
3753 #endif
3754
3755 /*-----------------------------------------------------------------*/
3756 /* genPlus - generates code for addition                           */
3757 /*-----------------------------------------------------------------*/
3758 static void
3759 genPlus (iCode * ic)
3760 {
3761   int size, offset = 0;
3762   int skip_bytes = 0;
3763   char *add = "add";
3764   operand *leftOp, *rightOp;
3765   operand * op;
3766
3767   /* special cases :- */
3768
3769   D(emitcode (";     genPlus",""));
3770
3771   aopOp (IC_LEFT (ic), ic, FALSE);
3772   aopOp (IC_RIGHT (ic), ic, FALSE);
3773   aopOp (IC_RESULT (ic), ic, TRUE);
3774
3775   /* if literal, literal on the right or
3776      if left requires ACC or right is already
3777      in ACC */
3778   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3779       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3780       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3781     {
3782       operand *t = IC_RIGHT (ic);
3783       IC_RIGHT (ic) = IC_LEFT (ic);
3784       IC_LEFT (ic) = t;
3785     }
3786
3787   /* if both left & right are in bit
3788      space */
3789   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3790       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3791     {
3792       genPlusBits (ic);
3793       goto release;
3794     }
3795
3796   /* if left in bit space & right literal */
3797   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3798       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3799     {
3800       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3801       /* if result in bit space */
3802       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3803         {
3804           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3805             emitcode ("cpl", "c");
3806           outBitC (IC_RESULT (ic));
3807         }
3808       else
3809         {
3810           size = getDataSize (IC_RESULT (ic));
3811           while (size--)
3812             {
3813               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
3814               emitcode ("addc", "a,#00");
3815               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3816             }
3817         }
3818       goto release;
3819     }
3820
3821   /* if I can do an increment instead
3822      of add then GOOD for ME */
3823   if (genPlusIncr (ic) == TRUE)
3824     goto release;
3825
3826   size = getDataSize (IC_RESULT (ic));
3827   leftOp = IC_LEFT(ic);
3828   rightOp = IC_RIGHT(ic);
3829   op=IC_LEFT(ic);
3830
3831   /* if this is an add for an array access
3832      at a 256 byte boundary */
3833   if ( 2 == size
3834        && AOP_TYPE (op) == AOP_IMMD
3835        && IS_SYMOP (op)
3836        && IS_SPEC (OP_SYM_ETYPE (op))
3837        && SPEC_ABSA (OP_SYM_ETYPE (op))
3838        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3839      )
3840     {
3841       D(emitcode (";     genPlus aligned array",""));
3842       aopPut (IC_RESULT (ic),
3843               aopGet (rightOp, 0, FALSE, FALSE),
3844               0,
3845               isOperandVolatile (IC_RESULT (ic), FALSE));
3846
3847       if( 1 == getDataSize (IC_RIGHT (ic)) )
3848         {
3849           aopPut (IC_RESULT (ic),
3850                   aopGet (leftOp, 1, FALSE, FALSE),
3851                   1,
3852                   isOperandVolatile (IC_RESULT (ic), FALSE));
3853         }
3854       else
3855         {
3856           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
3857           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3858           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3859         }
3860       goto release;
3861     }
3862
3863   /* if the lower bytes of a literal are zero skip the addition */
3864   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3865     {
3866        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3867               (skip_bytes+1 < size))
3868          {
3869            skip_bytes++;
3870          }
3871        if (skip_bytes)
3872          D(emitcode (";     genPlus shortcut",""));
3873     }
3874
3875   while (size--)
3876     {
3877       if( offset >= skip_bytes )
3878         {
3879           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3880             {
3881               bool pushedB;
3882               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3883               pushedB = pushB ();
3884               emitcode("xch", "a,b");
3885               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3886               emitcode (add, "a,b");
3887               popB (pushedB);
3888             }
3889           else if (aopGetUsesAcc (leftOp, offset))
3890             {
3891               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3892               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3893             }
3894           else
3895             {
3896               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3897               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3898             }
3899           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3900           add = "addc";  /* further adds must propagate carry */
3901         }
3902       else
3903         {
3904           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3905               isOperandVolatile (IC_RESULT (ic), FALSE))
3906             {
3907               /* just move */
3908               aopPut (IC_RESULT (ic),
3909                       aopGet (leftOp, offset, FALSE, FALSE),
3910                       offset,
3911                       isOperandVolatile (IC_RESULT (ic), FALSE));
3912             }
3913         }
3914       offset++;
3915     }
3916
3917   adjustArithmeticResult (ic);
3918
3919 release:
3920   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3921   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3922   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3923 }
3924
3925 /*-----------------------------------------------------------------*/
3926 /* genMinusDec :- does subtraction with deccrement if possible     */
3927 /*-----------------------------------------------------------------*/
3928 static bool
3929 genMinusDec (iCode * ic)
3930 {
3931   unsigned int icount;
3932   unsigned int size = getDataSize (IC_RESULT (ic));
3933
3934   /* will try to generate an increment */
3935   /* if the right side is not a literal
3936      we cannot */
3937   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3938     return FALSE;
3939
3940   /* if the literal value of the right hand side
3941      is greater than 4 then it is not worth it */
3942   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3943     return FALSE;
3944
3945   D(emitcode (";     genMinusDec",""));
3946
3947   /* if decrement >=16 bits in register or direct space */
3948   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3949       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3950       (size > 1) &&
3951       (icount == 1))
3952     {
3953       symbol *tlbl;
3954       int emitTlbl;
3955       int labelRange;
3956
3957       /* If the next instruction is a goto and the goto target
3958        * is <= 10 instructions previous to this, we can generate
3959        * jumps straight to that target.
3960        */
3961       if (ic->next && ic->next->op == GOTO
3962           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3963           && labelRange <= 10)
3964         {
3965           emitcode (";", "tail decrement optimized");
3966           tlbl = IC_LABEL (ic->next);
3967           emitTlbl = 0;
3968         }
3969       else
3970         {
3971           tlbl = newiTempLabel (NULL);
3972           emitTlbl = 1;
3973         }
3974
3975       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3976       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3977           IS_AOP_PREG (IC_RESULT (ic)))
3978         emitcode ("cjne", "%s,#0xff,%05d$"
3979                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
3980                   ,tlbl->key + 100);
3981       else
3982         {
3983           emitcode ("mov", "a,#0xff");
3984           emitcode ("cjne", "a,%s,%05d$"
3985                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
3986                     ,tlbl->key + 100);
3987         }
3988       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3989       if (size > 2)
3990         {
3991           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3992               IS_AOP_PREG (IC_RESULT (ic)))
3993             emitcode ("cjne", "%s,#0xff,%05d$"
3994                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
3995                       ,tlbl->key + 100);
3996           else
3997             {
3998               emitcode ("cjne", "a,%s,%05d$"
3999                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4000                         ,tlbl->key + 100);
4001             }
4002           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4003         }
4004       if (size > 3)
4005         {
4006           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4007               IS_AOP_PREG (IC_RESULT (ic)))
4008             emitcode ("cjne", "%s,#0xff,%05d$"
4009                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4010                       ,tlbl->key + 100);
4011           else
4012             {
4013               emitcode ("cjne", "a,%s,%05d$"
4014                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4015                         ,tlbl->key + 100);
4016             }
4017           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4018         }
4019       if (emitTlbl)
4020         {
4021           emitcode ("", "%05d$:", tlbl->key + 100);
4022         }
4023       return TRUE;
4024     }
4025
4026   /* if the sizes are greater than 1 then we cannot */
4027   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4028       AOP_SIZE (IC_LEFT (ic)) > 1)
4029     return FALSE;
4030
4031   /* we can if the aops of the left & result match or
4032      if they are in registers and the registers are the
4033      same */
4034   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4035     {
4036
4037       while (icount--)
4038         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4039
4040       return TRUE;
4041     }
4042
4043   return FALSE;
4044 }
4045
4046 /*-----------------------------------------------------------------*/
4047 /* addSign - complete with sign                                    */
4048 /*-----------------------------------------------------------------*/
4049 static void
4050 addSign (operand * result, int offset, int sign)
4051 {
4052   int size = (getDataSize (result) - offset);
4053   if (size > 0)
4054     {
4055       if (sign)
4056         {
4057           emitcode ("rlc", "a");
4058           emitcode ("subb", "a,acc");
4059           while (size--)
4060             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4061         }
4062       else
4063         while (size--)
4064           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4065     }
4066 }
4067
4068 /*-----------------------------------------------------------------*/
4069 /* genMinusBits - generates code for subtraction  of two bits      */
4070 /*-----------------------------------------------------------------*/
4071 static void
4072 genMinusBits (iCode * ic)
4073 {
4074   symbol *lbl = newiTempLabel (NULL);
4075
4076   D(emitcode (";     genMinusBits",""));
4077
4078   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4079     {
4080       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4081       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4082       emitcode ("cpl", "c");
4083       emitcode ("", "%05d$:", (lbl->key + 100));
4084       outBitC (IC_RESULT (ic));
4085     }
4086   else
4087     {
4088       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4089       emitcode ("subb", "a,acc");
4090       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4091       emitcode ("inc", "a");
4092       emitcode ("", "%05d$:", (lbl->key + 100));
4093       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4094       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4095     }
4096 }
4097
4098 /*-----------------------------------------------------------------*/
4099 /* genMinus - generates code for subtraction                       */
4100 /*-----------------------------------------------------------------*/
4101 static void
4102 genMinus (iCode * ic)
4103 {
4104   int size, offset = 0;
4105
4106   D(emitcode (";     genMinus",""));
4107
4108   aopOp (IC_LEFT (ic), ic, FALSE);
4109   aopOp (IC_RIGHT (ic), ic, FALSE);
4110   aopOp (IC_RESULT (ic), ic, TRUE);
4111
4112   /* special cases :- */
4113   /* if both left & right are in bit space */
4114   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4115       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4116     {
4117       genMinusBits (ic);
4118       goto release;
4119     }
4120
4121   /* if I can do an decrement instead
4122      of subtract then GOOD for ME */
4123   if (genMinusDec (ic) == TRUE)
4124     goto release;
4125
4126   size = getDataSize (IC_RESULT (ic));
4127
4128   /* if literal, add a,#-lit, else normal subb */
4129   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4130     {
4131       unsigned long lit = 0L;
4132       bool useCarry = FALSE;
4133
4134       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4135       lit = -(long) lit;
4136
4137       while (size--)
4138         {
4139           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL)) {
4140             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4141             if (!offset && !size && lit== (unsigned long) -1) {
4142               emitcode ("dec", "a");
4143             } else if (!useCarry) {
4144           /* first add without previous c */
4145               emitcode ("add", "a,#0x%02x",
4146                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4147               useCarry = TRUE;
4148           } else {
4149             emitcode ("addc", "a,#0x%02x",
4150                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4151           }
4152             aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4153             } else {
4154               /* no need to add zeroes */
4155               offset++;
4156             }
4157         }
4158     }
4159   else
4160     {
4161       operand *leftOp, *rightOp;
4162
4163       leftOp = IC_LEFT(ic);
4164       rightOp = IC_RIGHT(ic);
4165
4166       while (size--)
4167         {
4168           if (aopGetUsesAcc(rightOp, offset)) {
4169             if (aopGetUsesAcc(leftOp, offset)) {
4170               bool pushedB;
4171
4172               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4173               pushedB = pushB ();
4174               emitcode ("mov", "b,a");
4175               if (offset == 0)
4176                 CLRC;
4177               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4178               emitcode ("subb", "a,b");
4179               popB (pushedB);
4180             } else {
4181               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4182               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4183               if (offset == 0) {
4184                 emitcode( "setb", "c");
4185               }
4186               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4187               emitcode("cpl", "a");
4188             }
4189           } else {
4190             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4191             if (offset == 0)
4192               CLRC;
4193             emitcode ("subb", "a,%s",
4194                       aopGet(rightOp, offset, FALSE, TRUE));
4195           }
4196
4197           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4198         }
4199     }
4200
4201
4202   adjustArithmeticResult (ic);
4203
4204 release:
4205   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4206   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4207   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4208 }
4209
4210
4211 /*-----------------------------------------------------------------*/
4212 /* genMultbits :- multiplication of bits                           */
4213 /*-----------------------------------------------------------------*/
4214 static void
4215 genMultbits (operand * left,
4216              operand * right,
4217              operand * result)
4218 {
4219   D(emitcode (";     genMultbits",""));
4220
4221   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4222   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4223   outBitC (result);
4224 }
4225
4226 /*-----------------------------------------------------------------*/
4227 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4228 /*-----------------------------------------------------------------*/
4229 static void
4230 genMultOneByte (operand * left,
4231                 operand * right,
4232                 operand * result)
4233 {
4234   symbol *lbl;
4235   int size = AOP_SIZE (result);
4236   bool runtimeSign, compiletimeSign;
4237   bool lUnsigned, rUnsigned, pushedB;
4238
4239   D(emitcode (";     genMultOneByte",""));
4240
4241   if (size < 1 || size > 2)
4242     {
4243       /* this should never happen */
4244       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4245                AOP_SIZE(result), __FILE__, lineno);
4246       exit (1);
4247     }
4248
4249   /* (if two literals: the value is computed before) */
4250   /* if one literal, literal on the right */
4251   if (AOP_TYPE (left) == AOP_LIT)
4252     {
4253       operand *t = right;
4254       right = left;
4255       left = t;
4256       /* emitcode (";", "swapped left and right"); */
4257     }
4258   /* if no literal, unsigned on the right: shorter code */
4259   if (   AOP_TYPE (right) != AOP_LIT
4260       && SPEC_USIGN (getSpec (operandType (left))))
4261     {
4262       operand *t = right;
4263       right = left;
4264       left = t;
4265     }
4266
4267   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4268   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4269
4270   pushedB = pushB ();
4271
4272   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4273                    no need to take care about the signedness! */
4274       || (lUnsigned && rUnsigned))
4275     {
4276       /* just an unsigned 8 * 8 = 8 multiply
4277          or 8u * 8u = 16u */
4278       /* emitcode (";","unsigned"); */
4279       /* TODO: check for accumulator clash between left & right aops? */
4280
4281       if (AOP_TYPE (right) == AOP_LIT)
4282         {
4283           /* moving to accumulator first helps peepholes */
4284           MOVA (aopGet (left, 0, FALSE, FALSE));
4285           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4286         }
4287       else
4288         {
4289           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4290           MOVA (aopGet (left, 0, FALSE, FALSE));
4291         }
4292
4293       emitcode ("mul", "ab");
4294       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4295       if (size == 2)
4296         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4297
4298       popB (pushedB);
4299       return;
4300     }
4301
4302   /* we have to do a signed multiply */
4303   /* emitcode (";", "signed"); */
4304
4305   /* now sign adjust for both left & right */
4306
4307   /* let's see what's needed: */
4308   /* apply negative sign during runtime */
4309   runtimeSign = FALSE;
4310   /* negative sign from literals */
4311   compiletimeSign = FALSE;
4312
4313   if (!lUnsigned)
4314     {
4315       if (AOP_TYPE(left) == AOP_LIT)
4316         {
4317           /* signed literal */
4318           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4319           if (val < 0)
4320             compiletimeSign = TRUE;
4321         }
4322       else
4323         /* signed but not literal */
4324         runtimeSign = TRUE;
4325     }
4326
4327   if (!rUnsigned)
4328     {
4329       if (AOP_TYPE(right) == AOP_LIT)
4330         {
4331           /* signed literal */
4332           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4333           if (val < 0)
4334             compiletimeSign ^= TRUE;
4335         }
4336       else
4337         /* signed but not literal */
4338         runtimeSign = TRUE;
4339     }
4340
4341   /* initialize F0, which stores the runtime sign */
4342   if (runtimeSign)
4343     {
4344       if (compiletimeSign)
4345         emitcode ("setb", "F0"); /* set sign flag */
4346       else
4347         emitcode ("clr", "F0"); /* reset sign flag */
4348     }
4349
4350   /* save the signs of the operands */
4351   if (AOP_TYPE(right) == AOP_LIT)
4352     {
4353       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4354
4355       if (!rUnsigned && val < 0)
4356         emitcode ("mov", "b,#0x%02x", -val);
4357       else
4358         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4359     }
4360   else /* ! literal */
4361     {
4362       if (rUnsigned)  /* emitcode (";", "signed"); */
4363
4364         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4365       else
4366         {
4367           MOVA (aopGet (right, 0, FALSE, FALSE));
4368           lbl = newiTempLabel (NULL);
4369           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4370           emitcode ("cpl", "F0"); /* complement sign flag */
4371           emitcode ("cpl", "a");  /* 2's complement */
4372           emitcode ("inc", "a");
4373           emitcode ("", "%05d$:", (lbl->key + 100));
4374           emitcode ("mov", "b,a");
4375         }
4376     }
4377
4378   if (AOP_TYPE(left) == AOP_LIT)
4379     {
4380       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4381
4382       if (!lUnsigned && val < 0)
4383         emitcode ("mov", "a,#0x%02x", -val);
4384       else
4385         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4386     }
4387   else /* ! literal */
4388     {
4389       MOVA (aopGet (left, 0, FALSE, FALSE));
4390
4391       if (!lUnsigned)
4392         {
4393           lbl = newiTempLabel (NULL);
4394           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4395           emitcode ("cpl", "F0"); /* complement sign flag */
4396           emitcode ("cpl", "a"); /* 2's complement */
4397           emitcode ("inc", "a");
4398           emitcode ("", "%05d$:", (lbl->key + 100));
4399         }
4400     }
4401
4402   /* now the multiplication */
4403   emitcode ("mul", "ab");
4404   if (runtimeSign || compiletimeSign)
4405     {
4406       lbl = newiTempLabel (NULL);
4407       if (runtimeSign)
4408         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4409       emitcode ("cpl", "a"); /* lsb 2's complement */
4410       if (size != 2)
4411         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4412       else
4413         {
4414           emitcode ("add", "a,#1"); /* this sets carry flag */
4415           emitcode ("xch", "a,b");
4416           emitcode ("cpl", "a"); /* msb 2's complement */
4417           emitcode ("addc", "a,#0");
4418           emitcode ("xch", "a,b");
4419         }
4420       emitcode ("", "%05d$:", (lbl->key + 100));
4421     }
4422   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4423   if (size == 2)
4424     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4425
4426   popB (pushedB);
4427 }
4428
4429 /*-----------------------------------------------------------------*/
4430 /* genMult - generates code for multiplication                     */
4431 /*-----------------------------------------------------------------*/
4432 static void
4433 genMult (iCode * ic)
4434 {
4435   operand *left = IC_LEFT (ic);
4436   operand *right = IC_RIGHT (ic);
4437   operand *result = IC_RESULT (ic);
4438
4439   D(emitcode (";     genMult",""));
4440
4441   /* assign the amsops */
4442   aopOp (left, ic, FALSE);
4443   aopOp (right, ic, FALSE);
4444   aopOp (result, ic, TRUE);
4445
4446   /* special cases first */
4447   /* both are bits */
4448   if (AOP_TYPE (left) == AOP_CRY &&
4449       AOP_TYPE (right) == AOP_CRY)
4450     {
4451       genMultbits (left, right, result);
4452       goto release;
4453     }
4454
4455   /* if both are of size == 1 */
4456 #if 0 // one of them can be a sloc shared with the result
4457     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4458 #else
4459   if (getSize(operandType(left)) == 1 &&
4460       getSize(operandType(right)) == 1)
4461 #endif
4462     {
4463       genMultOneByte (left, right, result);
4464       goto release;
4465     }
4466
4467   /* should have been converted to function call */
4468     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4469              getSize(OP_SYMBOL(right)->type));
4470   assert (0);
4471
4472 release:
4473   freeAsmop (result, NULL, ic, TRUE);
4474   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4475   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4476 }
4477
4478 /*-----------------------------------------------------------------*/
4479 /* genDivbits :- division of bits                                  */
4480 /*-----------------------------------------------------------------*/
4481 static void
4482 genDivbits (operand * left,
4483             operand * right,
4484             operand * result)
4485 {
4486   char *l;
4487   bool pushedB;
4488
4489   D(emitcode (";     genDivbits",""));
4490
4491   pushedB = pushB ();
4492
4493   /* the result must be bit */
4494   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4495   l = aopGet (left, 0, FALSE, FALSE);
4496
4497   MOVA (l);
4498
4499   emitcode ("div", "ab");
4500   emitcode ("rrc", "a");
4501
4502   popB (pushedB);
4503
4504   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4505 }
4506
4507 /*-----------------------------------------------------------------*/
4508 /* genDivOneByte : 8 bit division                                  */
4509 /*-----------------------------------------------------------------*/
4510 static void
4511 genDivOneByte (operand * left,
4512                operand * right,
4513                operand * result)
4514 {
4515   bool lUnsigned, rUnsigned, pushedB;
4516   bool runtimeSign, compiletimeSign;
4517   symbol *lbl;
4518   int size, offset;
4519
4520   D(emitcode (";     genDivOneByte",""));
4521
4522   /* Why is it necessary that genDivOneByte() can return an int result?
4523      Have a look at:
4524
4525         volatile unsigned char uc;
4526         volatile signed char sc1, sc2;
4527         volatile int i;
4528
4529         uc  = 255;
4530         sc1 = -1;
4531         i = uc / sc1;
4532
4533      Or:
4534
4535         sc1 = -128;
4536         sc2 = -1;
4537         i = sc1 / sc2;
4538
4539      In all cases a one byte result would overflow, the following cast to int
4540      would return the wrong result.
4541
4542      Two possible solution:
4543         a) cast operands to int, if ((unsigned) / (signed)) or
4544            ((signed) / (signed))
4545         b) return an 16 bit signed int; this is what we're doing here!
4546   */
4547
4548   size = AOP_SIZE (result) - 1;
4549   offset = 1;
4550   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4551   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4552
4553   pushedB = pushB ();
4554
4555   /* signed or unsigned */
4556   if (lUnsigned && rUnsigned)
4557     {
4558       /* unsigned is easy */
4559       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4560       MOVA (aopGet (left, 0, FALSE, FALSE));
4561       emitcode ("div", "ab");
4562       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4563       while (size--)
4564         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4565
4566       popB (pushedB);
4567       return;
4568     }
4569
4570   /* signed is a little bit more difficult */
4571
4572   /* now sign adjust for both left & right */
4573
4574   /* let's see what's needed: */
4575   /* apply negative sign during runtime */
4576   runtimeSign = FALSE;
4577   /* negative sign from literals */
4578   compiletimeSign = FALSE;
4579
4580   if (!lUnsigned)
4581     {
4582       if (AOP_TYPE(left) == AOP_LIT)
4583         {
4584           /* signed literal */
4585           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4586           if (val < 0)
4587             compiletimeSign = TRUE;
4588         }
4589       else
4590         /* signed but not literal */
4591         runtimeSign = TRUE;
4592     }
4593
4594   if (!rUnsigned)
4595     {
4596       if (AOP_TYPE(right) == AOP_LIT)
4597         {
4598           /* signed literal */
4599           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4600           if (val < 0)
4601             compiletimeSign ^= TRUE;
4602         }
4603       else
4604         /* signed but not literal */
4605         runtimeSign = TRUE;
4606     }
4607
4608   /* initialize F0, which stores the runtime sign */
4609   if (runtimeSign)
4610     {
4611       if (compiletimeSign)
4612         emitcode ("setb", "F0"); /* set sign flag */
4613       else
4614         emitcode ("clr", "F0"); /* reset sign flag */
4615     }
4616
4617   /* save the signs of the operands */
4618   if (AOP_TYPE(right) == AOP_LIT)
4619     {
4620       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4621
4622       if (!rUnsigned && val < 0)
4623         emitcode ("mov", "b,#0x%02x", -val);
4624       else
4625         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4626     }
4627   else /* ! literal */
4628     {
4629       if (rUnsigned)
4630         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4631       else
4632         {
4633           MOVA (aopGet (right, 0, FALSE, FALSE));
4634           lbl = newiTempLabel (NULL);
4635           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4636           emitcode ("cpl", "F0"); /* complement sign flag */
4637           emitcode ("cpl", "a");  /* 2's complement */
4638           emitcode ("inc", "a");
4639           emitcode ("", "%05d$:", (lbl->key + 100));
4640           emitcode ("mov", "b,a");
4641         }
4642     }
4643
4644   if (AOP_TYPE(left) == AOP_LIT)
4645     {
4646       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4647
4648       if (!lUnsigned && val < 0)
4649         emitcode ("mov", "a,#0x%02x", -val);
4650       else
4651         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4652     }
4653   else /* ! literal */
4654     {
4655       MOVA (aopGet (left, 0, FALSE, FALSE));
4656
4657       if (!lUnsigned)
4658         {
4659           lbl = newiTempLabel (NULL);
4660           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4661           emitcode ("cpl", "F0"); /* complement sign flag */
4662           emitcode ("cpl", "a");  /* 2's complement */
4663           emitcode ("inc", "a");
4664           emitcode ("", "%05d$:", (lbl->key + 100));
4665         }
4666     }
4667
4668   /* now the division */
4669   emitcode ("div", "ab");
4670
4671   if (runtimeSign || compiletimeSign)
4672     {
4673       lbl = newiTempLabel (NULL);
4674       if (runtimeSign)
4675         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4676       emitcode ("cpl", "a"); /* lsb 2's complement */
4677       emitcode ("inc", "a");
4678       emitcode ("", "%05d$:", (lbl->key + 100));
4679
4680       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4681       if (size > 0)
4682         {
4683           /* msb is 0x00 or 0xff depending on the sign */
4684           if (runtimeSign)
4685             {
4686               emitcode ("mov", "c,F0");
4687               emitcode ("subb", "a,acc");
4688               while (size--)
4689                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4690             }
4691           else /* compiletimeSign */
4692             while (size--)
4693               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4694         }
4695     }
4696   else
4697     {
4698       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4699       while (size--)
4700         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4701     }
4702
4703   popB (pushedB);
4704 }
4705
4706 /*-----------------------------------------------------------------*/
4707 /* genDiv - generates code for division                            */
4708 /*-----------------------------------------------------------------*/
4709 static void
4710 genDiv (iCode * ic)
4711 {
4712   operand *left = IC_LEFT (ic);
4713   operand *right = IC_RIGHT (ic);
4714   operand *result = IC_RESULT (ic);
4715
4716   D(emitcode (";     genDiv",""));
4717
4718   /* assign the amsops */
4719   aopOp (left, ic, FALSE);
4720   aopOp (right, ic, FALSE);
4721   aopOp (result, ic, TRUE);
4722
4723   /* special cases first */
4724   /* both are bits */
4725   if (AOP_TYPE (left) == AOP_CRY &&
4726       AOP_TYPE (right) == AOP_CRY)
4727     {
4728       genDivbits (left, right, result);
4729       goto release;
4730     }
4731
4732   /* if both are of size == 1 */
4733   if (AOP_SIZE (left) == 1 &&
4734       AOP_SIZE (right) == 1)
4735     {
4736       genDivOneByte (left, right, result);
4737       goto release;
4738     }
4739
4740   /* should have been converted to function call */
4741   assert (0);
4742 release:
4743   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4744   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4745   freeAsmop (result, NULL, ic, TRUE);
4746 }
4747
4748 /*-----------------------------------------------------------------*/
4749 /* genModbits :- modulus of bits                                   */
4750 /*-----------------------------------------------------------------*/
4751 static void
4752 genModbits (operand * left,
4753             operand * right,
4754             operand * result)
4755 {
4756   char *l;
4757   bool pushedB;
4758
4759   D(emitcode (";     genModbits",""));
4760
4761   pushedB = pushB ();
4762
4763   /* the result must be bit */
4764   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4765   l = aopGet (left, 0, FALSE, FALSE);
4766
4767   MOVA (l);
4768
4769   emitcode ("div", "ab");
4770   emitcode ("mov", "a,b");
4771   emitcode ("rrc", "a");
4772
4773   popB (pushedB);
4774
4775   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4776 }
4777
4778 /*-----------------------------------------------------------------*/
4779 /* genModOneByte : 8 bit modulus                                   */
4780 /*-----------------------------------------------------------------*/
4781 static void
4782 genModOneByte (operand * left,
4783                operand * right,
4784                operand * result)
4785 {
4786   bool lUnsigned, rUnsigned, pushedB;
4787   bool runtimeSign, compiletimeSign;
4788   symbol *lbl;
4789   int size, offset;
4790
4791   D(emitcode (";     genModOneByte",""));
4792
4793   size = AOP_SIZE (result) - 1;
4794   offset = 1;
4795   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4796   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4797
4798   /* if right is a literal, check it for 2^n */
4799   if (AOP_TYPE(right) == AOP_LIT)
4800     {
4801       unsigned char val = abs((int) operandLitValue(right));
4802       symbol *lbl2 = NULL;
4803
4804       switch (val)
4805         {
4806           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4807           case 2:
4808           case 4:
4809           case 8:
4810           case 16:
4811           case 32:
4812           case 64:
4813           case 128:
4814             if (lUnsigned)
4815               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4816                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4817               /* because iCode should have been changed to genAnd  */
4818               /* see file "SDCCopt.c", function "convertToFcall()" */
4819
4820             MOVA (aopGet (left, 0, FALSE, FALSE));
4821             emitcode ("mov", "c,acc.7");
4822             emitcode ("anl", "a,#0x%02x", val - 1);
4823             lbl = newiTempLabel (NULL);
4824             emitcode ("jz", "%05d$", (lbl->key + 100));
4825             emitcode ("jnc", "%05d$", (lbl->key + 100));
4826             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4827             if (size)
4828               {
4829                 int size2 = size;
4830                 int offs2 = offset;
4831
4832                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4833                 while (size2--)
4834                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
4835                 lbl2 = newiTempLabel (NULL);
4836                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4837               }
4838             emitcode ("", "%05d$:", (lbl->key + 100));
4839             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4840             while (size--)
4841               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4842             if (lbl2)
4843               {
4844                 emitcode ("", "%05d$:", (lbl2->key + 100));
4845               }
4846             return;
4847
4848           default:
4849             break;
4850         }
4851     }
4852
4853   pushedB = pushB ();
4854
4855   /* signed or unsigned */
4856   if (lUnsigned && rUnsigned)
4857     {
4858       /* unsigned is easy */
4859       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4860       MOVA (aopGet (left, 0, FALSE, FALSE));
4861       emitcode ("div", "ab");
4862       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4863       while (size--)
4864         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4865
4866       popB (pushedB);
4867       return;
4868     }
4869
4870   /* signed is a little bit more difficult */
4871
4872   /* now sign adjust for both left & right */
4873
4874   /* modulus: sign of the right operand has no influence on the result! */
4875   if (AOP_TYPE(right) == AOP_LIT)
4876     {
4877       signed char val = (char) operandLitValue(right);
4878
4879       if (!rUnsigned && val < 0)
4880         emitcode ("mov", "b,#0x%02x", -val);
4881       else
4882         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4883     }
4884   else /* not literal */
4885     {
4886       if (rUnsigned)
4887         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4888       else
4889         {
4890           MOVA (aopGet (right, 0, FALSE, FALSE));
4891           lbl = newiTempLabel (NULL);
4892           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4893           emitcode ("cpl", "a"); /* 2's complement */
4894           emitcode ("inc", "a");
4895           emitcode ("", "%05d$:", (lbl->key + 100));
4896           emitcode ("mov", "b,a");
4897         }
4898     }
4899
4900   /* let's see what's needed: */
4901   /* apply negative sign during runtime */
4902   runtimeSign = FALSE;
4903   /* negative sign from literals */
4904   compiletimeSign = FALSE;
4905
4906   /* sign adjust left side */
4907   if (AOP_TYPE(left) == AOP_LIT)
4908     {
4909       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4910
4911       if (!lUnsigned && val < 0)
4912         {
4913           compiletimeSign = TRUE; /* set sign flag */
4914           emitcode ("mov", "a,#0x%02x", -val);
4915         }
4916       else
4917         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4918     }
4919   else /* ! literal */
4920     {
4921       MOVA (aopGet (left, 0, FALSE, FALSE));
4922
4923       if (!lUnsigned)
4924         {
4925           runtimeSign = TRUE;
4926           emitcode ("clr", "F0"); /* clear sign flag */
4927
4928           lbl = newiTempLabel (NULL);
4929           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4930           emitcode ("setb", "F0"); /* set sign flag */
4931           emitcode ("cpl", "a");   /* 2's complement */
4932           emitcode ("inc", "a");
4933           emitcode ("", "%05d$:", (lbl->key + 100));
4934         }
4935     }
4936
4937   /* now the modulus */
4938   emitcode ("div", "ab");
4939
4940   if (runtimeSign || compiletimeSign)
4941     {
4942       emitcode ("mov", "a,b");
4943       lbl = newiTempLabel (NULL);
4944       if (runtimeSign)
4945         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4946       emitcode ("cpl", "a"); /* 2's complement */
4947       emitcode ("inc", "a");
4948       emitcode ("", "%05d$:", (lbl->key + 100));
4949
4950       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4951       if (size > 0)
4952         {
4953           /* msb is 0x00 or 0xff depending on the sign */
4954           if (runtimeSign)
4955             {
4956               emitcode ("mov", "c,F0");
4957               emitcode ("subb", "a,acc");
4958               while (size--)
4959                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4960             }
4961           else /* compiletimeSign */
4962             while (size--)
4963               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4964         }
4965     }
4966   else
4967     {
4968       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4969       while (size--)
4970         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4971     }
4972
4973   popB (pushedB);
4974 }
4975
4976 /*-----------------------------------------------------------------*/
4977 /* genMod - generates code for division                            */
4978 /*-----------------------------------------------------------------*/
4979 static void
4980 genMod (iCode * ic)
4981 {
4982   operand *left = IC_LEFT (ic);
4983   operand *right = IC_RIGHT (ic);
4984   operand *result = IC_RESULT (ic);
4985
4986   D(emitcode (";     genMod",""));
4987
4988   /* assign the asmops */
4989   aopOp (left, ic, FALSE);
4990   aopOp (right, ic, FALSE);
4991   aopOp (result, ic, TRUE);
4992
4993   /* special cases first */
4994   /* both are bits */
4995   if (AOP_TYPE (left) == AOP_CRY &&
4996       AOP_TYPE (right) == AOP_CRY)
4997     {
4998       genModbits (left, right, result);
4999       goto release;
5000     }
5001
5002   /* if both are of size == 1 */
5003   if (AOP_SIZE (left) == 1 &&
5004       AOP_SIZE (right) == 1)
5005     {
5006       genModOneByte (left, right, result);
5007       goto release;
5008     }
5009
5010   /* should have been converted to function call */
5011   assert (0);
5012
5013 release:
5014   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5015   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5016   freeAsmop (result, NULL, ic, TRUE);
5017 }
5018
5019 /*-----------------------------------------------------------------*/
5020 /* genIfxJump :- will create a jump depending on the ifx           */
5021 /*-----------------------------------------------------------------*/
5022 static void
5023 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5024 {
5025   symbol *jlbl;
5026   symbol *tlbl = newiTempLabel (NULL);
5027   char *inst;
5028
5029   D(emitcode (";     genIfxJump",""));
5030
5031   /* if true label then we jump if condition
5032      supplied is true */
5033   if (IC_TRUE (ic))
5034     {
5035       jlbl = IC_TRUE (ic);
5036       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5037                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5038     }
5039   else
5040     {
5041       /* false label is present */
5042       jlbl = IC_FALSE (ic);
5043       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5044                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5045     }
5046   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5047     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5048   else
5049     emitcode (inst, "%05d$", tlbl->key + 100);
5050   freeForBranchAsmop (result);
5051   freeForBranchAsmop (right);
5052   freeForBranchAsmop (left);
5053   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5054   emitcode ("", "%05d$:", tlbl->key + 100);
5055
5056   /* mark the icode as generated */
5057   ic->generated = 1;
5058 }
5059
5060 /*-----------------------------------------------------------------*/
5061 /* genCmp :- greater or less than comparison                       */
5062 /*-----------------------------------------------------------------*/
5063 static void
5064 genCmp (operand * left, operand * right,
5065         operand * result, iCode * ifx, int sign, iCode *ic)
5066 {
5067   int size, offset = 0;
5068   unsigned long lit = 0L;
5069   bool rightInB;
5070
5071   D(emitcode (";     genCmp",""));
5072
5073   /* if left & right are bit variables */
5074   if (AOP_TYPE (left) == AOP_CRY &&
5075       AOP_TYPE (right) == AOP_CRY)
5076     {
5077       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5078       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5079     }
5080   else
5081     {
5082       /* subtract right from left if at the
5083          end the carry flag is set then we know that
5084          left is greater than right */
5085       size = max (AOP_SIZE (left), AOP_SIZE (right));
5086
5087       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5088       if ((size == 1) && !sign &&
5089           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5090         {
5091           symbol *lbl = newiTempLabel (NULL);
5092           emitcode ("cjne", "%s,%s,%05d$",
5093                     aopGet (left, offset, FALSE, FALSE),
5094                     aopGet (right, offset, FALSE, FALSE),
5095                     lbl->key + 100);
5096           emitcode ("", "%05d$:", lbl->key + 100);
5097         }
5098       else
5099         {
5100           if (AOP_TYPE (right) == AOP_LIT)
5101             {
5102               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5103               /* optimize if(x < 0) or if(x >= 0) */
5104               if (lit == 0L)
5105                 {
5106                   if (!sign)
5107                     {
5108                       CLRC;
5109                     }
5110                   else
5111                     {
5112                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5113                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5114                         {
5115                           genIfxJump (ifx, "acc.7", left, right, result);
5116                           freeAsmop (right, NULL, ic, TRUE);
5117                           freeAsmop (left, NULL, ic, TRUE);
5118
5119                           return;
5120                         }
5121                       else
5122                         emitcode ("rlc", "a");
5123                     }
5124                   goto release;
5125                 }
5126             }
5127           CLRC;
5128           while (size--)
5129             {
5130               bool pushedB = FALSE;
5131               rightInB = aopGetUsesAcc(right, offset);
5132               if (rightInB)
5133                 {
5134                   pushedB = pushB ();
5135                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5136                 }
5137               MOVA (aopGet (left, offset, FALSE, FALSE));
5138               if (sign && size == 0)
5139                 {
5140                   emitcode ("xrl", "a,#0x80");
5141                   if (AOP_TYPE (right) == AOP_LIT)
5142                     {
5143                       unsigned long lit = (unsigned long)
5144                       floatFromVal (AOP (right)->aopu.aop_lit);
5145                       emitcode ("subb", "a,#0x%02x",
5146                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5147                     }
5148                   else
5149                     {
5150                       if (!rightInB)
5151                         {
5152                           pushedB = pushB ();
5153                           rightInB++;
5154                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5155                         }
5156                       emitcode ("xrl", "b,#0x80");
5157                       emitcode ("subb", "a,b");
5158                     }
5159                 }
5160               else
5161                 {
5162                   if (rightInB)
5163                     emitcode ("subb", "a,b");
5164                   else
5165                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5166                 }
5167               if (rightInB)
5168                 popB (pushedB);
5169               offset++;
5170             }
5171         }
5172     }
5173
5174 release:
5175   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5176   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5177   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5178     {
5179       outBitC (result);
5180     }
5181   else
5182     {
5183       /* if the result is used in the next
5184          ifx conditional branch then generate
5185          code a little differently */
5186       if (ifx)
5187         genIfxJump (ifx, "c", NULL, NULL, result);
5188       else
5189         outBitC (result);
5190       /* leave the result in acc */
5191     }
5192 }
5193
5194 /*-----------------------------------------------------------------*/
5195 /* genCmpGt :- greater than comparison                             */
5196 /*-----------------------------------------------------------------*/
5197 static void
5198 genCmpGt (iCode * ic, iCode * ifx)
5199 {
5200   operand *left, *right, *result;
5201   sym_link *letype, *retype;
5202   int sign;
5203
5204   D(emitcode (";     genCmpGt",""));
5205
5206   left = IC_LEFT (ic);
5207   right = IC_RIGHT (ic);
5208   result = IC_RESULT (ic);
5209
5210   letype = getSpec (operandType (left));
5211   retype = getSpec (operandType (right));
5212   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5213            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5214   /* assign the amsops */
5215   aopOp (left, ic, FALSE);
5216   aopOp (right, ic, FALSE);
5217   aopOp (result, ic, TRUE);
5218
5219   genCmp (right, left, result, ifx, sign, ic);
5220
5221   freeAsmop (result, NULL, ic, TRUE);
5222 }
5223
5224 /*-----------------------------------------------------------------*/
5225 /* genCmpLt - less than comparisons                                */
5226 /*-----------------------------------------------------------------*/
5227 static void
5228 genCmpLt (iCode * ic, iCode * ifx)
5229 {
5230   operand *left, *right, *result;
5231   sym_link *letype, *retype;
5232   int sign;
5233
5234   D(emitcode (";     genCmpLt",""));
5235
5236   left = IC_LEFT (ic);
5237   right = IC_RIGHT (ic);
5238   result = IC_RESULT (ic);
5239
5240   letype = getSpec (operandType (left));
5241   retype = getSpec (operandType (right));
5242   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5243            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5244   /* assign the amsops */
5245   aopOp (left, ic, FALSE);
5246   aopOp (right, ic, FALSE);
5247   aopOp (result, ic, TRUE);
5248
5249   genCmp (left, right, result, ifx, sign,ic);
5250
5251   freeAsmop (result, NULL, ic, TRUE);
5252 }
5253
5254 /*-----------------------------------------------------------------*/
5255 /* gencjneshort - compare and jump if not equal                    */
5256 /*-----------------------------------------------------------------*/
5257 static void
5258 gencjneshort (operand * left, operand * right, symbol * lbl)
5259 {
5260   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5261   int offset = 0;
5262   unsigned long lit = 0L;
5263
5264   /* if the left side is a literal or
5265      if the right is in a pointer register and left
5266      is not */
5267   if ((AOP_TYPE (left) == AOP_LIT) ||
5268       (AOP_TYPE (left) == AOP_IMMD) ||
5269       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5270     {
5271       operand *t = right;
5272       right = left;
5273       left = t;
5274     }
5275
5276   if (AOP_TYPE (right) == AOP_LIT)
5277     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5278
5279   /* if the right side is a literal then anything goes */
5280   if (AOP_TYPE (right) == AOP_LIT &&
5281       AOP_TYPE (left) != AOP_DIR  &&
5282       AOP_TYPE (left) != AOP_IMMD)
5283     {
5284       while (size--)
5285         {
5286           emitcode ("cjne", "%s,%s,%05d$",
5287                     aopGet (left, offset, FALSE, FALSE),
5288                     aopGet (right, offset, FALSE, FALSE),
5289                     lbl->key + 100);
5290           offset++;
5291         }
5292     }
5293
5294   /* if the right side is in a register or in direct space or
5295      if the left is a pointer register & right is not */
5296   else if (AOP_TYPE (right) == AOP_REG ||
5297            AOP_TYPE (right) == AOP_DIR ||
5298            AOP_TYPE (right) == AOP_LIT ||
5299            AOP_TYPE (right) == AOP_IMMD ||
5300            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5301            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5302     {
5303       while (size--)
5304         {
5305           MOVA (aopGet (left, offset, FALSE, FALSE));
5306           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5307               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5308             emitcode ("jnz", "%05d$", lbl->key + 100);
5309           else
5310             emitcode ("cjne", "a,%s,%05d$",
5311                       aopGet (right, offset, FALSE, TRUE),
5312                       lbl->key + 100);
5313           offset++;
5314         }
5315     }
5316   else
5317     {
5318       /* right is a pointer reg need both a & b */
5319       while (size--)
5320         {
5321           char *l;
5322           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5323           wassertl(!BINUSE, "B was in use");
5324           l = aopGet (left, offset, FALSE, FALSE);
5325           if (strcmp (l, "b"))
5326             emitcode ("mov", "b,%s", l);
5327           MOVA (aopGet (right, offset, FALSE, FALSE));
5328           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5329           offset++;
5330         }
5331     }
5332 }
5333
5334 /*-----------------------------------------------------------------*/
5335 /* gencjne - compare and jump if not equal                         */
5336 /*-----------------------------------------------------------------*/
5337 static void
5338 gencjne (operand * left, operand * right, symbol * lbl)
5339 {
5340   symbol *tlbl = newiTempLabel (NULL);
5341
5342   gencjneshort (left, right, lbl);
5343
5344   emitcode ("mov", "a,%s", one);
5345   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5346   emitcode ("", "%05d$:", lbl->key + 100);
5347   emitcode ("clr", "a");
5348   emitcode ("", "%05d$:", tlbl->key + 100);
5349 }
5350
5351 /*-----------------------------------------------------------------*/
5352 /* genCmpEq - generates code for equal to                          */
5353 /*-----------------------------------------------------------------*/
5354 static void
5355 genCmpEq (iCode * ic, iCode * ifx)
5356 {
5357   operand *left, *right, *result;
5358
5359   D(emitcode (";     genCmpEq",""));
5360
5361   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5362   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5363   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5364
5365   /* if literal, literal on the right or
5366      if the right is in a pointer register and left
5367      is not */
5368   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5369       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5370     {
5371       operand *t = IC_RIGHT (ic);
5372       IC_RIGHT (ic) = IC_LEFT (ic);
5373       IC_LEFT (ic) = t;
5374     }
5375
5376   if (ifx && !AOP_SIZE (result))
5377     {
5378       symbol *tlbl;
5379       /* if they are both bit variables */
5380       if (AOP_TYPE (left) == AOP_CRY &&
5381           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5382         {
5383           if (AOP_TYPE (right) == AOP_LIT)
5384             {
5385               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5386               if (lit == 0L)
5387                 {
5388                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5389                   emitcode ("cpl", "c");
5390                 }
5391               else if (lit == 1L)
5392                 {
5393                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5394                 }
5395               else
5396                 {
5397                   emitcode ("clr", "c");
5398                 }
5399               /* AOP_TYPE(right) == AOP_CRY */
5400             }
5401           else
5402             {
5403               symbol *lbl = newiTempLabel (NULL);
5404               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5405               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5406               emitcode ("cpl", "c");
5407               emitcode ("", "%05d$:", (lbl->key + 100));
5408             }
5409           /* if true label then we jump if condition
5410              supplied is true */
5411           tlbl = newiTempLabel (NULL);
5412           if (IC_TRUE (ifx))
5413             {
5414               emitcode ("jnc", "%05d$", tlbl->key + 100);
5415               freeForBranchAsmop (result);
5416               freeForBranchAsmop (right);
5417               freeForBranchAsmop (left);
5418               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5419             }
5420           else
5421             {
5422               emitcode ("jc", "%05d$", tlbl->key + 100);
5423               freeForBranchAsmop (result);
5424               freeForBranchAsmop (right);
5425               freeForBranchAsmop (left);
5426               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5427             }
5428           emitcode ("", "%05d$:", tlbl->key + 100);
5429         }
5430       else
5431         {
5432           tlbl = newiTempLabel (NULL);
5433           gencjneshort (left, right, tlbl);
5434           if (IC_TRUE (ifx))
5435             {
5436               freeForBranchAsmop (result);
5437               freeForBranchAsmop (right);
5438               freeForBranchAsmop (left);
5439               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5440               emitcode ("", "%05d$:", tlbl->key + 100);
5441             }
5442           else
5443             {
5444               symbol *lbl = newiTempLabel (NULL);
5445               emitcode ("sjmp", "%05d$", lbl->key + 100);
5446               emitcode ("", "%05d$:", tlbl->key + 100);
5447               freeForBranchAsmop (result);
5448               freeForBranchAsmop (right);
5449               freeForBranchAsmop (left);
5450               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5451               emitcode ("", "%05d$:", lbl->key + 100);
5452             }
5453         }
5454       /* mark the icode as generated */
5455       ifx->generated = 1;
5456       goto release;
5457     }
5458
5459   /* if they are both bit variables */
5460   if (AOP_TYPE (left) == AOP_CRY &&
5461       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5462     {
5463       if (AOP_TYPE (right) == AOP_LIT)
5464         {
5465           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5466           if (lit == 0L)
5467             {
5468               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5469               emitcode ("cpl", "c");
5470             }
5471           else if (lit == 1L)
5472             {
5473               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5474             }
5475           else
5476             {
5477               emitcode ("clr", "c");
5478             }
5479           /* AOP_TYPE(right) == AOP_CRY */
5480         }
5481       else
5482         {
5483           symbol *lbl = newiTempLabel (NULL);
5484           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5485           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5486           emitcode ("cpl", "c");
5487           emitcode ("", "%05d$:", (lbl->key + 100));
5488         }
5489       /* c = 1 if egal */
5490       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5491         {
5492           outBitC (result);
5493           goto release;
5494         }
5495       if (ifx)
5496         {
5497           genIfxJump (ifx, "c", left, right, result);
5498           goto release;
5499         }
5500       /* if the result is used in an arithmetic operation
5501          then put the result in place */
5502       outBitC (result);
5503     }
5504   else
5505     {
5506       gencjne (left, right, newiTempLabel (NULL));
5507       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5508         {
5509           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5510           goto release;
5511         }
5512       if (ifx)
5513         {
5514           genIfxJump (ifx, "a", left, right, result);
5515           goto release;
5516         }
5517       /* if the result is used in an arithmetic operation
5518          then put the result in place */
5519       if (AOP_TYPE (result) != AOP_CRY)
5520         outAcc (result);
5521       /* leave the result in acc */
5522     }
5523
5524 release:
5525   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5526   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5527   freeAsmop (result, NULL, ic, TRUE);
5528 }
5529
5530 /*-----------------------------------------------------------------*/
5531 /* ifxForOp - returns the icode containing the ifx for operand     */
5532 /*-----------------------------------------------------------------*/
5533 static iCode *
5534 ifxForOp (operand * op, iCode * ic)
5535 {
5536   /* if true symbol then needs to be assigned */
5537   if (IS_TRUE_SYMOP (op))
5538     return NULL;
5539
5540   /* if this has register type condition and
5541      the next instruction is ifx with the same operand
5542      and live to of the operand is upto the ifx only then */
5543   if (ic->next &&
5544       ic->next->op == IFX &&
5545       IC_COND (ic->next)->key == op->key &&
5546       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5547     return ic->next;
5548
5549   return NULL;
5550 }
5551
5552 /*-----------------------------------------------------------------*/
5553 /* hasInc - operand is incremented before any other use            */
5554 /*-----------------------------------------------------------------*/
5555 static iCode *
5556 hasInc (operand *op, iCode *ic,int osize)
5557 {
5558   sym_link *type = operandType(op);
5559   sym_link *retype = getSpec (type);
5560   iCode *lic = ic->next;
5561   int isize ;
5562
5563   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5564   if (!IS_SYMOP(op)) return NULL;
5565
5566   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5567   if (IS_AGGREGATE(type->next)) return NULL;
5568   if (osize != (isize = getSize(type->next))) return NULL;
5569
5570   while (lic) {
5571     /* if operand of the form op = op + <sizeof *op> */
5572     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5573         isOperandEqual(IC_RESULT(lic),op) &&
5574         isOperandLiteral(IC_RIGHT(lic)) &&
5575         operandLitValue(IC_RIGHT(lic)) == isize) {
5576       return lic;
5577     }
5578     /* if the operand used or deffed */
5579     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5580       return NULL;
5581     }
5582     /* if GOTO or IFX */
5583     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5584     lic = lic->next;
5585   }
5586   return NULL;
5587 }
5588
5589 /*-----------------------------------------------------------------*/
5590 /* genAndOp - for && operation                                     */
5591 /*-----------------------------------------------------------------*/
5592 static void
5593 genAndOp (iCode * ic)
5594 {
5595   operand *left, *right, *result;
5596   symbol *tlbl;
5597
5598   D(emitcode (";     genAndOp",""));
5599
5600   /* note here that && operations that are in an
5601      if statement are taken away by backPatchLabels
5602      only those used in arthmetic operations remain */
5603   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5604   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5605   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5606
5607   /* if both are bit variables */
5608   if (AOP_TYPE (left) == AOP_CRY &&
5609       AOP_TYPE (right) == AOP_CRY)
5610     {
5611       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5612       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5613       outBitC (result);
5614     }
5615   else
5616     {
5617       tlbl = newiTempLabel (NULL);
5618       toBoolean (left);
5619       emitcode ("jz", "%05d$", tlbl->key + 100);
5620       toBoolean (right);
5621       emitcode ("", "%05d$:", tlbl->key + 100);
5622       outBitAcc (result);
5623     }
5624
5625   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5626   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5627   freeAsmop (result, NULL, ic, TRUE);
5628 }
5629
5630
5631 /*-----------------------------------------------------------------*/
5632 /* genOrOp - for || operation                                      */
5633 /*-----------------------------------------------------------------*/
5634 static void
5635 genOrOp (iCode * ic)
5636 {
5637   operand *left, *right, *result;
5638   symbol *tlbl;
5639
5640   D(emitcode (";     genOrOp",""));
5641
5642   /* note here that || operations that are in an
5643      if statement are taken away by backPatchLabels
5644      only those used in arthmetic operations remain */
5645   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5646   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5647   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5648
5649   /* if both are bit variables */
5650   if (AOP_TYPE (left) == AOP_CRY &&
5651       AOP_TYPE (right) == AOP_CRY)
5652     {
5653       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5654       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5655       outBitC (result);
5656     }
5657   else
5658     {
5659       tlbl = newiTempLabel (NULL);
5660       toBoolean (left);
5661       emitcode ("jnz", "%05d$", tlbl->key + 100);
5662       toBoolean (right);
5663       emitcode ("", "%05d$:", tlbl->key + 100);
5664       outBitAcc (result);
5665     }
5666
5667   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5668   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5669   freeAsmop (result, NULL, ic, TRUE);
5670 }
5671
5672 /*-----------------------------------------------------------------*/
5673 /* isLiteralBit - test if lit == 2^n                               */
5674 /*-----------------------------------------------------------------*/
5675 static int
5676 isLiteralBit (unsigned long lit)
5677 {
5678   unsigned long pw[32] =
5679   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5680    0x100L, 0x200L, 0x400L, 0x800L,
5681    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5682    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5683    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5684    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5685    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5686   int idx;
5687
5688   for (idx = 0; idx < 32; idx++)
5689     if (lit == pw[idx])
5690       return idx + 1;
5691   return 0;
5692 }
5693
5694 /*-----------------------------------------------------------------*/
5695 /* continueIfTrue -                                                */
5696 /*-----------------------------------------------------------------*/
5697 static void
5698 continueIfTrue (iCode * ic)
5699 {
5700   if (IC_TRUE (ic))
5701     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5702   ic->generated = 1;
5703 }
5704
5705 /*-----------------------------------------------------------------*/
5706 /* jmpIfTrue -                                                     */
5707 /*-----------------------------------------------------------------*/
5708 static void
5709 jumpIfTrue (iCode * ic)
5710 {
5711   if (!IC_TRUE (ic))
5712     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5713   ic->generated = 1;
5714 }
5715
5716 /*-----------------------------------------------------------------*/
5717 /* jmpTrueOrFalse -                                                */
5718 /*-----------------------------------------------------------------*/
5719 static void
5720 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5721 {
5722   // ugly but optimized by peephole
5723   if (IC_TRUE (ic))
5724     {
5725       symbol *nlbl = newiTempLabel (NULL);
5726       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5727       emitcode ("", "%05d$:", tlbl->key + 100);
5728       freeForBranchAsmop (result);
5729       freeForBranchAsmop (right);
5730       freeForBranchAsmop (left);
5731       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5732       emitcode ("", "%05d$:", nlbl->key + 100);
5733     }
5734   else
5735     {
5736       freeForBranchAsmop (result);
5737       freeForBranchAsmop (right);
5738       freeForBranchAsmop (left);
5739       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5740       emitcode ("", "%05d$:", tlbl->key + 100);
5741     }
5742   ic->generated = 1;
5743 }
5744
5745 /*-----------------------------------------------------------------*/
5746 /* genAnd  - code for and                                          */
5747 /*-----------------------------------------------------------------*/
5748 static void
5749 genAnd (iCode * ic, iCode * ifx)
5750 {
5751   operand *left, *right, *result;
5752   int size, offset = 0;
5753   unsigned long lit = 0L;
5754   int bytelit = 0;
5755   char buffer[10];
5756
5757   D(emitcode (";     genAnd",""));
5758
5759   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5760   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5761   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5762
5763 #ifdef DEBUG_TYPE
5764   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5765             AOP_TYPE (result),
5766             AOP_TYPE (left), AOP_TYPE (right));
5767   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5768             AOP_SIZE (result),
5769             AOP_SIZE (left), AOP_SIZE (right));
5770 #endif
5771
5772   /* if left is a literal & right is not then exchange them */
5773   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5774       AOP_NEEDSACC (left))
5775     {
5776       operand *tmp = right;
5777       right = left;
5778       left = tmp;
5779     }
5780
5781   /* if result = right then exchange left and right */
5782   if (sameRegs (AOP (result), AOP (right)))
5783     {
5784       operand *tmp = right;
5785       right = left;
5786       left = tmp;
5787     }
5788
5789   /* if right is bit then exchange them */
5790   if (AOP_TYPE (right) == AOP_CRY &&
5791       AOP_TYPE (left) != AOP_CRY)
5792     {
5793       operand *tmp = right;
5794       right = left;
5795       left = tmp;
5796     }
5797   if (AOP_TYPE (right) == AOP_LIT)
5798     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5799
5800   size = AOP_SIZE (result);
5801
5802   // if(bit & yy)
5803   // result = bit & yy;
5804   if (AOP_TYPE (left) == AOP_CRY)
5805     {
5806       // c = bit & literal;
5807       if (AOP_TYPE (right) == AOP_LIT)
5808         {
5809           if (lit & 1)
5810             {
5811               if (size && sameRegs (AOP (result), AOP (left)))
5812                 // no change
5813                 goto release;
5814               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5815             }
5816           else
5817             {
5818               // bit(result) = 0;
5819               if (size && (AOP_TYPE (result) == AOP_CRY))
5820                 {
5821                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5822                   goto release;
5823                 }
5824               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5825                 {
5826                   jumpIfTrue (ifx);
5827                   goto release;
5828                 }
5829               emitcode ("clr", "c");
5830             }
5831         }
5832       else
5833         {
5834           if (AOP_TYPE (right) == AOP_CRY)
5835             {
5836               // c = bit & bit;
5837               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5838               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5839             }
5840           else
5841             {
5842               // c = bit & val;
5843               MOVA (aopGet (right, 0, FALSE, FALSE));
5844               // c = lsb
5845               emitcode ("rrc", "a");
5846               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5847             }
5848         }
5849       // bit = c
5850       // val = c
5851       if (size)
5852         outBitC (result);
5853       // if(bit & ...)
5854       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5855         genIfxJump (ifx, "c", left, right, result);
5856       goto release;
5857     }
5858
5859   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5860   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5861   if ((AOP_TYPE (right) == AOP_LIT) &&
5862       (AOP_TYPE (result) == AOP_CRY) &&
5863       (AOP_TYPE (left) != AOP_CRY))
5864     {
5865       int posbit = isLiteralBit (lit);
5866       /* left &  2^n */
5867       if (posbit)
5868         {
5869           posbit--;
5870           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
5871           // bit = left & 2^n
5872           if (size)
5873             {
5874               switch (posbit & 0x07)
5875                 {
5876                   case 0: emitcode ("rrc", "a");
5877                           break;
5878                   case 7: emitcode ("rlc", "a");
5879                           break;
5880                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5881                           break;
5882                 }
5883             }
5884           // if(left &  2^n)
5885           else
5886             {
5887               if (ifx)
5888                 {
5889                   SNPRINTF (buffer, sizeof(buffer),
5890                             "acc.%d", posbit & 0x07);
5891                   genIfxJump (ifx, buffer, left, right, result);
5892                 }
5893               else
5894                 {// what is this case? just found it in ds390/gen.c
5895                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5896                 }
5897               goto release;
5898             }
5899         }
5900       else
5901         {
5902           symbol *tlbl = newiTempLabel (NULL);
5903           int sizel = AOP_SIZE (left);
5904           if (size)
5905             emitcode ("setb", "c");
5906           while (sizel--)
5907             {
5908               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5909                 {
5910                   MOVA (aopGet (left, offset, FALSE, FALSE));
5911                   // byte ==  2^n ?
5912                   if ((posbit = isLiteralBit (bytelit)) != 0)
5913                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5914                   else
5915                     {
5916                       if (bytelit != 0x0FFL)
5917                         emitcode ("anl", "a,%s",
5918                                   aopGet (right, offset, FALSE, TRUE));
5919                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5920                     }
5921                 }
5922               offset++;
5923             }
5924           // bit = left & literal
5925           if (size)
5926             {
5927               emitcode ("clr", "c");
5928               emitcode ("", "%05d$:", tlbl->key + 100);
5929             }
5930           // if(left & literal)
5931           else
5932             {
5933               if (ifx)
5934                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5935               else
5936                 emitcode ("", "%05d$:", tlbl->key + 100);
5937               goto release;
5938             }
5939         }
5940       outBitC (result);
5941       goto release;
5942     }
5943
5944   /* if left is same as result */
5945   if (sameRegs (AOP (result), AOP (left)))
5946     {
5947       for (; size--; offset++)
5948         {
5949           if (AOP_TYPE (right) == AOP_LIT)
5950             {
5951               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5952               if (bytelit == 0x0FF)
5953                 {
5954                   /* dummy read of volatile operand */
5955                   if (isOperandVolatile (left, FALSE))
5956                     MOVA (aopGet (left, offset, FALSE, FALSE));
5957                   else
5958                     continue;
5959                 }
5960               else if (bytelit == 0)
5961                 {
5962                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
5963                 }
5964               else if (IS_AOP_PREG (result))
5965                 {
5966                   MOVA (aopGet (left, offset, FALSE, TRUE));
5967                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
5968                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
5969                 }
5970               else
5971                 emitcode ("anl", "%s,%s",
5972                           aopGet (left, offset, FALSE, TRUE),
5973                           aopGet (right, offset, FALSE, FALSE));
5974             }
5975           else
5976             {
5977               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
5978                 {
5979                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
5980                 }
5981               else
5982                 {
5983                   MOVA (aopGet (right, offset, FALSE, FALSE));
5984                   if (IS_AOP_PREG (result))
5985                     {
5986                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
5987                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
5988                     }
5989                   else
5990                     emitcode ("anl", "%s,a",
5991                               aopGet (left, offset, FALSE, TRUE));
5992                 }
5993             }
5994         }
5995     }
5996   else
5997     {
5998       // left & result in different registers
5999       if (AOP_TYPE (result) == AOP_CRY)
6000         {
6001           // result = bit
6002           // if(size), result in bit
6003           // if(!size && ifx), conditional oper: if(left & right)
6004           symbol *tlbl = newiTempLabel (NULL);
6005           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6006           if (size)
6007             emitcode ("setb", "c");
6008           while (sizer--)
6009             {
6010               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6011                   && AOP_TYPE(left)==AOP_ACC)
6012                 {
6013                   if (offset)
6014                     emitcode("mov", "a,b");
6015                   emitcode ("anl", "a,%s",
6016                             aopGet (right, offset, FALSE, FALSE));
6017                 } else {
6018                   if (AOP_TYPE(left)==AOP_ACC)
6019                     {
6020                       if (!offset)
6021                         {
6022                           bool pushedB = pushB ();
6023                           emitcode("mov", "b,a");
6024                           MOVA (aopGet (right, offset, FALSE, FALSE));
6025                           emitcode("anl", "a,b");
6026                           popB (pushedB);
6027                         }
6028                       else
6029                         {
6030                           MOVA (aopGet (right, offset, FALSE, FALSE));
6031                           emitcode("anl", "a,b");
6032                         }
6033                 } else {
6034                       MOVA (aopGet (right, offset, FALSE, FALSE));
6035                   emitcode ("anl", "a,%s",
6036                                 aopGet (left, offset, FALSE, FALSE));
6037                 }
6038               }
6039               emitcode ("jnz", "%05d$", tlbl->key + 100);
6040               offset++;
6041             }
6042           if (size)
6043             {
6044               CLRC;
6045               emitcode ("", "%05d$:", tlbl->key + 100);
6046               outBitC (result);
6047             }
6048           else if (ifx)
6049             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6050           else
6051             emitcode ("", "%05d$:", tlbl->key + 100);
6052         }
6053       else
6054         {
6055           for (; (size--); offset++)
6056             {
6057               // normal case
6058               // result = left & right
6059               if (AOP_TYPE (right) == AOP_LIT)
6060                 {
6061                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6062                   if (bytelit == 0x0FF)
6063                     {
6064                       aopPut (result,
6065                               aopGet (left, offset, FALSE, FALSE),
6066                               offset,
6067                               isOperandVolatile (result, FALSE));
6068                       continue;
6069                     }
6070                   else if (bytelit == 0)
6071                     {
6072                       /* dummy read of volatile operand */
6073                       if (isOperandVolatile (left, FALSE))
6074                         MOVA (aopGet (left, offset, FALSE, FALSE));
6075                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6076                       continue;
6077                     }
6078                   else if (AOP_TYPE (left) == AOP_ACC)
6079                     {
6080                       if (!offset)
6081                         {
6082                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6083                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6084                           continue;
6085                         }
6086                       else
6087                         {
6088                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6089                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6090                           continue;
6091                         }
6092                     }
6093                 }
6094               // faster than result <- left, anl result,right
6095               // and better if result is SFR
6096               if (AOP_TYPE (left) == AOP_ACC)
6097                 {
6098                   if (offset)
6099                     emitcode("mov", "a,b");
6100                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6101                 }
6102               else
6103                 {
6104                   MOVA (aopGet (right, offset, FALSE, FALSE));
6105                   emitcode ("anl", "a,%s",
6106                             aopGet (left, offset, FALSE, FALSE));
6107                 }
6108               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6109             }
6110         }
6111     }
6112
6113 release:
6114   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6115   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6116   freeAsmop (result, NULL, ic, TRUE);
6117 }
6118
6119 /*-----------------------------------------------------------------*/
6120 /* genOr  - code for or                                            */
6121 /*-----------------------------------------------------------------*/
6122 static void
6123 genOr (iCode * ic, iCode * ifx)
6124 {
6125   operand *left, *right, *result;
6126   int size, offset = 0;
6127   unsigned long lit = 0L;
6128   int bytelit = 0;
6129
6130   D(emitcode (";     genOr",""));
6131
6132   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6133   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6134   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6135
6136 #ifdef DEBUG_TYPE
6137   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6138             AOP_TYPE (result),
6139             AOP_TYPE (left), AOP_TYPE (right));
6140   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6141             AOP_SIZE (result),
6142             AOP_SIZE (left), AOP_SIZE (right));
6143 #endif
6144
6145   /* if left is a literal & right is not then exchange them */
6146   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6147       AOP_NEEDSACC (left))
6148     {
6149       operand *tmp = right;
6150       right = left;
6151       left = tmp;
6152     }
6153
6154   /* if result = right then exchange them */
6155   if (sameRegs (AOP (result), AOP (right)))
6156     {
6157       operand *tmp = right;
6158       right = left;
6159       left = tmp;
6160     }
6161
6162   /* if right is bit then exchange them */
6163   if (AOP_TYPE (right) == AOP_CRY &&
6164       AOP_TYPE (left) != AOP_CRY)
6165     {
6166       operand *tmp = right;
6167       right = left;
6168       left = tmp;
6169     }
6170   if (AOP_TYPE (right) == AOP_LIT)
6171     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6172
6173   size = AOP_SIZE (result);
6174
6175   // if(bit | yy)
6176   // xx = bit | yy;
6177   if (AOP_TYPE (left) == AOP_CRY)
6178     {
6179       if (AOP_TYPE (right) == AOP_LIT)
6180         {
6181           // c = bit | literal;
6182           if (lit)
6183             {
6184               // lit != 0 => result = 1
6185               if (AOP_TYPE (result) == AOP_CRY)
6186                 {
6187                   if (size)
6188                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6189                   else if (ifx)
6190                     continueIfTrue (ifx);
6191                   goto release;
6192                 }
6193               emitcode ("setb", "c");
6194             }
6195           else
6196             {
6197               // lit == 0 => result = left
6198               if (size && sameRegs (AOP (result), AOP (left)))
6199                 goto release;
6200               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6201             }
6202         }
6203       else
6204         {
6205           if (AOP_TYPE (right) == AOP_CRY)
6206             {
6207               // c = bit | bit;
6208               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6209               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6210             }
6211           else
6212             {
6213               // c = bit | val;
6214               symbol *tlbl = newiTempLabel (NULL);
6215               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6216                 emitcode ("setb", "c");
6217               emitcode ("jb", "%s,%05d$",
6218                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6219               toBoolean (right);
6220               emitcode ("jnz", "%05d$", tlbl->key + 100);
6221               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6222                 {
6223                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6224                   goto release;
6225                 }
6226               else
6227                 {
6228                   CLRC;
6229                   emitcode ("", "%05d$:", tlbl->key + 100);
6230                 }
6231             }
6232         }
6233       // bit = c
6234       // val = c
6235       if (size)
6236         outBitC (result);
6237       // if(bit | ...)
6238       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6239         genIfxJump (ifx, "c", left, right, result);
6240       goto release;
6241     }
6242
6243   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6244   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6245   if ((AOP_TYPE (right) == AOP_LIT) &&
6246       (AOP_TYPE (result) == AOP_CRY) &&
6247       (AOP_TYPE (left) != AOP_CRY))
6248     {
6249       if (lit)
6250         {
6251           // result = 1
6252           if (size)
6253             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6254           else
6255             continueIfTrue (ifx);
6256           goto release;
6257         }
6258       else
6259         {
6260           // lit = 0, result = boolean(left)
6261           if (size)
6262             emitcode ("setb", "c");
6263           toBoolean (right);
6264           if (size)
6265             {
6266               symbol *tlbl = newiTempLabel (NULL);
6267               emitcode ("jnz", "%05d$", tlbl->key + 100);
6268               CLRC;
6269               emitcode ("", "%05d$:", tlbl->key + 100);
6270             }
6271           else
6272             {
6273               genIfxJump (ifx, "a", left, right, result);
6274               goto release;
6275             }
6276         }
6277       outBitC (result);
6278       goto release;
6279     }
6280
6281   /* if left is same as result */
6282   if (sameRegs (AOP (result), AOP (left)))
6283     {
6284       for (; size--; offset++)
6285         {
6286           if (AOP_TYPE (right) == AOP_LIT)
6287             {
6288               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6289               if (bytelit == 0)
6290                 {
6291                   /* dummy read of volatile operand */
6292                   if (isOperandVolatile (left, FALSE))
6293                     MOVA (aopGet (left, offset, FALSE, FALSE));
6294                   else
6295                     continue;
6296                 }
6297               else if (bytelit == 0x0FF)
6298                 {
6299                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6300                 }
6301               else if (IS_AOP_PREG (left))
6302                 {
6303                   MOVA (aopGet (left, offset, FALSE, TRUE));
6304                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6305                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6306                 }
6307               else
6308                 {
6309                   emitcode ("orl", "%s,%s",
6310                             aopGet (left, offset, FALSE, TRUE),
6311                             aopGet (right, offset, FALSE, FALSE));
6312                 }
6313             }
6314           else
6315             {
6316               if (AOP_TYPE (left) == AOP_ACC)
6317                 {
6318                   if (offset)
6319                     emitcode("mov", "a,b");
6320                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6321                 }
6322               else
6323                 {
6324                   MOVA (aopGet (right, offset, FALSE, FALSE));
6325                   if (IS_AOP_PREG (left))
6326                     {
6327                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6328                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6329                     }
6330                   else
6331                     {
6332                       emitcode ("orl", "%s,a",
6333                                 aopGet (left, offset, FALSE, TRUE));
6334                     }
6335                 }
6336             }
6337         }
6338     }
6339   else
6340     {
6341       // left & result in different registers
6342       if (AOP_TYPE (result) == AOP_CRY)
6343         {
6344           // result = bit
6345           // if(size), result in bit
6346           // if(!size && ifx), conditional oper: if(left | right)
6347           symbol *tlbl = newiTempLabel (NULL);
6348           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6349           if (size)
6350             emitcode ("setb", "c");
6351           while (sizer--)
6352             {
6353               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6354                 if (offset)
6355                   emitcode("mov", "a,b");
6356                 emitcode ("orl", "a,%s",
6357                           aopGet (right, offset, FALSE, FALSE));
6358               } else {
6359                 MOVA (aopGet (right, offset, FALSE, FALSE));
6360                 emitcode ("orl", "a,%s",
6361                           aopGet (left, offset, FALSE, FALSE));
6362               }
6363               emitcode ("jnz", "%05d$", tlbl->key + 100);
6364               offset++;
6365             }
6366           if (size)
6367             {
6368               CLRC;
6369               emitcode ("", "%05d$:", tlbl->key + 100);
6370               outBitC (result);
6371             }
6372           else if (ifx)
6373             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6374           else
6375             emitcode ("", "%05d$:", tlbl->key + 100);
6376         }
6377       else
6378         {
6379           for (; (size--); offset++)
6380             {
6381               // normal case
6382               // result = left | right
6383               if (AOP_TYPE (right) == AOP_LIT)
6384                 {
6385                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6386                   if (bytelit == 0)
6387                     {
6388                       aopPut (result,
6389                               aopGet (left, offset, FALSE, FALSE),
6390                               offset,
6391                               isOperandVolatile (result, FALSE));
6392                       continue;
6393                     }
6394                   else if (bytelit == 0x0FF)
6395                     {
6396                       /* dummy read of volatile operand */
6397                       if (isOperandVolatile (left, FALSE))
6398                         MOVA (aopGet (left, offset, FALSE, FALSE));
6399                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6400                       continue;
6401                     }
6402                 }
6403               // faster than result <- left, anl result,right
6404               // and better if result is SFR
6405               if (AOP_TYPE (left) == AOP_ACC)
6406                 {
6407                   if (offset)
6408                     emitcode("mov", "a,b");
6409                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6410                 }
6411               else
6412                 {
6413                   MOVA (aopGet (right, offset, FALSE, FALSE));
6414                   emitcode ("orl", "a,%s",
6415                             aopGet (left, offset, FALSE, FALSE));
6416                 }
6417               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6418             }
6419         }
6420     }
6421
6422 release:
6423   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6425   freeAsmop (result, NULL, ic, TRUE);
6426 }
6427
6428 /*-----------------------------------------------------------------*/
6429 /* genXor - code for xclusive or                                   */
6430 /*-----------------------------------------------------------------*/
6431 static void
6432 genXor (iCode * ic, iCode * ifx)
6433 {
6434   operand *left, *right, *result;
6435   int size, offset = 0;
6436   unsigned long lit = 0L;
6437   int bytelit = 0;
6438
6439   D(emitcode (";     genXor",""));
6440
6441   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6442   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6443   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6444
6445 #ifdef DEBUG_TYPE
6446   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6447             AOP_TYPE (result),
6448             AOP_TYPE (left), AOP_TYPE (right));
6449   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6450             AOP_SIZE (result),
6451             AOP_SIZE (left), AOP_SIZE (right));
6452 #endif
6453
6454   /* if left is a literal & right is not ||
6455      if left needs acc & right does not */
6456   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6457       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6458     {
6459       operand *tmp = right;
6460       right = left;
6461       left = tmp;
6462     }
6463
6464   /* if result = right then exchange them */
6465   if (sameRegs (AOP (result), AOP (right)))
6466     {
6467       operand *tmp = right;
6468       right = left;
6469       left = tmp;
6470     }
6471
6472   /* if right is bit then exchange them */
6473   if (AOP_TYPE (right) == AOP_CRY &&
6474       AOP_TYPE (left) != AOP_CRY)
6475     {
6476       operand *tmp = right;
6477       right = left;
6478       left = tmp;
6479     }
6480   if (AOP_TYPE (right) == AOP_LIT)
6481     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6482
6483   size = AOP_SIZE (result);
6484
6485   // if(bit ^ yy)
6486   // xx = bit ^ yy;
6487   if (AOP_TYPE (left) == AOP_CRY)
6488     {
6489       if (AOP_TYPE (right) == AOP_LIT)
6490         {
6491           // c = bit & literal;
6492           if (lit >> 1)
6493             {
6494               // lit>>1  != 0 => result = 1
6495               if (AOP_TYPE (result) == AOP_CRY)
6496                 {
6497                   if (size)
6498                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6499                   else if (ifx)
6500                     continueIfTrue (ifx);
6501                   goto release;
6502                 }
6503               emitcode ("setb", "c");
6504             }
6505           else
6506             {
6507               // lit == (0 or 1)
6508               if (lit == 0)
6509                 {
6510                   // lit == 0, result = left
6511                   if (size && sameRegs (AOP (result), AOP (left)))
6512                     goto release;
6513                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6514                 }
6515               else
6516                 {
6517                   // lit == 1, result = not(left)
6518                   if (size && sameRegs (AOP (result), AOP (left)))
6519                     {
6520                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6521                       goto release;
6522                     }
6523                   else
6524                     {
6525                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6526                       emitcode ("cpl", "c");
6527                     }
6528                 }
6529             }
6530
6531         }
6532       else
6533         {
6534           // right != literal
6535           symbol *tlbl = newiTempLabel (NULL);
6536           if (AOP_TYPE (right) == AOP_CRY)
6537             {
6538               // c = bit ^ bit;
6539               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6540             }
6541           else
6542             {
6543               int sizer = AOP_SIZE (right);
6544               // c = bit ^ val
6545               // if val>>1 != 0, result = 1
6546               emitcode ("setb", "c");
6547               while (sizer)
6548                 {
6549                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6550                   if (sizer == 1)
6551                     // test the msb of the lsb
6552                     emitcode ("anl", "a,#0xfe");
6553                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6554                   sizer--;
6555                 }
6556               // val = (0,1)
6557               emitcode ("rrc", "a");
6558             }
6559           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6560           emitcode ("cpl", "c");
6561           emitcode ("", "%05d$:", (tlbl->key + 100));
6562         }
6563       // bit = c
6564       // val = c
6565       if (size)
6566         outBitC (result);
6567       // if(bit | ...)
6568       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6569         genIfxJump (ifx, "c", left, right, result);
6570       goto release;
6571     }
6572
6573   /* if left is same as result */
6574   if (sameRegs (AOP (result), AOP (left)))
6575     {
6576       for (; size--; offset++)
6577         {
6578           if (AOP_TYPE (right) == AOP_LIT)
6579             {
6580               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6581               if (bytelit == 0)
6582                 {
6583                   /* dummy read of volatile operand */
6584                   if (isOperandVolatile (left, FALSE))
6585                     MOVA (aopGet (left, offset, FALSE, FALSE));
6586                   else
6587                     continue;
6588                 }
6589               else if (IS_AOP_PREG (left))
6590                 {
6591                   MOVA (aopGet (left, offset, FALSE, TRUE));
6592                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6593                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6594                 }
6595               else
6596                 {
6597                   emitcode ("xrl", "%s,%s",
6598                             aopGet (left, offset, FALSE, TRUE),
6599                             aopGet (right, offset, FALSE, FALSE));
6600                 }
6601             }
6602           else
6603             {
6604               if (AOP_TYPE (left) == AOP_ACC)
6605                 {
6606                   if (offset)
6607                     emitcode("mov", "a,b");
6608                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6609                 }
6610               else
6611                 {
6612                   MOVA (aopGet (right, offset, FALSE, FALSE));
6613                   if (IS_AOP_PREG (left))
6614                     {
6615                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6616                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6617                     }
6618                   else
6619                     emitcode ("xrl", "%s,a",
6620                               aopGet (left, offset, FALSE, TRUE));
6621                 }
6622             }
6623         }
6624     }
6625   else
6626     {
6627       // left & result in different registers
6628       if (AOP_TYPE (result) == AOP_CRY)
6629         {
6630           // result = bit
6631           // if(size), result in bit
6632           // if(!size && ifx), conditional oper: if(left ^ right)
6633           symbol *tlbl = newiTempLabel (NULL);
6634           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6635           if (size)
6636             emitcode ("setb", "c");
6637           while (sizer--)
6638             {
6639               if ((AOP_TYPE (right) == AOP_LIT) &&
6640                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6641                 {
6642                   MOVA (aopGet (left, offset, FALSE, FALSE));
6643                 }
6644               else
6645                 {
6646                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6647                     if (offset)
6648                       emitcode("mov", "a,b");
6649                     emitcode ("xrl", "a,%s",
6650                               aopGet (right, offset, FALSE, FALSE));
6651                   } else {
6652                     MOVA (aopGet (right, offset, FALSE, FALSE));
6653                     emitcode ("xrl", "a,%s",
6654                               aopGet (left, offset, FALSE, FALSE));
6655                   }
6656                 }
6657               emitcode ("jnz", "%05d$", tlbl->key + 100);
6658               offset++;
6659             }
6660           if (size)
6661             {
6662               CLRC;
6663               emitcode ("", "%05d$:", tlbl->key + 100);
6664               outBitC (result);
6665             }
6666           else if (ifx)
6667             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6668         }
6669       else
6670         {
6671           for (; (size--); offset++)
6672             {
6673               // normal case
6674               // result = left & right
6675               if (AOP_TYPE (right) == AOP_LIT)
6676                 {
6677                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6678                   if (bytelit == 0)
6679                     {
6680                       aopPut (result,
6681                               aopGet (left, offset, FALSE, FALSE),
6682                               offset,
6683                               isOperandVolatile (result, FALSE));
6684                       continue;
6685                     }
6686                 }
6687               // faster than result <- left, anl result,right
6688               // and better if result is SFR
6689               if (AOP_TYPE (left) == AOP_ACC)
6690                 {
6691                   if (offset)
6692                     emitcode("mov", "a,b");
6693                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6694                 }
6695               else
6696                 {
6697                   MOVA (aopGet (right, offset, FALSE, FALSE));
6698                   emitcode ("xrl", "a,%s",
6699                             aopGet (left, offset, FALSE, TRUE));
6700                 }
6701               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6702             }
6703         }
6704     }
6705
6706 release:
6707   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6708   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6709   freeAsmop (result, NULL, ic, TRUE);
6710 }
6711
6712 /*-----------------------------------------------------------------*/
6713 /* genInline - write the inline code out                           */
6714 /*-----------------------------------------------------------------*/
6715 static void
6716 genInline (iCode * ic)
6717 {
6718   char *buffer, *bp, *bp1;
6719
6720   D(emitcode (";     genInline",""));
6721
6722   _G.inLine += (!options.asmpeep);
6723
6724   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6725   strcpy (buffer, IC_INLINE (ic));
6726
6727   /* emit each line as a code */
6728   while (*bp)
6729     {
6730       if (*bp == '\n')
6731         {
6732           *bp++ = '\0';
6733           emitcode (bp1, "");
6734           bp1 = bp;
6735         }
6736       else
6737         {
6738           /* Add \n for labels, not dirs such as c:\mydir */
6739           if ( (*bp == ':') && (isspace(bp[1])) )
6740             {
6741               bp++;
6742               *bp = '\0';
6743               bp++;
6744               emitcode (bp1, "");
6745               bp1 = bp;
6746             }
6747           else
6748             bp++;
6749         }
6750     }
6751   if (bp1 != bp)
6752     emitcode (bp1, "");
6753   /*     emitcode("",buffer); */
6754   _G.inLine -= (!options.asmpeep);
6755 }
6756
6757 /*-----------------------------------------------------------------*/
6758 /* genRRC - rotate right with carry                                */
6759 /*-----------------------------------------------------------------*/
6760 static void
6761 genRRC (iCode * ic)
6762 {
6763   operand *left, *result;
6764   int size, offset = 0;
6765   char *l;
6766
6767   D(emitcode (";     genRRC",""));
6768
6769   /* rotate right with carry */
6770   left = IC_LEFT (ic);
6771   result = IC_RESULT (ic);
6772   aopOp (left, ic, FALSE);
6773   aopOp (result, ic, FALSE);
6774
6775   /* move it to the result */
6776   size = AOP_SIZE (result);
6777   offset = size - 1;
6778   if (size == 1) { /* special case for 1 byte */
6779       l = aopGet (left, offset, FALSE, FALSE);
6780       MOVA (l);
6781       emitcode ("rr", "a");
6782       goto release;
6783   }
6784   /* no need to clear carry, bit7 will be written later */
6785   while (size--)
6786     {
6787       l = aopGet (left, offset, FALSE, FALSE);
6788       MOVA (l);
6789       emitcode ("rrc", "a");
6790       if (AOP_SIZE (result) > 1)
6791         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
6792     }
6793   /* now we need to put the carry into the
6794      highest order byte of the result */
6795   if (AOP_SIZE (result) > 1)
6796     {
6797       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
6798       MOVA (l);
6799     }
6800   emitcode ("mov", "acc.7,c");
6801  release:
6802   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6803   freeAsmop (left, NULL, ic, TRUE);
6804   freeAsmop (result, NULL, ic, TRUE);
6805 }
6806
6807 /*-----------------------------------------------------------------*/
6808 /* genRLC - generate code for rotate left with carry               */
6809 /*-----------------------------------------------------------------*/
6810 static void
6811 genRLC (iCode * ic)
6812 {
6813   operand *left, *result;
6814   int size, offset = 0;
6815   char *l;
6816
6817   D(emitcode (";     genRLC",""));
6818
6819   /* rotate right with carry */
6820   left = IC_LEFT (ic);
6821   result = IC_RESULT (ic);
6822   aopOp (left, ic, FALSE);
6823   aopOp (result, ic, FALSE);
6824
6825   /* move it to the result */
6826   size = AOP_SIZE (result);
6827   offset = 0;
6828   if (size--)
6829     {
6830       l = aopGet (left, offset, FALSE, FALSE);
6831       MOVA (l);
6832       if (size == 0) { /* special case for 1 byte */
6833               emitcode("rl","a");
6834               goto release;
6835       }
6836       emitcode("rlc","a"); /* bit0 will be written later */
6837       if (AOP_SIZE (result) > 1)
6838         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6839       while (size--)
6840         {
6841           l = aopGet (left, offset, FALSE, FALSE);
6842           MOVA (l);
6843           emitcode ("rlc", "a");
6844           if (AOP_SIZE (result) > 1)
6845             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6846         }
6847     }
6848   /* now we need to put the carry into the
6849      highest order byte of the result */
6850   if (AOP_SIZE (result) > 1)
6851     {
6852       l = aopGet (result, 0, FALSE, FALSE);
6853       MOVA (l);
6854     }
6855   emitcode ("mov", "acc.0,c");
6856  release:
6857   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6858   freeAsmop (left, NULL, ic, TRUE);
6859   freeAsmop (result, NULL, ic, TRUE);
6860 }
6861
6862 /*-----------------------------------------------------------------*/
6863 /* genGetHbit - generates code get highest order bit               */
6864 /*-----------------------------------------------------------------*/
6865 static void
6866 genGetHbit (iCode * ic)
6867 {
6868   operand *left, *result;
6869
6870   D(emitcode (";     genGetHbit",""));
6871
6872   left = IC_LEFT (ic);
6873   result = IC_RESULT (ic);
6874   aopOp (left, ic, FALSE);
6875   aopOp (result, ic, FALSE);
6876
6877   /* get the highest order byte into a */
6878   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
6879   if (AOP_TYPE (result) == AOP_CRY)
6880     {
6881       emitcode ("rlc", "a");
6882       outBitC (result);
6883     }
6884   else
6885     {
6886       emitcode ("rl", "a");
6887       emitcode ("anl", "a,#0x01");
6888       outAcc (result);
6889     }
6890
6891
6892   freeAsmop (left, NULL, ic, TRUE);
6893   freeAsmop (result, NULL, ic, TRUE);
6894 }
6895
6896 /*-----------------------------------------------------------------*/
6897 /* genSwap - generates code to swap nibbles or bytes               */
6898 /*-----------------------------------------------------------------*/
6899 static void
6900 genSwap (iCode * ic)
6901 {
6902   operand *left, *result;
6903
6904   D(emitcode (";     genSwap",""));
6905
6906   left = IC_LEFT (ic);
6907   result = IC_RESULT (ic);
6908   aopOp (left, ic, FALSE);
6909   aopOp (result, ic, FALSE);
6910
6911   switch (AOP_SIZE (left))
6912     {
6913     case 1: /* swap nibbles in byte */
6914       MOVA (aopGet (left, 0, FALSE, FALSE));
6915       emitcode ("swap", "a");
6916       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6917       break;
6918     case 2: /* swap bytes in word */
6919       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6920         {
6921           MOVA (aopGet (left, 0, FALSE, FALSE));
6922           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6923                   0, isOperandVolatile (result, FALSE));
6924           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
6925         }
6926       else if (operandsEqu (left, result))
6927         {
6928           char * reg = "a";
6929           bool pushedB = FALSE, leftInB = FALSE;
6930
6931           MOVA (aopGet (left, 0, FALSE, FALSE));
6932           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
6933             {
6934               pushedB = pushB ();
6935               emitcode ("mov", "b,a");
6936               reg = "b";
6937               leftInB = TRUE;
6938             }
6939           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6940                   0, isOperandVolatile (result, FALSE));
6941           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
6942
6943           if (leftInB)
6944             popB (pushedB);
6945         }
6946       else
6947         {
6948           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6949                   0, isOperandVolatile (result, FALSE));
6950           aopPut (result, aopGet (left, 0, FALSE, FALSE),
6951                   1, isOperandVolatile (result, FALSE));
6952         }
6953       break;
6954     default:
6955       wassertl(FALSE, "unsupported SWAP operand size");
6956     }
6957
6958   freeAsmop (left, NULL, ic, TRUE);
6959   freeAsmop (result, NULL, ic, TRUE);
6960 }
6961
6962
6963 /*-----------------------------------------------------------------*/
6964 /* AccRol - rotate left accumulator by known count                 */
6965 /*-----------------------------------------------------------------*/
6966 static void
6967 AccRol (int shCount)
6968 {
6969   shCount &= 0x0007;            // shCount : 0..7
6970
6971   switch (shCount)
6972     {
6973     case 0:
6974       break;
6975     case 1:
6976       emitcode ("rl", "a");
6977       break;
6978     case 2:
6979       emitcode ("rl", "a");
6980       emitcode ("rl", "a");
6981       break;
6982     case 3:
6983       emitcode ("swap", "a");
6984       emitcode ("rr", "a");
6985       break;
6986     case 4:
6987       emitcode ("swap", "a");
6988       break;
6989     case 5:
6990       emitcode ("swap", "a");
6991       emitcode ("rl", "a");
6992       break;
6993     case 6:
6994       emitcode ("rr", "a");
6995       emitcode ("rr", "a");
6996       break;
6997     case 7:
6998       emitcode ("rr", "a");
6999       break;
7000     }
7001 }
7002
7003 /*-----------------------------------------------------------------*/
7004 /* AccLsh - left shift accumulator by known count                  */
7005 /*-----------------------------------------------------------------*/
7006 static void
7007 AccLsh (int shCount)
7008 {
7009   if (shCount != 0)
7010     {
7011       if (shCount == 1)
7012         emitcode ("add", "a,acc");
7013       else if (shCount == 2)
7014         {
7015           emitcode ("add", "a,acc");
7016           emitcode ("add", "a,acc");
7017         }
7018       else
7019         {
7020           /* rotate left accumulator */
7021           AccRol (shCount);
7022           /* and kill the lower order bits */
7023           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7024         }
7025     }
7026 }
7027
7028 /*-----------------------------------------------------------------*/
7029 /* AccRsh - right shift accumulator by known count                 */
7030 /*-----------------------------------------------------------------*/
7031 static void
7032 AccRsh (int shCount)
7033 {
7034   if (shCount != 0)
7035     {
7036       if (shCount == 1)
7037         {
7038           CLRC;
7039           emitcode ("rrc", "a");
7040         }
7041       else
7042         {
7043           /* rotate right accumulator */
7044           AccRol (8 - shCount);
7045           /* and kill the higher order bits */
7046           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7047         }
7048     }
7049 }
7050
7051 /*-----------------------------------------------------------------*/
7052 /* AccSRsh - signed right shift accumulator by known count                 */
7053 /*-----------------------------------------------------------------*/
7054 static void
7055 AccSRsh (int shCount)
7056 {
7057   symbol *tlbl;
7058   if (shCount != 0)
7059     {
7060       if (shCount == 1)
7061         {
7062           emitcode ("mov", "c,acc.7");
7063           emitcode ("rrc", "a");
7064         }
7065       else if (shCount == 2)
7066         {
7067           emitcode ("mov", "c,acc.7");
7068           emitcode ("rrc", "a");
7069           emitcode ("mov", "c,acc.7");
7070           emitcode ("rrc", "a");
7071         }
7072       else
7073         {
7074           tlbl = newiTempLabel (NULL);
7075           /* rotate right accumulator */
7076           AccRol (8 - shCount);
7077           /* and kill the higher order bits */
7078           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7079           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7080           emitcode ("orl", "a,#0x%02x",
7081                     (unsigned char) ~SRMask[shCount]);
7082           emitcode ("", "%05d$:", tlbl->key + 100);
7083         }
7084     }
7085 }
7086
7087 /*-----------------------------------------------------------------*/
7088 /* shiftR1Left2Result - shift right one byte from left to result   */
7089 /*-----------------------------------------------------------------*/
7090 static void
7091 shiftR1Left2Result (operand * left, int offl,
7092                     operand * result, int offr,
7093                     int shCount, int sign)
7094 {
7095   MOVA (aopGet (left, offl, FALSE, FALSE));
7096   /* shift right accumulator */
7097   if (sign)
7098     AccSRsh (shCount);
7099   else
7100     AccRsh (shCount);
7101   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7102 }
7103
7104 /*-----------------------------------------------------------------*/
7105 /* shiftL1Left2Result - shift left one byte from left to result    */
7106 /*-----------------------------------------------------------------*/
7107 static void
7108 shiftL1Left2Result (operand * left, int offl,
7109                     operand * result, int offr, int shCount)
7110 {
7111   char *l;
7112   l = aopGet (left, offl, FALSE, FALSE);
7113   MOVA (l);
7114   /* shift left accumulator */
7115   AccLsh (shCount);
7116   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7117 }
7118
7119 /*-----------------------------------------------------------------*/
7120 /* movLeft2Result - move byte from left to result                  */
7121 /*-----------------------------------------------------------------*/
7122 static void
7123 movLeft2Result (operand * left, int offl,
7124                 operand * result, int offr, int sign)
7125 {
7126   char *l;
7127   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7128     {
7129       l = aopGet (left, offl, FALSE, FALSE);
7130
7131       if (*l == '@' && (IS_AOP_PREG (result)))
7132         {
7133           emitcode ("mov", "a,%s", l);
7134           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7135         }
7136       else
7137         {
7138           if (!sign)
7139             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7140           else
7141             {
7142               /* MSB sign in acc.7 ! */
7143               if (getDataSize (left) == offl + 1)
7144                 {
7145                   emitcode ("mov", "a,%s", l);
7146                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7147                 }
7148             }
7149         }
7150     }
7151 }
7152
7153 /*-----------------------------------------------------------------*/
7154 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7155 /*-----------------------------------------------------------------*/
7156 static void
7157 AccAXRrl1 (char *x)
7158 {
7159   emitcode ("rrc", "a");
7160   emitcode ("xch", "a,%s", x);
7161   emitcode ("rrc", "a");
7162   emitcode ("xch", "a,%s", x);
7163 }
7164
7165 /*-----------------------------------------------------------------*/
7166 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7167 /*-----------------------------------------------------------------*/
7168 static void
7169 AccAXLrl1 (char *x)
7170 {
7171   emitcode ("xch", "a,%s", x);
7172   emitcode ("rlc", "a");
7173   emitcode ("xch", "a,%s", x);
7174   emitcode ("rlc", "a");
7175 }
7176
7177 /*-----------------------------------------------------------------*/
7178 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7179 /*-----------------------------------------------------------------*/
7180 static void
7181 AccAXLsh1 (char *x)
7182 {
7183   emitcode ("xch", "a,%s", x);
7184   emitcode ("add", "a,acc");
7185   emitcode ("xch", "a,%s", x);
7186   emitcode ("rlc", "a");
7187 }
7188
7189 /*-----------------------------------------------------------------*/
7190 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7191 /*-----------------------------------------------------------------*/
7192 static void
7193 AccAXLsh (char *x, int shCount)
7194 {
7195   switch (shCount)
7196     {
7197     case 0:
7198       break;
7199     case 1:
7200       AccAXLsh1 (x);
7201       break;
7202     case 2:
7203       AccAXLsh1 (x);
7204       AccAXLsh1 (x);
7205       break;
7206     case 3:
7207     case 4:
7208     case 5:                     // AAAAABBB:CCCCCDDD
7209
7210       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7211
7212       emitcode ("anl", "a,#0x%02x",
7213                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7214
7215       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7216
7217       AccRol (shCount);         // DDDCCCCC:BBB00000
7218
7219       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7220
7221       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7222
7223       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7224
7225       emitcode ("anl", "a,#0x%02x",
7226                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7227
7228       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7229
7230       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7231
7232       break;
7233     case 6:                     // AAAAAABB:CCCCCCDD
7234       emitcode ("anl", "a,#0x%02x",
7235                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7236       emitcode ("mov", "c,acc.0");      // c = B
7237       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7238 #if 0 // REMOVE ME
7239       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7240       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7241 #else
7242       emitcode("rrc","a");
7243       emitcode("xch","a,%s", x);
7244       emitcode("rrc","a");
7245       emitcode("mov","c,acc.0"); //<< get correct bit
7246       emitcode("xch","a,%s", x);
7247
7248       emitcode("rrc","a");
7249       emitcode("xch","a,%s", x);
7250       emitcode("rrc","a");
7251       emitcode("xch","a,%s", x);
7252 #endif
7253       break;
7254     case 7:                     // a:x <<= 7
7255
7256       emitcode ("anl", "a,#0x%02x",
7257                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7258
7259       emitcode ("mov", "c,acc.0");      // c = B
7260
7261       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7262
7263       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7264
7265       break;
7266     default:
7267       break;
7268     }
7269 }
7270
7271 /*-----------------------------------------------------------------*/
7272 /* AccAXRsh - right shift a:x known count (0..7)                   */
7273 /*-----------------------------------------------------------------*/
7274 static void
7275 AccAXRsh (char *x, int shCount)
7276 {
7277   switch (shCount)
7278     {
7279     case 0:
7280       break;
7281     case 1:
7282       CLRC;
7283       AccAXRrl1 (x);            // 0->a:x
7284
7285       break;
7286     case 2:
7287       CLRC;
7288       AccAXRrl1 (x);            // 0->a:x
7289
7290       CLRC;
7291       AccAXRrl1 (x);            // 0->a:x
7292
7293       break;
7294     case 3:
7295     case 4:
7296     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7297
7298       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7299
7300       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7301
7302       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7303
7304       emitcode ("anl", "a,#0x%02x",
7305                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7306
7307       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7308
7309       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7310
7311       emitcode ("anl", "a,#0x%02x",
7312                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7313
7314       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7315
7316       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7317
7318       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7319
7320       break;
7321     case 6:                     // AABBBBBB:CCDDDDDD
7322
7323       emitcode ("mov", "c,acc.7");
7324       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7325
7326       emitcode ("mov", "c,acc.7");
7327       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7328
7329       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7330
7331       emitcode ("anl", "a,#0x%02x",
7332                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7333
7334       break;
7335     case 7:                     // ABBBBBBB:CDDDDDDD
7336
7337       emitcode ("mov", "c,acc.7");      // c = A
7338
7339       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7340
7341       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7342
7343       emitcode ("anl", "a,#0x%02x",
7344                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7345
7346       break;
7347     default:
7348       break;
7349     }
7350 }
7351
7352 /*-----------------------------------------------------------------*/
7353 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7354 /*-----------------------------------------------------------------*/
7355 static void
7356 AccAXRshS (char *x, int shCount)
7357 {
7358   symbol *tlbl;
7359   switch (shCount)
7360     {
7361     case 0:
7362       break;
7363     case 1:
7364       emitcode ("mov", "c,acc.7");
7365       AccAXRrl1 (x);            // s->a:x
7366
7367       break;
7368     case 2:
7369       emitcode ("mov", "c,acc.7");
7370       AccAXRrl1 (x);            // s->a:x
7371
7372       emitcode ("mov", "c,acc.7");
7373       AccAXRrl1 (x);            // s->a:x
7374
7375       break;
7376     case 3:
7377     case 4:
7378     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7379
7380       tlbl = newiTempLabel (NULL);
7381       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7382
7383       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7384
7385       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7386
7387       emitcode ("anl", "a,#0x%02x",
7388                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7389
7390       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7391
7392       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7393
7394       emitcode ("anl", "a,#0x%02x",
7395                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7396
7397       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7398
7399       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7400
7401       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7402
7403       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7404       emitcode ("orl", "a,#0x%02x",
7405                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7406
7407       emitcode ("", "%05d$:", tlbl->key + 100);
7408       break;                    // SSSSAAAA:BBBCCCCC
7409
7410     case 6:                     // AABBBBBB:CCDDDDDD
7411
7412       tlbl = newiTempLabel (NULL);
7413       emitcode ("mov", "c,acc.7");
7414       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7415
7416       emitcode ("mov", "c,acc.7");
7417       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7418
7419       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7420
7421       emitcode ("anl", "a,#0x%02x",
7422                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7423
7424       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7425       emitcode ("orl", "a,#0x%02x",
7426                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7427
7428       emitcode ("", "%05d$:", tlbl->key + 100);
7429       break;
7430     case 7:                     // ABBBBBBB:CDDDDDDD
7431
7432       tlbl = newiTempLabel (NULL);
7433       emitcode ("mov", "c,acc.7");      // c = A
7434
7435       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7436
7437       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7438
7439       emitcode ("anl", "a,#0x%02x",
7440                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7441
7442       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7443       emitcode ("orl", "a,#0x%02x",
7444                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7445
7446       emitcode ("", "%05d$:", tlbl->key + 100);
7447       break;
7448     default:
7449       break;
7450     }
7451 }
7452
7453 /*-----------------------------------------------------------------*/
7454 /* shiftL2Left2Result - shift left two bytes from left to result   */
7455 /*-----------------------------------------------------------------*/
7456 static void
7457 shiftL2Left2Result (operand * left, int offl,
7458                     operand * result, int offr, int shCount)
7459 {
7460   if (sameRegs (AOP (result), AOP (left)) &&
7461       ((offl + MSB16) == offr))
7462     {
7463       /* don't crash result[offr] */
7464       MOVA (aopGet (left, offl, FALSE, FALSE));
7465       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7466     }
7467   else
7468     {
7469       movLeft2Result (left, offl, result, offr, 0);
7470       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7471     }
7472   /* ax << shCount (x = lsb(result)) */
7473   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
7474   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7475 }
7476
7477
7478 /*-----------------------------------------------------------------*/
7479 /* shiftR2Left2Result - shift right two bytes from left to result  */
7480 /*-----------------------------------------------------------------*/
7481 static void
7482 shiftR2Left2Result (operand * left, int offl,
7483                     operand * result, int offr,
7484                     int shCount, int sign)
7485 {
7486   if (sameRegs (AOP (result), AOP (left)) &&
7487       ((offl + MSB16) == offr))
7488     {
7489       /* don't crash result[offr] */
7490       MOVA (aopGet (left, offl, FALSE, FALSE));
7491       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7492     }
7493   else
7494     {
7495       movLeft2Result (left, offl, result, offr, 0);
7496       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7497     }
7498   /* a:x >> shCount (x = lsb(result)) */
7499   if (sign)
7500     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
7501   else
7502     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
7503   if (getDataSize (result) > 1)
7504     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7505 }
7506
7507 /*-----------------------------------------------------------------*/
7508 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7509 /*-----------------------------------------------------------------*/
7510 static void
7511 shiftLLeftOrResult (operand * left, int offl,
7512                     operand * result, int offr, int shCount)
7513 {
7514   MOVA (aopGet (left, offl, FALSE, FALSE));
7515   /* shift left accumulator */
7516   AccLsh (shCount);
7517   /* or with result */
7518   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7519   /* back to result */
7520   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7521 }
7522
7523 /*-----------------------------------------------------------------*/
7524 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7525 /*-----------------------------------------------------------------*/
7526 static void
7527 shiftRLeftOrResult (operand * left, int offl,
7528                     operand * result, int offr, int shCount)
7529 {
7530   MOVA (aopGet (left, offl, FALSE, FALSE));
7531   /* shift right accumulator */
7532   AccRsh (shCount);
7533   /* or with result */
7534   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7535   /* back to result */
7536   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7537 }
7538
7539 /*-----------------------------------------------------------------*/
7540 /* genlshOne - left shift a one byte quantity by known count       */
7541 /*-----------------------------------------------------------------*/
7542 static void
7543 genlshOne (operand * result, operand * left, int shCount)
7544 {
7545   D(emitcode (";     genlshOne",""));
7546
7547   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7548 }
7549
7550 /*-----------------------------------------------------------------*/
7551 /* genlshTwo - left shift two bytes by known amount != 0           */
7552 /*-----------------------------------------------------------------*/
7553 static void
7554 genlshTwo (operand * result, operand * left, int shCount)
7555 {
7556   int size;
7557
7558   D(emitcode (";     genlshTwo",""));
7559
7560   size = getDataSize (result);
7561
7562   /* if shCount >= 8 */
7563   if (shCount >= 8)
7564     {
7565       shCount -= 8;
7566
7567       if (size > 1)
7568         {
7569           if (shCount)
7570             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7571           else
7572             movLeft2Result (left, LSB, result, MSB16, 0);
7573         }
7574       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7575     }
7576
7577   /*  1 <= shCount <= 7 */
7578   else
7579     {
7580       if (size == 1)
7581         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7582       else
7583         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7584     }
7585 }
7586
7587 /*-----------------------------------------------------------------*/
7588 /* shiftLLong - shift left one long from left to result            */
7589 /* offl = LSB or MSB16                                             */
7590 /*-----------------------------------------------------------------*/
7591 static void
7592 shiftLLong (operand * left, operand * result, int offr)
7593 {
7594   char *l;
7595   int size = AOP_SIZE (result);
7596
7597   if (size >= LSB + offr)
7598     {
7599       l = aopGet (left, LSB, FALSE, FALSE);
7600       MOVA (l);
7601       emitcode ("add", "a,acc");
7602       if (sameRegs (AOP (left), AOP (result)) &&
7603           size >= MSB16 + offr && offr != LSB)
7604         emitcode ("xch", "a,%s",
7605                   aopGet (left, LSB + offr, FALSE, FALSE));
7606       else
7607         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
7608     }
7609
7610   if (size >= MSB16 + offr)
7611     {
7612       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7613         {
7614           l = aopGet (left, MSB16, FALSE, FALSE);
7615           MOVA (l);
7616         }
7617       emitcode ("rlc", "a");
7618       if (sameRegs (AOP (left), AOP (result)) &&
7619           size >= MSB24 + offr && offr != LSB)
7620         emitcode ("xch", "a,%s",
7621                   aopGet (left, MSB16 + offr, FALSE, FALSE));
7622       else
7623         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7624     }
7625
7626   if (size >= MSB24 + offr)
7627     {
7628       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7629         {
7630           l = aopGet (left, MSB24, FALSE, FALSE);
7631           MOVA (l);
7632         }
7633       emitcode ("rlc", "a");
7634       if (sameRegs (AOP (left), AOP (result)) &&
7635           size >= MSB32 + offr && offr != LSB)
7636         emitcode ("xch", "a,%s",
7637                   aopGet (left, MSB24 + offr, FALSE, FALSE));
7638       else
7639         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7640     }
7641
7642   if (size > MSB32 + offr)
7643     {
7644       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7645         {
7646           l = aopGet (left, MSB32, FALSE, FALSE);
7647           MOVA (l);
7648         }
7649       emitcode ("rlc", "a");
7650       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7651     }
7652   if (offr != LSB)
7653     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7654 }
7655
7656 /*-----------------------------------------------------------------*/
7657 /* genlshFour - shift four byte by a known amount != 0             */
7658 /*-----------------------------------------------------------------*/
7659 static void
7660 genlshFour (operand * result, operand * left, int shCount)
7661 {
7662   int size;
7663
7664   D(emitcode (";     genlshFour",""));
7665
7666   size = AOP_SIZE (result);
7667
7668   /* if shifting more that 3 bytes */
7669   if (shCount >= 24)
7670     {
7671       shCount -= 24;
7672       if (shCount)
7673         /* lowest order of left goes to the highest
7674            order of the destination */
7675         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7676       else
7677         movLeft2Result (left, LSB, result, MSB32, 0);
7678       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7679       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7680       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
7681       return;
7682     }
7683
7684   /* more than two bytes */
7685   else if (shCount >= 16)
7686     {
7687       /* lower order two bytes goes to higher order two bytes */
7688       shCount -= 16;
7689       /* if some more remaining */
7690       if (shCount)
7691         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7692       else
7693         {
7694           movLeft2Result (left, MSB16, result, MSB32, 0);
7695           movLeft2Result (left, LSB, result, MSB24, 0);
7696         }
7697       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7698       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7699       return;
7700     }
7701
7702   /* if more than 1 byte */
7703   else if (shCount >= 8)
7704     {
7705       /* lower order three bytes goes to higher order  three bytes */
7706       shCount -= 8;
7707       if (size == 2)
7708         {
7709           if (shCount)
7710             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7711           else
7712             movLeft2Result (left, LSB, result, MSB16, 0);
7713         }
7714       else
7715         {                       /* size = 4 */
7716           if (shCount == 0)
7717             {
7718               movLeft2Result (left, MSB24, result, MSB32, 0);
7719               movLeft2Result (left, MSB16, result, MSB24, 0);
7720               movLeft2Result (left, LSB, result, MSB16, 0);
7721               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7722             }
7723           else if (shCount == 1)
7724             shiftLLong (left, result, MSB16);
7725           else
7726             {
7727               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7728               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7729               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7730               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7731             }
7732         }
7733     }
7734
7735   /* 1 <= shCount <= 7 */
7736   else if (shCount <= 2)
7737     {
7738       shiftLLong (left, result, LSB);
7739       if (shCount == 2)
7740         shiftLLong (result, result, LSB);
7741     }
7742   /* 3 <= shCount <= 7, optimize */
7743   else
7744     {
7745       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7746       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7747       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7748     }
7749 }
7750
7751 /*-----------------------------------------------------------------*/
7752 /* genLeftShiftLiteral - left shifting by known count              */
7753 /*-----------------------------------------------------------------*/
7754 static void
7755 genLeftShiftLiteral (operand * left,
7756                      operand * right,
7757                      operand * result,
7758                      iCode * ic)
7759 {
7760   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7761   int size;
7762
7763   D(emitcode (";     genLeftShiftLiteral",""));
7764
7765   freeAsmop (right, NULL, ic, TRUE);
7766
7767   aopOp (left, ic, FALSE);
7768   aopOp (result, ic, FALSE);
7769
7770   size = getSize (operandType (result));
7771
7772 #if VIEW_SIZE
7773   emitcode ("; shift left ", "result %d, left %d", size,
7774             AOP_SIZE (left));
7775 #endif
7776
7777   /* I suppose that the left size >= result size */
7778   if (shCount == 0)
7779     {
7780       while (size--)
7781         {
7782           movLeft2Result (left, size, result, size, 0);
7783         }
7784     }
7785
7786   else if (shCount >= (size * 8))
7787     while (size--)
7788       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
7789   else
7790     {
7791       switch (size)
7792         {
7793         case 1:
7794           genlshOne (result, left, shCount);
7795           break;
7796
7797         case 2:
7798           genlshTwo (result, left, shCount);
7799           break;
7800
7801         case 4:
7802           genlshFour (result, left, shCount);
7803           break;
7804         default:
7805           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7806                   "*** ack! mystery literal shift!\n");
7807           break;
7808         }
7809     }
7810   freeAsmop (left, NULL, ic, TRUE);
7811   freeAsmop (result, NULL, ic, TRUE);
7812 }
7813
7814 /*-----------------------------------------------------------------*/
7815 /* genLeftShift - generates code for left shifting                 */
7816 /*-----------------------------------------------------------------*/
7817 static void
7818 genLeftShift (iCode * ic)
7819 {
7820   operand *left, *right, *result;
7821   int size, offset;
7822   char *l;
7823   symbol *tlbl, *tlbl1;
7824   bool pushedB;
7825
7826   D(emitcode (";     genLeftShift",""));
7827
7828   right = IC_RIGHT (ic);
7829   left = IC_LEFT (ic);
7830   result = IC_RESULT (ic);
7831
7832   aopOp (right, ic, FALSE);
7833
7834   /* if the shift count is known then do it
7835      as efficiently as possible */
7836   if (AOP_TYPE (right) == AOP_LIT)
7837     {
7838       genLeftShiftLiteral (left, right, result, ic);
7839       return;
7840     }
7841
7842   /* shift count is unknown then we have to form
7843      a loop get the loop count in B : Note: we take
7844      only the lower order byte since shifting
7845      more that 32 bits make no sense anyway, ( the
7846      largest size of an object can be only 32 bits ) */
7847
7848   pushedB = pushB ();
7849   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
7850   emitcode ("inc", "b");
7851   freeAsmop (right, NULL, ic, TRUE);
7852   aopOp (left, ic, FALSE);
7853   aopOp (result, ic, FALSE);
7854
7855   /* now move the left to the result if they are not the same */
7856   if (!sameRegs (AOP (left), AOP (result)) &&
7857       AOP_SIZE (result) > 1)
7858     {
7859
7860       size = AOP_SIZE (result);
7861       offset = 0;
7862       while (size--)
7863         {
7864           l = aopGet (left, offset, FALSE, TRUE);
7865           if (*l == '@' && (IS_AOP_PREG (result)))
7866             {
7867
7868               emitcode ("mov", "a,%s", l);
7869               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7870             }
7871           else
7872             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
7873           offset++;
7874         }
7875     }
7876
7877   tlbl = newiTempLabel (NULL);
7878   size = AOP_SIZE (result);
7879   offset = 0;
7880   tlbl1 = newiTempLabel (NULL);
7881
7882   /* if it is only one byte then */
7883   if (size == 1)
7884     {
7885       symbol *tlbl1 = newiTempLabel (NULL);
7886
7887       l = aopGet (left, 0, FALSE, FALSE);
7888       MOVA (l);
7889       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7890       emitcode ("", "%05d$:", tlbl->key + 100);
7891       emitcode ("add", "a,acc");
7892       emitcode ("", "%05d$:", tlbl1->key + 100);
7893       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7894       popB (pushedB);
7895       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7896       goto release;
7897     }
7898
7899   reAdjustPreg (AOP (result));
7900
7901   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7902   emitcode ("", "%05d$:", tlbl->key + 100);
7903   l = aopGet (result, offset, FALSE, FALSE);
7904   MOVA (l);
7905   emitcode ("add", "a,acc");
7906   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7907   while (--size)
7908     {
7909       l = aopGet (result, offset, FALSE, FALSE);
7910       MOVA (l);
7911       emitcode ("rlc", "a");
7912       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7913     }
7914   reAdjustPreg (AOP (result));
7915
7916   emitcode ("", "%05d$:", tlbl1->key + 100);
7917   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7918   popB (pushedB);
7919 release:
7920   freeAsmop (left, NULL, ic, TRUE);
7921   freeAsmop (result, NULL, ic, TRUE);
7922 }
7923
7924 /*-----------------------------------------------------------------*/
7925 /* genrshOne - right shift a one byte quantity by known count      */
7926 /*-----------------------------------------------------------------*/
7927 static void
7928 genrshOne (operand * result, operand * left,
7929            int shCount, int sign)
7930 {
7931   D(emitcode (";     genrshOne",""));
7932
7933   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7934 }
7935
7936 /*-----------------------------------------------------------------*/
7937 /* genrshTwo - right shift two bytes by known amount != 0          */
7938 /*-----------------------------------------------------------------*/
7939 static void
7940 genrshTwo (operand * result, operand * left,
7941            int shCount, int sign)
7942 {
7943   D(emitcode (";     genrshTwo",""));
7944
7945   /* if shCount >= 8 */
7946   if (shCount >= 8)
7947     {
7948       shCount -= 8;
7949       if (shCount)
7950         shiftR1Left2Result (left, MSB16, result, LSB,
7951                             shCount, sign);
7952       else
7953         movLeft2Result (left, MSB16, result, LSB, sign);
7954       addSign (result, MSB16, sign);
7955     }
7956
7957   /*  1 <= shCount <= 7 */
7958   else
7959     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7960 }
7961
7962 /*-----------------------------------------------------------------*/
7963 /* shiftRLong - shift right one long from left to result           */
7964 /* offl = LSB or MSB16                                             */
7965 /*-----------------------------------------------------------------*/
7966 static void
7967 shiftRLong (operand * left, int offl,
7968             operand * result, int sign)
7969 {
7970   int isSameRegs=sameRegs(AOP(left),AOP(result));
7971
7972   if (isSameRegs && offl>1) {
7973     // we are in big trouble, but this shouldn't happen
7974     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7975   }
7976
7977   MOVA (aopGet (left, MSB32, FALSE, FALSE));
7978
7979   if (offl==MSB16) {
7980     // shift is > 8
7981     if (sign) {
7982       emitcode ("rlc", "a");
7983       emitcode ("subb", "a,acc");
7984       if (isSameRegs)
7985         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
7986       else {
7987         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
7988         MOVA (aopGet (left, MSB32, FALSE, FALSE));
7989       }
7990     } else {
7991       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
7992     }
7993   }
7994
7995   if (!sign) {
7996     emitcode ("clr", "c");
7997   } else {
7998     emitcode ("mov", "c,acc.7");
7999   }
8000
8001   emitcode ("rrc", "a");
8002
8003   if (isSameRegs && offl==MSB16) {
8004     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8005   } else {
8006     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8007     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8008   }
8009
8010   emitcode ("rrc", "a");
8011   if (isSameRegs && offl==1) {
8012     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8013   } else {
8014     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8015     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8016   }
8017   emitcode ("rrc", "a");
8018   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8019
8020   if (offl == LSB)
8021     {
8022       MOVA (aopGet (left, LSB, FALSE, FALSE));
8023       emitcode ("rrc", "a");
8024       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8025     }
8026 }
8027
8028 /*-----------------------------------------------------------------*/
8029 /* genrshFour - shift four byte by a known amount != 0             */
8030 /*-----------------------------------------------------------------*/
8031 static void
8032 genrshFour (operand * result, operand * left,
8033             int shCount, int sign)
8034 {
8035   D(emitcode (";     genrshFour",""));
8036
8037   /* if shifting more that 3 bytes */
8038   if (shCount >= 24)
8039     {
8040       shCount -= 24;
8041       if (shCount)
8042         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8043       else
8044         movLeft2Result (left, MSB32, result, LSB, sign);
8045       addSign (result, MSB16, sign);
8046     }
8047   else if (shCount >= 16)
8048     {
8049       shCount -= 16;
8050       if (shCount)
8051         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8052       else
8053         {
8054           movLeft2Result (left, MSB24, result, LSB, 0);
8055           movLeft2Result (left, MSB32, result, MSB16, sign);
8056         }
8057       addSign (result, MSB24, sign);
8058     }
8059   else if (shCount >= 8)
8060     {
8061       shCount -= 8;
8062       if (shCount == 1)
8063         shiftRLong (left, MSB16, result, sign);
8064       else if (shCount == 0)
8065         {
8066           movLeft2Result (left, MSB16, result, LSB, 0);
8067           movLeft2Result (left, MSB24, result, MSB16, 0);
8068           movLeft2Result (left, MSB32, result, MSB24, sign);
8069           addSign (result, MSB32, sign);
8070         }
8071       else
8072         {
8073           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8074           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8075           /* the last shift is signed */
8076           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8077           addSign (result, MSB32, sign);
8078         }
8079     }
8080   else
8081     {                           /* 1 <= shCount <= 7 */
8082       if (shCount <= 2)
8083         {
8084           shiftRLong (left, LSB, result, sign);
8085           if (shCount == 2)
8086             shiftRLong (result, LSB, result, sign);
8087         }
8088       else
8089         {
8090           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8091           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8092           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8093         }
8094     }
8095 }
8096
8097 /*-----------------------------------------------------------------*/
8098 /* genRightShiftLiteral - right shifting by known count            */
8099 /*-----------------------------------------------------------------*/
8100 static void
8101 genRightShiftLiteral (operand * left,
8102                       operand * right,
8103                       operand * result,
8104                       iCode * ic,
8105                       int sign)
8106 {
8107   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8108   int size;
8109
8110   D(emitcode (";     genRightShiftLiteral",""));
8111
8112   freeAsmop (right, NULL, ic, TRUE);
8113
8114   aopOp (left, ic, FALSE);
8115   aopOp (result, ic, FALSE);
8116
8117 #if VIEW_SIZE
8118   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8119             AOP_SIZE (left));
8120 #endif
8121
8122   size = getDataSize (left);
8123   /* test the LEFT size !!! */
8124
8125   /* I suppose that the left size >= result size */
8126   if (shCount == 0)
8127     {
8128       size = getDataSize (result);
8129       while (size--)
8130         movLeft2Result (left, size, result, size, 0);
8131     }
8132
8133   else if (shCount >= (size * 8))
8134     {
8135       if (sign) {
8136         /* get sign in acc.7 */
8137         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8138       }
8139       addSign (result, LSB, sign);
8140     }
8141   else
8142     {
8143       switch (size)
8144         {
8145         case 1:
8146           genrshOne (result, left, shCount, sign);
8147           break;
8148
8149         case 2:
8150           genrshTwo (result, left, shCount, sign);
8151           break;
8152
8153         case 4:
8154           genrshFour (result, left, shCount, sign);
8155           break;
8156         default:
8157           break;
8158         }
8159     }
8160   freeAsmop (left, NULL, ic, TRUE);
8161   freeAsmop (result, NULL, ic, TRUE);
8162 }
8163
8164 /*-----------------------------------------------------------------*/
8165 /* genSignedRightShift - right shift of signed number              */
8166 /*-----------------------------------------------------------------*/
8167 static void
8168 genSignedRightShift (iCode * ic)
8169 {
8170   operand *right, *left, *result;
8171   int size, offset;
8172   char *l;
8173   symbol *tlbl, *tlbl1;
8174   bool pushedB;
8175
8176   D(emitcode (";     genSignedRightShift",""));
8177
8178   /* we do it the hard way put the shift count in b
8179      and loop thru preserving the sign */
8180
8181   right = IC_RIGHT (ic);
8182   left = IC_LEFT (ic);
8183   result = IC_RESULT (ic);
8184
8185   aopOp (right, ic, FALSE);
8186
8187
8188   if (AOP_TYPE (right) == AOP_LIT)
8189     {
8190       genRightShiftLiteral (left, right, result, ic, 1);
8191       return;
8192     }
8193   /* shift count is unknown then we have to form
8194      a loop get the loop count in B : Note: we take
8195      only the lower order byte since shifting
8196      more that 32 bits make no sense anyway, ( the
8197      largest size of an object can be only 32 bits ) */
8198
8199   pushedB = pushB ();
8200   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8201   emitcode ("inc", "b");
8202   freeAsmop (right, NULL, ic, TRUE);
8203   aopOp (left, ic, FALSE);
8204   aopOp (result, ic, FALSE);
8205
8206   /* now move the left to the result if they are not the
8207      same */
8208   if (!sameRegs (AOP (left), AOP (result)) &&
8209       AOP_SIZE (result) > 1)
8210     {
8211
8212       size = AOP_SIZE (result);
8213       offset = 0;
8214       while (size--)
8215         {
8216           l = aopGet (left, offset, FALSE, TRUE);
8217           if (*l == '@' && IS_AOP_PREG (result))
8218             {
8219
8220               emitcode ("mov", "a,%s", l);
8221               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8222             }
8223           else
8224             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8225           offset++;
8226         }
8227     }
8228
8229   /* mov the highest order bit to OVR */
8230   tlbl = newiTempLabel (NULL);
8231   tlbl1 = newiTempLabel (NULL);
8232
8233   size = AOP_SIZE (result);
8234   offset = size - 1;
8235   MOVA (aopGet (left, offset, FALSE, FALSE));
8236   emitcode ("rlc", "a");
8237   emitcode ("mov", "ov,c");
8238   /* if it is only one byte then */
8239   if (size == 1)
8240     {
8241       l = aopGet (left, 0, FALSE, FALSE);
8242       MOVA (l);
8243       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8244       emitcode ("", "%05d$:", tlbl->key + 100);
8245       emitcode ("mov", "c,ov");
8246       emitcode ("rrc", "a");
8247       emitcode ("", "%05d$:", tlbl1->key + 100);
8248       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8249       popB (pushedB);
8250       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8251       goto release;
8252     }
8253
8254   reAdjustPreg (AOP (result));
8255   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8256   emitcode ("", "%05d$:", tlbl->key + 100);
8257   emitcode ("mov", "c,ov");
8258   while (size--)
8259     {
8260       l = aopGet (result, offset, FALSE, FALSE);
8261       MOVA (l);
8262       emitcode ("rrc", "a");
8263       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8264     }
8265   reAdjustPreg (AOP (result));
8266   emitcode ("", "%05d$:", tlbl1->key + 100);
8267   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8268   popB (pushedB);
8269
8270 release:
8271   freeAsmop (left, NULL, ic, TRUE);
8272   freeAsmop (result, NULL, ic, TRUE);
8273 }
8274
8275 /*-----------------------------------------------------------------*/
8276 /* genRightShift - generate code for right shifting                */
8277 /*-----------------------------------------------------------------*/
8278 static void
8279 genRightShift (iCode * ic)
8280 {
8281   operand *right, *left, *result;
8282   sym_link *letype;
8283   int size, offset;
8284   char *l;
8285   symbol *tlbl, *tlbl1;
8286   bool pushedB;
8287
8288   D(emitcode (";     genRightShift",""));
8289
8290   /* if signed then we do it the hard way preserve the
8291      sign bit moving it inwards */
8292   letype = getSpec (operandType (IC_LEFT (ic)));
8293
8294   if (!SPEC_USIGN (letype))
8295     {
8296       genSignedRightShift (ic);
8297       return;
8298     }
8299
8300   /* signed & unsigned types are treated the same : i.e. the
8301      signed is NOT propagated inwards : quoting from the
8302      ANSI - standard : "for E1 >> E2, is equivalent to division
8303      by 2**E2 if unsigned or if it has a non-negative value,
8304      otherwise the result is implementation defined ", MY definition
8305      is that the sign does not get propagated */
8306
8307   right = IC_RIGHT (ic);
8308   left = IC_LEFT (ic);
8309   result = IC_RESULT (ic);
8310
8311   aopOp (right, ic, FALSE);
8312
8313   /* if the shift count is known then do it
8314      as efficiently as possible */
8315   if (AOP_TYPE (right) == AOP_LIT)
8316     {
8317       genRightShiftLiteral (left, right, result, ic, 0);
8318       return;
8319     }
8320
8321   /* shift count is unknown then we have to form
8322      a loop get the loop count in B : Note: we take
8323      only the lower order byte since shifting
8324      more that 32 bits make no sense anyway, ( the
8325      largest size of an object can be only 32 bits ) */
8326
8327   pushedB = pushB ();
8328   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8329   emitcode ("inc", "b");
8330   freeAsmop (right, NULL, ic, TRUE);
8331   aopOp (left, ic, FALSE);
8332   aopOp (result, ic, FALSE);
8333
8334   /* now move the left to the result if they are not the
8335      same */
8336   if (!sameRegs (AOP (left), AOP (result)) &&
8337       AOP_SIZE (result) > 1)
8338     {
8339
8340       size = AOP_SIZE (result);
8341       offset = 0;
8342       while (size--)
8343         {
8344           l = aopGet (left, offset, FALSE, TRUE);
8345           if (*l == '@' && IS_AOP_PREG (result))
8346             {
8347
8348               emitcode ("mov", "a,%s", l);
8349               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8350             }
8351           else
8352             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8353           offset++;
8354         }
8355     }
8356
8357   tlbl = newiTempLabel (NULL);
8358   tlbl1 = newiTempLabel (NULL);
8359   size = AOP_SIZE (result);
8360   offset = size - 1;
8361
8362   /* if it is only one byte then */
8363   if (size == 1)
8364     {
8365       l = aopGet (left, 0, FALSE, FALSE);
8366       MOVA (l);
8367       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8368       emitcode ("", "%05d$:", tlbl->key + 100);
8369       CLRC;
8370       emitcode ("rrc", "a");
8371       emitcode ("", "%05d$:", tlbl1->key + 100);
8372       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8373       popB (pushedB);
8374       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8375       goto release;
8376     }
8377
8378   reAdjustPreg (AOP (result));
8379   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8380   emitcode ("", "%05d$:", tlbl->key + 100);
8381   CLRC;
8382   while (size--)
8383     {
8384       l = aopGet (result, offset, FALSE, FALSE);
8385       MOVA (l);
8386       emitcode ("rrc", "a");
8387       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8388     }
8389   reAdjustPreg (AOP (result));
8390
8391   emitcode ("", "%05d$:", tlbl1->key + 100);
8392   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8393   popB (pushedB);
8394
8395 release:
8396   freeAsmop (left, NULL, ic, TRUE);
8397   freeAsmop (result, NULL, ic, TRUE);
8398 }
8399
8400 /*-----------------------------------------------------------------*/
8401 /* emitPtrByteGet - emits code to get a byte into A through a      */
8402 /*                  pointer register (R0, R1, or DPTR). The        */
8403 /*                  original value of A can be preserved in B.     */
8404 /*-----------------------------------------------------------------*/
8405 static void
8406 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8407 {
8408   switch (p_type)
8409     {
8410     case IPOINTER:
8411     case POINTER:
8412       if (preserveAinB)
8413         emitcode ("mov", "b,a");
8414       emitcode ("mov", "a,@%s", rname);
8415       break;
8416
8417     case PPOINTER:
8418       if (preserveAinB)
8419         emitcode ("mov", "b,a");
8420       emitcode ("movx", "a,@%s", rname);
8421       break;
8422
8423     case FPOINTER:
8424       if (preserveAinB)
8425         emitcode ("mov", "b,a");
8426       emitcode ("movx", "a,@dptr");
8427       break;
8428
8429     case CPOINTER:
8430       if (preserveAinB)
8431         emitcode ("mov", "b,a");
8432       emitcode ("clr", "a");
8433       emitcode ("movc", "a,@a+dptr");
8434       break;
8435
8436     case GPOINTER:
8437       if (preserveAinB)
8438         {
8439           emitcode ("push", "b");
8440           emitcode ("push", "acc");
8441         }
8442       emitcode ("lcall", "__gptrget");
8443       if (preserveAinB)
8444         emitcode ("pop", "b");
8445       break;
8446     }
8447 }
8448
8449 /*-----------------------------------------------------------------*/
8450 /* emitPtrByteSet - emits code to set a byte from src through a    */
8451 /*                  pointer register (R0, R1, or DPTR).            */
8452 /*-----------------------------------------------------------------*/
8453 static void
8454 emitPtrByteSet (char *rname, int p_type, char *src)
8455 {
8456   switch (p_type)
8457     {
8458     case IPOINTER:
8459     case POINTER:
8460       if (*src=='@')
8461         {
8462           MOVA (src);
8463           emitcode ("mov", "@%s,a", rname);
8464         }
8465       else
8466         emitcode ("mov", "@%s,%s", rname, src);
8467       break;
8468
8469     case PPOINTER:
8470       MOVA (src);
8471       emitcode ("movx", "@%s,a", rname);
8472       break;
8473
8474     case FPOINTER:
8475       MOVA (src);
8476       emitcode ("movx", "@dptr,a");
8477       break;
8478
8479     case GPOINTER:
8480       MOVA (src);
8481       emitcode ("lcall", "__gptrput");
8482       break;
8483     }
8484 }
8485
8486 /*-----------------------------------------------------------------*/
8487 /* genUnpackBits - generates code for unpacking bits               */
8488 /*-----------------------------------------------------------------*/
8489 static void
8490 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8491 {
8492   int offset = 0;       /* result byte offset */
8493   int rsize;            /* result size */
8494   int rlen = 0;         /* remaining bitfield length */
8495   sym_link *etype;      /* bitfield type information */
8496   int blen;             /* bitfield length */
8497   int bstr;             /* bitfield starting bit within byte */
8498   char buffer[10];
8499
8500   D(emitcode (";     genUnpackBits",""));
8501
8502   etype = getSpec (operandType (result));
8503   rsize = getSize (operandType (result));
8504   blen = SPEC_BLEN (etype);
8505   bstr = SPEC_BSTR (etype);
8506
8507   if (ifx && blen <= 8)
8508     {
8509       emitPtrByteGet (rname, ptype, FALSE);
8510       if (blen == 1)
8511         {
8512           SNPRINTF (buffer, sizeof(buffer),
8513                     "acc.%d", bstr);
8514           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8515         }
8516       else
8517         {
8518           if (blen < 8)
8519             emitcode ("anl", "a,#0x%02x",
8520                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8521           genIfxJump (ifx, "a", NULL, NULL, NULL);
8522         }
8523       return;
8524     }
8525   wassert (!ifx);
8526
8527   /* If the bitfield length is less than a byte */
8528   if (blen < 8)
8529     {
8530       emitPtrByteGet (rname, ptype, FALSE);
8531       AccRsh (bstr);
8532       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8533       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8534       goto finish;
8535     }
8536
8537   /* Bit field did not fit in a byte. Copy all
8538      but the partial byte at the end.  */
8539   for (rlen=blen;rlen>=8;rlen-=8)
8540     {
8541       emitPtrByteGet (rname, ptype, FALSE);
8542       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8543       if (rlen>8)
8544         emitcode ("inc", "%s", rname);
8545     }
8546
8547   /* Handle the partial byte at the end */
8548   if (rlen)
8549     {
8550       emitPtrByteGet (rname, ptype, FALSE);
8551       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8552       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8553     }
8554
8555 finish:
8556   if (offset < rsize)
8557     {
8558       rsize -= offset;
8559       while (rsize--)
8560         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
8561     }
8562 }
8563
8564
8565 /*-----------------------------------------------------------------*/
8566 /* genDataPointerGet - generates code when ptr offset is known     */
8567 /*-----------------------------------------------------------------*/
8568 static void
8569 genDataPointerGet (operand * left,
8570                    operand * result,
8571                    iCode * ic)
8572 {
8573   char *l;
8574   char buffer[256];
8575   int size, offset = 0;
8576
8577   D(emitcode (";     genDataPointerGet",""));
8578
8579   aopOp (result, ic, TRUE);
8580
8581   /* get the string representation of the name */
8582   l = aopGet (left, 0, FALSE, TRUE);
8583   size = AOP_SIZE (result);
8584   while (size--)
8585     {
8586       if (offset)
8587         sprintf (buffer, "(%s + %d)", l + 1, offset);
8588       else
8589         sprintf (buffer, "%s", l + 1);
8590       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
8591     }
8592
8593   freeAsmop (left, NULL, ic, TRUE);
8594   freeAsmop (result, NULL, ic, TRUE);
8595 }
8596
8597 /*-----------------------------------------------------------------*/
8598 /* genNearPointerGet - emitcode for near pointer fetch             */
8599 /*-----------------------------------------------------------------*/
8600 static void
8601 genNearPointerGet (operand * left,
8602                    operand * result,
8603                    iCode * ic,
8604                    iCode * pi,
8605                    iCode * ifx)
8606 {
8607   asmop *aop = NULL;
8608   regs *preg = NULL;
8609   char *rname;
8610   sym_link *rtype, *retype;
8611   sym_link *ltype = operandType (left);
8612   char buffer[80];
8613
8614   D(emitcode (";     genNearPointerGet",""));
8615
8616   rtype = operandType (result);
8617   retype = getSpec (rtype);
8618
8619   aopOp (left, ic, FALSE);
8620
8621   /* if left is rematerialisable and
8622      result is not bitfield variable type and
8623      the left is pointer to data space i.e
8624      lower 128 bytes of space */
8625   if (AOP_TYPE (left) == AOP_IMMD &&
8626       !IS_BITFIELD (retype) &&
8627       DCL_TYPE (ltype) == POINTER)
8628     {
8629       genDataPointerGet (left, result, ic);
8630       return;
8631     }
8632
8633  /* if the value is already in a pointer register
8634      then don't need anything more */
8635   if (!AOP_INPREG (AOP (left)))
8636     {
8637       if (IS_AOP_PREG (left))
8638         {
8639           // Aha, it is a pointer, just in disguise.
8640           rname = aopGet (left, 0, FALSE, FALSE);
8641           if (*rname != '@')
8642             {
8643               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8644                       __FILE__, __LINE__);
8645             }
8646           else
8647             {
8648               // Expected case.
8649               emitcode ("mov", "a%s,%s", rname + 1, rname);
8650               rname++;  // skip the '@'.
8651             }
8652         }
8653       else
8654         {
8655           /* otherwise get a free pointer register */
8656           aop = newAsmop (0);
8657           preg = getFreePtr (ic, &aop, FALSE);
8658           emitcode ("mov", "%s,%s",
8659                     preg->name,
8660                     aopGet (left, 0, FALSE, TRUE));
8661           rname = preg->name;
8662         }
8663     }
8664   else
8665     rname = aopGet (left, 0, FALSE, FALSE);
8666
8667   //aopOp (result, ic, FALSE);
8668   aopOp (result, ic, result?TRUE:FALSE);
8669
8670   /* if bitfield then unpack the bits */
8671   if (IS_BITFIELD (retype))
8672     genUnpackBits (result, rname, POINTER, ifx);
8673   else
8674     {
8675       /* we have can just get the values */
8676       int size = AOP_SIZE (result);
8677       int offset = 0;
8678
8679       while (size--)
8680         {
8681           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8682             {
8683
8684               emitcode ("mov", "a,@%s", rname);
8685               if (!ifx)
8686               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8687             }
8688           else
8689             {
8690               sprintf (buffer, "@%s", rname);
8691               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
8692             }
8693           offset++;
8694           if (size || pi)
8695             emitcode ("inc", "%s", rname);
8696         }
8697     }
8698
8699   /* now some housekeeping stuff */
8700   if (aop)       /* we had to allocate for this iCode */
8701     {
8702       if (pi) { /* post increment present */
8703         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8704       }
8705       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8706     }
8707   else
8708     {
8709       /* we did not allocate which means left
8710          already in a pointer register, then
8711          if size > 0 && this could be used again
8712          we have to point it back to where it
8713          belongs */
8714       if ((AOP_SIZE (result) > 1 &&
8715            !OP_SYMBOL (left)->remat &&
8716            (OP_SYMBOL (left)->liveTo > ic->seq ||
8717             ic->depth)) &&
8718           !pi)
8719         {
8720           int size = AOP_SIZE (result) - 1;
8721           while (size--)
8722             emitcode ("dec", "%s", rname);
8723         }
8724     }
8725
8726   if (ifx && !ifx->generated)
8727     {
8728       genIfxJump (ifx, "a", left, NULL, result);
8729     }
8730
8731   /* done */
8732   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8733   freeAsmop (left, NULL, ic, TRUE);
8734   if (pi) pi->generated = 1;
8735 }
8736
8737 /*-----------------------------------------------------------------*/
8738 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8739 /*-----------------------------------------------------------------*/
8740 static void
8741 genPagedPointerGet (operand * left,
8742                     operand * result,
8743                     iCode * ic,
8744                     iCode *pi,
8745                     iCode *ifx)
8746 {
8747   asmop *aop = NULL;
8748   regs *preg = NULL;
8749   char *rname;
8750   sym_link *rtype, *retype;
8751
8752   D(emitcode (";     genPagedPointerGet",""));
8753
8754   rtype = operandType (result);
8755   retype = getSpec (rtype);
8756
8757   aopOp (left, ic, FALSE);
8758
8759   /* if the value is already in a pointer register
8760      then don't need anything more */
8761   if (!AOP_INPREG (AOP (left)))
8762     {
8763       /* otherwise get a free pointer register */
8764       aop = newAsmop (0);
8765       preg = getFreePtr (ic, &aop, FALSE);
8766       emitcode ("mov", "%s,%s",
8767                 preg->name,
8768                 aopGet (left, 0, FALSE, TRUE));
8769       rname = preg->name;
8770     }
8771   else
8772     rname = aopGet (left, 0, FALSE, FALSE);
8773
8774   aopOp (result, ic, FALSE);
8775
8776   /* if bitfield then unpack the bits */
8777   if (IS_BITFIELD (retype))
8778     genUnpackBits (result, rname, PPOINTER, ifx);
8779   else
8780     {
8781       /* we have can just get the values */
8782       int size = AOP_SIZE (result);
8783       int offset = 0;
8784
8785       while (size--)
8786         {
8787
8788           emitcode ("movx", "a,@%s", rname);
8789           if (!ifx)
8790           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8791
8792           offset++;
8793
8794           if (size || pi)
8795             emitcode ("inc", "%s", rname);
8796         }
8797     }
8798
8799   /* now some housekeeping stuff */
8800   if (aop) /* we had to allocate for this iCode */
8801     {
8802       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8803       freeAsmop (NULL, aop, ic, TRUE);
8804     }
8805   else
8806     {
8807       /* we did not allocate which means left
8808          already in a pointer register, then
8809          if size > 0 && this could be used again
8810          we have to point it back to where it
8811          belongs */
8812       if ((AOP_SIZE (result) > 1 &&
8813            !OP_SYMBOL (left)->remat &&
8814            (OP_SYMBOL (left)->liveTo > ic->seq ||
8815             ic->depth)) &&
8816           !pi)
8817         {
8818           int size = AOP_SIZE (result) - 1;
8819           while (size--)
8820             emitcode ("dec", "%s", rname);
8821         }
8822     }
8823
8824   if (ifx && !ifx->generated)
8825     {
8826       genIfxJump (ifx, "a", left, NULL, result);
8827     }
8828
8829   /* done */
8830   freeAsmop (left, NULL, ic, TRUE);
8831   freeAsmop (result, NULL, ic, TRUE);
8832   if (pi) pi->generated = 1;
8833
8834 }
8835
8836 /*--------------------------------------------------------------------*/
8837 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8838 /*--------------------------------------------------------------------*/
8839 static void
8840 loadDptrFromOperand (operand *op, bool loadBToo)
8841 {
8842   if (AOP_TYPE (op) != AOP_STR)
8843     {
8844       /* if this is rematerializable */
8845       if (AOP_TYPE (op) == AOP_IMMD)
8846         {
8847           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
8848           if (loadBToo)
8849             {
8850               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8851                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
8852               else
8853                 {
8854                   wassertl(FALSE, "need pointerCode");
8855                   emitcode ("", "; mov b,???");
8856                   /* genPointerGet and genPointerSet originally did different
8857                   ** things for this case. Both seem wrong.
8858                   ** from genPointerGet:
8859                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8860                   ** from genPointerSet:
8861                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
8862                   */
8863                 }
8864             }
8865         }
8866       else if (AOP_TYPE (op) == AOP_DPTR)
8867         {
8868           if (loadBToo)
8869             {
8870               MOVA (aopGet (op, 0, FALSE, FALSE));
8871               emitcode ("push", "acc");
8872               MOVA (aopGet (op, 1, FALSE, FALSE));
8873               emitcode ("push", "acc");
8874               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8875               emitcode ("pop", "dph");
8876               emitcode ("pop", "dpl");
8877             }
8878           else
8879             {
8880               MOVA (aopGet (op, 0, FALSE, FALSE));
8881               emitcode ("push", "acc");
8882               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
8883               emitcode ("pop", "dpl");
8884             }
8885         }
8886       else
8887         {                       /* we need to get it byte by byte */
8888           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
8889           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
8890           if (loadBToo)
8891             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8892         }
8893     }
8894 }
8895
8896 /*-----------------------------------------------------------------*/
8897 /* genFarPointerGet - gget value from far space                    */
8898 /*-----------------------------------------------------------------*/
8899 static void
8900 genFarPointerGet (operand * left,
8901                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8902 {
8903   int size, offset;
8904   sym_link *retype = getSpec (operandType (result));
8905
8906   D(emitcode (";     genFarPointerGet",""));
8907
8908   aopOp (left, ic, FALSE);
8909   loadDptrFromOperand (left, FALSE);
8910
8911   /* so dptr now contains the address */
8912   aopOp (result, ic, FALSE);
8913
8914   /* if bit then unpack */
8915   if (IS_BITFIELD (retype))
8916     genUnpackBits (result, "dptr", FPOINTER, ifx);
8917   else
8918     {
8919       size = AOP_SIZE (result);
8920       offset = 0;
8921
8922       while (size--)
8923         {
8924           emitcode ("movx", "a,@dptr");
8925           if (!ifx)
8926             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8927           if (size || pi)
8928             emitcode ("inc", "dptr");
8929         }
8930     }
8931
8932   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8933     {
8934     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
8935     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
8936     pi->generated = 1;
8937   }
8938
8939   if (ifx && !ifx->generated)
8940     {
8941       genIfxJump (ifx, "a", left, NULL, result);
8942     }
8943
8944   freeAsmop (left, NULL, ic, TRUE);
8945   freeAsmop (result, NULL, ic, TRUE);
8946 }
8947
8948 /*-----------------------------------------------------------------*/
8949 /* genCodePointerGet - gget value from code space                  */
8950 /*-----------------------------------------------------------------*/
8951 static void
8952 genCodePointerGet (operand * left,
8953                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8954 {
8955   int size, offset;
8956   sym_link *retype = getSpec (operandType (result));
8957
8958   D(emitcode (";     genCodePointerGet",""));
8959
8960   aopOp (left, ic, FALSE);
8961   loadDptrFromOperand (left, FALSE);
8962
8963   /* so dptr now contains the address */
8964   aopOp (result, ic, FALSE);
8965
8966   /* if bit then unpack */
8967   if (IS_BITFIELD (retype))
8968     genUnpackBits (result, "dptr", CPOINTER, ifx);
8969   else
8970     {
8971       size = AOP_SIZE (result);
8972       offset = 0;
8973
8974       while (size--)
8975         {
8976           if (pi)
8977             {
8978               emitcode ("clr", "a");
8979               emitcode ("movc", "a,@a+dptr");
8980               if (!ifx)
8981               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8982               emitcode ("inc", "dptr");
8983             }
8984           else
8985             {
8986               emitcode ("mov", "a,#0x%02x", offset);
8987               emitcode ("movc", "a,@a+dptr");
8988               if (!ifx)
8989               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8990             }
8991         }
8992     }
8993
8994   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8995     {
8996     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
8997     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
8998     pi->generated = 1;
8999   }
9000
9001   if (ifx && !ifx->generated)
9002     {
9003       genIfxJump (ifx, "a", left, NULL, result);
9004     }
9005
9006   freeAsmop (left, NULL, ic, TRUE);
9007   freeAsmop (result, NULL, ic, TRUE);
9008 }
9009
9010 /*-----------------------------------------------------------------*/
9011 /* genGenPointerGet - gget value from generic pointer space        */
9012 /*-----------------------------------------------------------------*/
9013 static void
9014 genGenPointerGet (operand * left,
9015                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9016 {
9017   int size, offset;
9018   sym_link *retype = getSpec (operandType (result));
9019
9020   D(emitcode (";     genGenPointerGet",""));
9021
9022   aopOp (left, ic, FALSE);
9023   loadDptrFromOperand (left, TRUE);
9024
9025   /* so dptr know contains the address */
9026   aopOp (result, ic, FALSE);
9027
9028   /* if bit then unpack */
9029   if (IS_BITFIELD (retype))
9030     genUnpackBits (result, "dptr", GPOINTER, ifx);
9031   else
9032     {
9033       size = AOP_SIZE (result);
9034       offset = 0;
9035
9036       while (size--)
9037         {
9038           emitcode ("lcall", "__gptrget");
9039           if (!ifx)
9040           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9041           if (size || pi)
9042             emitcode ("inc", "dptr");
9043         }
9044     }
9045
9046   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9047     {
9048     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9049     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9050     pi->generated = 1;
9051   }
9052
9053   if (ifx && !ifx->generated)
9054     {
9055       genIfxJump (ifx, "a", left, NULL, result);
9056     }
9057
9058
9059   freeAsmop (left, NULL, ic, TRUE);
9060   freeAsmop (result, NULL, ic, TRUE);
9061 }
9062
9063 /*-----------------------------------------------------------------*/
9064 /* genPointerGet - generate code for pointer get                   */
9065 /*-----------------------------------------------------------------*/
9066 static void
9067 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9068 {
9069   operand *left, *result;
9070   sym_link *type, *etype;
9071   int p_type;
9072
9073   D(emitcode (";     genPointerGet",""));
9074
9075   left = IC_LEFT (ic);
9076   result = IC_RESULT (ic);
9077
9078   if (getSize (operandType (result))>1)
9079     ifx = NULL;
9080
9081   /* depending on the type of pointer we need to
9082      move it to the correct pointer register */
9083   type = operandType (left);
9084   etype = getSpec (type);
9085   /* if left is of type of pointer then it is simple */
9086   if (IS_PTR (type) && !IS_FUNC (type->next))
9087     p_type = DCL_TYPE (type);
9088   else
9089     {
9090       /* we have to go by the storage class */
9091       p_type = PTR_TYPE (SPEC_OCLS (etype));
9092     }
9093
9094   /* special case when cast remat */
9095   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9096       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9097           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9098           type = operandType (left);
9099           p_type = DCL_TYPE (type);
9100   }
9101   /* now that we have the pointer type we assign
9102      the pointer values */
9103   switch (p_type)
9104     {
9105
9106     case POINTER:
9107     case IPOINTER:
9108       genNearPointerGet (left, result, ic, pi, ifx);
9109       break;
9110
9111     case PPOINTER:
9112       genPagedPointerGet (left, result, ic, pi, ifx);
9113       break;
9114
9115     case FPOINTER:
9116       genFarPointerGet (left, result, ic, pi, ifx);
9117       break;
9118
9119     case CPOINTER:
9120       genCodePointerGet (left, result, ic, pi, ifx);
9121       break;
9122
9123     case GPOINTER:
9124       genGenPointerGet (left, result, ic, pi, ifx);
9125       break;
9126     }
9127
9128 }
9129
9130
9131
9132 /*-----------------------------------------------------------------*/
9133 /* genPackBits - generates code for packed bit storage             */
9134 /*-----------------------------------------------------------------*/
9135 static void
9136 genPackBits (sym_link * etype,
9137              operand * right,
9138              char *rname, int p_type)
9139 {
9140   int offset = 0;       /* source byte offset */
9141   int rlen = 0;         /* remaining bitfield length */
9142   int blen;             /* bitfield length */
9143   int bstr;             /* bitfield starting bit within byte */
9144   int litval;           /* source literal value (if AOP_LIT) */
9145   unsigned char mask;   /* bitmask within current byte */
9146
9147   D(emitcode (";     genPackBits",""));
9148
9149   blen = SPEC_BLEN (etype);
9150   bstr = SPEC_BSTR (etype);
9151
9152   /* If the bitfield length is less than a byte */
9153   if (blen < 8)
9154     {
9155       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9156               (unsigned char) (0xFF >> (8 - bstr)));
9157
9158       if (AOP_TYPE (right) == AOP_LIT)
9159         {
9160           /* Case with a bitfield length <8 and literal source
9161           */
9162           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9163           litval <<= bstr;
9164           litval &= (~mask) & 0xff;
9165           emitPtrByteGet (rname, p_type, FALSE);
9166           if ((mask|litval)!=0xff)
9167             emitcode ("anl","a,#0x%02x", mask);
9168           if (litval)
9169             emitcode ("orl","a,#0x%02x", litval);
9170         }
9171       else
9172         {
9173           if ((blen==1) && (p_type!=GPOINTER))
9174             {
9175               /* Case with a bitfield length == 1 and no generic pointer
9176               */
9177               if (AOP_TYPE (right) == AOP_CRY)
9178                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9179               else
9180                 {
9181                   MOVA (aopGet (right, 0, FALSE, FALSE));
9182                   emitcode ("rrc","a");
9183                 }
9184               emitPtrByteGet (rname, p_type, FALSE);
9185               emitcode ("mov","acc.%d,c",bstr);
9186             }
9187           else
9188             {
9189               bool pushedB;
9190               /* Case with a bitfield length < 8 and arbitrary source
9191               */
9192               MOVA (aopGet (right, 0, FALSE, FALSE));
9193               /* shift and mask source value */
9194               AccLsh (bstr);
9195               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9196
9197               pushedB = pushB ();
9198               /* transfer A to B and get next byte */
9199               emitPtrByteGet (rname, p_type, TRUE);
9200
9201               emitcode ("anl", "a,#0x%02x", mask);
9202               emitcode ("orl", "a,b");
9203               if (p_type == GPOINTER)
9204                 emitcode ("pop", "b");
9205
9206               popB (pushedB);
9207            }
9208         }
9209
9210       emitPtrByteSet (rname, p_type, "a");
9211       return;
9212     }
9213
9214   /* Bit length is greater than 7 bits. In this case, copy  */
9215   /* all except the partial byte at the end                 */
9216   for (rlen=blen;rlen>=8;rlen-=8)
9217     {
9218       emitPtrByteSet (rname, p_type,
9219                       aopGet (right, offset++, FALSE, TRUE) );
9220       if (rlen>8)
9221         emitcode ("inc", "%s", rname);
9222     }
9223
9224   /* If there was a partial byte at the end */
9225   if (rlen)
9226     {
9227       mask = (((unsigned char) -1 << rlen) & 0xff);
9228
9229       if (AOP_TYPE (right) == AOP_LIT)
9230         {
9231           /* Case with partial byte and literal source
9232           */
9233           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9234           litval >>= (blen-rlen);
9235           litval &= (~mask) & 0xff;
9236           emitPtrByteGet (rname, p_type, FALSE);
9237           if ((mask|litval)!=0xff)
9238             emitcode ("anl","a,#0x%02x", mask);
9239           if (litval)
9240             emitcode ("orl","a,#0x%02x", litval);
9241         }
9242       else
9243         {
9244           bool pushedB;
9245           /* Case with partial byte and arbitrary source
9246           */
9247           MOVA (aopGet (right, offset++, FALSE, FALSE));
9248           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9249
9250           pushedB = pushB ();
9251           /* transfer A to B and get next byte */
9252           emitPtrByteGet (rname, p_type, TRUE);
9253
9254           emitcode ("anl", "a,#0x%02x", mask);
9255           emitcode ("orl", "a,b");
9256           if (p_type == GPOINTER)
9257             emitcode ("pop", "b");
9258
9259           popB (pushedB);
9260         }
9261       emitPtrByteSet (rname, p_type, "a");
9262     }
9263
9264 }
9265
9266
9267 /*-----------------------------------------------------------------*/
9268 /* genDataPointerSet - remat pointer to data space                 */
9269 /*-----------------------------------------------------------------*/
9270 static void
9271 genDataPointerSet (operand * right,
9272                    operand * result,
9273                    iCode * ic)
9274 {
9275   int size, offset = 0;
9276   char *l, buffer[256];
9277
9278   D(emitcode (";     genDataPointerSet",""));
9279
9280   aopOp (right, ic, FALSE);
9281
9282   l = aopGet (result, 0, FALSE, TRUE);
9283   size = AOP_SIZE (right);
9284   while (size--)
9285     {
9286       if (offset)
9287         sprintf (buffer, "(%s + %d)", l + 1, offset);
9288       else
9289         sprintf (buffer, "%s", l + 1);
9290       emitcode ("mov", "%s,%s", buffer,
9291                 aopGet (right, offset++, FALSE, FALSE));
9292     }
9293
9294   freeAsmop (right, NULL, ic, TRUE);
9295   freeAsmop (result, NULL, ic, TRUE);
9296 }
9297
9298 /*-----------------------------------------------------------------*/
9299 /* genNearPointerSet - emitcode for near pointer put                */
9300 /*-----------------------------------------------------------------*/
9301 static void
9302 genNearPointerSet (operand * right,
9303                    operand * result,
9304                    iCode * ic,
9305                    iCode * pi)
9306 {
9307   asmop *aop = NULL;
9308   regs *preg = NULL;
9309   char *rname, *l;
9310   sym_link *retype, *letype;
9311   sym_link *ptype = operandType (result);
9312
9313   D(emitcode (";     genNearPointerSet",""));
9314
9315   retype = getSpec (operandType (right));
9316   letype = getSpec (ptype);
9317   aopOp (result, ic, FALSE);
9318
9319   /* if the result is rematerializable &
9320      in data space & not a bit variable */
9321   if (AOP_TYPE (result) == AOP_IMMD &&
9322       DCL_TYPE (ptype) == POINTER &&
9323       !IS_BITVAR (retype) &&
9324       !IS_BITVAR (letype))
9325     {
9326       genDataPointerSet (right, result, ic);
9327       return;
9328     }
9329
9330   /* if the value is already in a pointer register
9331      then don't need anything more */
9332   if (!AOP_INPREG (AOP (result)))
9333     {
9334         if (
9335             //AOP_TYPE (result) == AOP_STK
9336             IS_AOP_PREG(result)
9337             )
9338         {
9339             // Aha, it is a pointer, just in disguise.
9340             rname = aopGet (result, 0, FALSE, FALSE);
9341             if (*rname != '@')
9342             {
9343                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9344                         __FILE__, __LINE__);
9345             }
9346             else
9347             {
9348                 // Expected case.
9349                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9350                 rname++;  // skip the '@'.
9351             }
9352         }
9353         else
9354         {
9355             /* otherwise get a free pointer register */
9356             aop = newAsmop (0);
9357             preg = getFreePtr (ic, &aop, FALSE);
9358             emitcode ("mov", "%s,%s",
9359                       preg->name,
9360                       aopGet (result, 0, FALSE, TRUE));
9361             rname = preg->name;
9362         }
9363     }
9364     else
9365     {
9366         rname = aopGet (result, 0, FALSE, FALSE);
9367     }
9368
9369   aopOp (right, ic, FALSE);
9370
9371   /* if bitfield then unpack the bits */
9372   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9373     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9374   else
9375     {
9376       /* we have can just get the values */
9377       int size = AOP_SIZE (right);
9378       int offset = 0;
9379
9380       while (size--)
9381         {
9382           l = aopGet (right, offset, FALSE, TRUE);
9383           if (*l == '@')
9384             {
9385               MOVA (l);
9386               emitcode ("mov", "@%s,a", rname);
9387             }
9388           else
9389             emitcode ("mov", "@%s,%s", rname, l);
9390           if (size || pi)
9391             emitcode ("inc", "%s", rname);
9392           offset++;
9393         }
9394     }
9395
9396   /* now some housekeeping stuff */
9397   if (aop) /* we had to allocate for this iCode */
9398     {
9399       if (pi)
9400         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9401       freeAsmop (NULL, aop, ic, TRUE);
9402     }
9403   else
9404     {
9405       /* we did not allocate which means left
9406          already in a pointer register, then
9407          if size > 0 && this could be used again
9408          we have to point it back to where it
9409          belongs */
9410       if ((AOP_SIZE (right) > 1 &&
9411            !OP_SYMBOL (result)->remat &&
9412            (OP_SYMBOL (result)->liveTo > ic->seq ||
9413             ic->depth)) &&
9414           !pi)
9415         {
9416           int size = AOP_SIZE (right) - 1;
9417           while (size--)
9418             emitcode ("dec", "%s", rname);
9419         }
9420     }
9421
9422   /* done */
9423   if (pi) pi->generated = 1;
9424   freeAsmop (result, NULL, ic, TRUE);
9425   freeAsmop (right, NULL, ic, TRUE);
9426 }
9427
9428 /*-----------------------------------------------------------------*/
9429 /* genPagedPointerSet - emitcode for Paged pointer put             */
9430 /*-----------------------------------------------------------------*/
9431 static void
9432 genPagedPointerSet (operand * right,
9433                     operand * result,
9434                     iCode * ic,
9435                     iCode * pi)
9436 {
9437   asmop *aop = NULL;
9438   regs *preg = NULL;
9439   char *rname, *l;
9440   sym_link *retype, *letype;
9441
9442   D(emitcode (";     genPagedPointerSet",""));
9443
9444   retype = getSpec (operandType (right));
9445   letype = getSpec (operandType (result));
9446
9447   aopOp (result, ic, FALSE);
9448
9449   /* if the value is already in a pointer register
9450      then don't need anything more */
9451   if (!AOP_INPREG (AOP (result)))
9452     {
9453       /* otherwise get a free pointer register */
9454       aop = newAsmop (0);
9455       preg = getFreePtr (ic, &aop, FALSE);
9456       emitcode ("mov", "%s,%s",
9457                 preg->name,
9458                 aopGet (result, 0, FALSE, TRUE));
9459       rname = preg->name;
9460     }
9461   else
9462     rname = aopGet (result, 0, FALSE, FALSE);
9463
9464   aopOp (right, ic, FALSE);
9465
9466   /* if bitfield then unpack the bits */
9467   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9468     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9469   else
9470     {
9471       /* we have can just get the values */
9472       int size = AOP_SIZE (right);
9473       int offset = 0;
9474
9475       while (size--)
9476         {
9477           l = aopGet (right, offset, FALSE, TRUE);
9478
9479           MOVA (l);
9480           emitcode ("movx", "@%s,a", rname);
9481
9482           if (size || pi)
9483             emitcode ("inc", "%s", rname);
9484
9485           offset++;
9486         }
9487     }
9488
9489   /* now some housekeeping stuff */
9490   if (aop) /* we had to allocate for this iCode */
9491     {
9492       if (pi)
9493         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9494       freeAsmop (NULL, aop, ic, TRUE);
9495     }
9496   else
9497     {
9498       /* we did not allocate which means left
9499          already in a pointer register, then
9500          if size > 0 && this could be used again
9501          we have to point it back to where it
9502          belongs */
9503       if (AOP_SIZE (right) > 1 &&
9504           !OP_SYMBOL (result)->remat &&
9505           (OP_SYMBOL (result)->liveTo > ic->seq ||
9506            ic->depth))
9507         {
9508           int size = AOP_SIZE (right) - 1;
9509           while (size--)
9510             emitcode ("dec", "%s", rname);
9511         }
9512     }
9513
9514   /* done */
9515   if (pi) pi->generated = 1;
9516   freeAsmop (result, NULL, ic, TRUE);
9517   freeAsmop (right, NULL, ic, TRUE);
9518
9519
9520 }
9521
9522 /*-----------------------------------------------------------------*/
9523 /* genFarPointerSet - set value from far space                     */
9524 /*-----------------------------------------------------------------*/
9525 static void
9526 genFarPointerSet (operand * right,
9527                   operand * result, iCode * ic, iCode * pi)
9528 {
9529   int size, offset;
9530   sym_link *retype = getSpec (operandType (right));
9531   sym_link *letype = getSpec (operandType (result));
9532
9533   D(emitcode (";     genFarPointerSet",""));
9534
9535   aopOp (result, ic, FALSE);
9536   loadDptrFromOperand (result, FALSE);
9537
9538   /* so dptr know contains the address */
9539   aopOp (right, ic, FALSE);
9540
9541   /* if bit then unpack */
9542   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9543     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9544   else
9545     {
9546       size = AOP_SIZE (right);
9547       offset = 0;
9548
9549       while (size--)
9550         {
9551           char *l = aopGet (right, offset++, FALSE, FALSE);
9552           MOVA (l);
9553           emitcode ("movx", "@dptr,a");
9554           if (size || pi)
9555             emitcode ("inc", "dptr");
9556         }
9557     }
9558   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9559     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9560     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9561     pi->generated=1;
9562   }
9563   freeAsmop (result, NULL, ic, TRUE);
9564   freeAsmop (right, NULL, ic, TRUE);
9565 }
9566
9567 /*-----------------------------------------------------------------*/
9568 /* genGenPointerSet - set value from generic pointer space         */
9569 /*-----------------------------------------------------------------*/
9570 static void
9571 genGenPointerSet (operand * right,
9572                   operand * result, iCode * ic, iCode * pi)
9573 {
9574   int size, offset;
9575   sym_link *retype = getSpec (operandType (right));
9576   sym_link *letype = getSpec (operandType (result));
9577
9578   D(emitcode (";     genGenPointerSet",""));
9579
9580   aopOp (result, ic, FALSE);
9581   loadDptrFromOperand (result, TRUE);
9582
9583   /* so dptr know contains the address */
9584   aopOp (right, ic, FALSE);
9585
9586   /* if bit then unpack */
9587   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9588     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9589   else
9590     {
9591       size = AOP_SIZE (right);
9592       offset = 0;
9593
9594       while (size--)
9595         {
9596           char *l = aopGet (right, offset++, FALSE, FALSE);
9597           MOVA (l);
9598           emitcode ("lcall", "__gptrput");
9599           if (size || pi)
9600             emitcode ("inc", "dptr");
9601         }
9602     }
9603
9604   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9605     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9606     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9607     pi->generated=1;
9608   }
9609   freeAsmop (result, NULL, ic, TRUE);
9610   freeAsmop (right, NULL, ic, TRUE);
9611 }
9612
9613 /*-----------------------------------------------------------------*/
9614 /* genPointerSet - stores the value into a pointer location        */
9615 /*-----------------------------------------------------------------*/
9616 static void
9617 genPointerSet (iCode * ic, iCode *pi)
9618 {
9619   operand *right, *result;
9620   sym_link *type, *etype;
9621   int p_type;
9622
9623   D(emitcode (";     genPointerSet",""));
9624
9625   right = IC_RIGHT (ic);
9626   result = IC_RESULT (ic);
9627
9628   /* depending on the type of pointer we need to
9629      move it to the correct pointer register */
9630   type = operandType (result);
9631   etype = getSpec (type);
9632   /* if left is of type of pointer then it is simple */
9633   if (IS_PTR (type) && !IS_FUNC (type->next))
9634     {
9635       p_type = DCL_TYPE (type);
9636     }
9637   else
9638     {
9639       /* we have to go by the storage class */
9640       p_type = PTR_TYPE (SPEC_OCLS (etype));
9641     }
9642
9643   /* special case when cast remat */
9644   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9645       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9646           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9647           type = operandType (result);
9648           p_type = DCL_TYPE (type);
9649   }
9650   /* now that we have the pointer type we assign
9651      the pointer values */
9652   switch (p_type)
9653     {
9654
9655     case POINTER:
9656     case IPOINTER:
9657       genNearPointerSet (right, result, ic, pi);
9658       break;
9659
9660     case PPOINTER:
9661       genPagedPointerSet (right, result, ic, pi);
9662       break;
9663
9664     case FPOINTER:
9665       genFarPointerSet (right, result, ic, pi);
9666       break;
9667
9668     case GPOINTER:
9669       genGenPointerSet (right, result, ic, pi);
9670       break;
9671
9672     default:
9673       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9674               "genPointerSet: illegal pointer type");
9675     }
9676
9677 }
9678
9679 /*-----------------------------------------------------------------*/
9680 /* genIfx - generate code for Ifx statement                        */
9681 /*-----------------------------------------------------------------*/
9682 static void
9683 genIfx (iCode * ic, iCode * popIc)
9684 {
9685   operand *cond = IC_COND (ic);
9686   int isbit = 0;
9687
9688   D(emitcode (";     genIfx",""));
9689
9690   aopOp (cond, ic, FALSE);
9691
9692   /* get the value into acc */
9693   if (AOP_TYPE (cond) != AOP_CRY)
9694     toBoolean (cond);
9695   else
9696     isbit = 1;
9697   /* the result is now in the accumulator */
9698   freeAsmop (cond, NULL, ic, TRUE);
9699
9700   /* if there was something to be popped then do it */
9701   if (popIc)
9702     genIpop (popIc);
9703
9704   /* if the condition is a bit variable */
9705   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9706     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9707   else if (isbit && !IS_ITEMP (cond))
9708     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9709   else
9710     genIfxJump (ic, "a", NULL, NULL, NULL);
9711
9712   ic->generated = 1;
9713 }
9714
9715 /*-----------------------------------------------------------------*/
9716 /* genAddrOf - generates code for address of                       */
9717 /*-----------------------------------------------------------------*/
9718 static void
9719 genAddrOf (iCode * ic)
9720 {
9721   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9722   int size, offset;
9723
9724   D(emitcode (";     genAddrOf",""));
9725
9726   aopOp (IC_RESULT (ic), ic, FALSE);
9727
9728   /* if the operand is on the stack then we
9729      need to get the stack offset of this
9730      variable */
9731   if (sym->onStack)
9732     {
9733       /* if it has an offset then we need to compute
9734          it */
9735       if (sym->stack)
9736         {
9737           emitcode ("mov", "a,%s", SYM_BP (sym));
9738           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9739                                          ((char) (sym->stack - _G.nRegsSaved)) :
9740                                          ((char) sym->stack)) & 0xff);
9741           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9742         }
9743       else
9744         {
9745           /* we can just move _bp */
9746           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9747         }
9748       /* fill the result with zero */
9749       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9750
9751       offset = 1;
9752       while (size--)
9753         {
9754           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9755         }
9756
9757       goto release;
9758     }
9759
9760   /* object not on stack then we need the name */
9761   size = AOP_SIZE (IC_RESULT (ic));
9762   offset = 0;
9763
9764   while (size--)
9765     {
9766       char s[SDCC_NAME_MAX];
9767       if (offset)
9768         sprintf (s, "#(%s >> %d)",
9769                  sym->rname,
9770                  offset * 8);
9771       else
9772         sprintf (s, "#%s", sym->rname);
9773       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9774     }
9775
9776 release:
9777   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9778
9779 }
9780
9781 /*-----------------------------------------------------------------*/
9782 /* genFarFarAssign - assignment when both are in far space         */
9783 /*-----------------------------------------------------------------*/
9784 static void
9785 genFarFarAssign (operand * result, operand * right, iCode * ic)
9786 {
9787   int size = AOP_SIZE (right);
9788   int offset = 0;
9789   char *l;
9790
9791   D(emitcode (";     genFarFarAssign",""));
9792
9793   /* first push the right side on to the stack */
9794   while (size--)
9795     {
9796       l = aopGet (right, offset++, FALSE, FALSE);
9797       MOVA (l);
9798       emitcode ("push", "acc");
9799     }
9800
9801   freeAsmop (right, NULL, ic, FALSE);
9802   /* now assign DPTR to result */
9803   aopOp (result, ic, FALSE);
9804   size = AOP_SIZE (result);
9805   while (size--)
9806     {
9807       emitcode ("pop", "acc");
9808       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
9809     }
9810   freeAsmop (result, NULL, ic, FALSE);
9811
9812 }
9813
9814 /*-----------------------------------------------------------------*/
9815 /* genAssign - generate code for assignment                        */
9816 /*-----------------------------------------------------------------*/
9817 static void
9818 genAssign (iCode * ic)
9819 {
9820   operand *result, *right;
9821   int size, offset;
9822   unsigned long lit = 0L;
9823
9824   D(emitcode(";     genAssign",""));
9825
9826   result = IC_RESULT (ic);
9827   right = IC_RIGHT (ic);
9828
9829   /* if they are the same */
9830   if (operandsEqu (result, right) &&
9831       !isOperandVolatile (result, FALSE) &&
9832       !isOperandVolatile (right, FALSE))
9833     return;
9834
9835   aopOp (right, ic, FALSE);
9836
9837   /* special case both in far space */
9838   if (AOP_TYPE (right) == AOP_DPTR &&
9839       IS_TRUE_SYMOP (result) &&
9840       isOperandInFarSpace (result))
9841     {
9842
9843       genFarFarAssign (result, right, ic);
9844       return;
9845     }
9846
9847   aopOp (result, ic, TRUE);
9848
9849   /* if they are the same registers */
9850   if (sameRegs (AOP (right), AOP (result)) &&
9851       !isOperandVolatile (result, FALSE) &&
9852       !isOperandVolatile (right, FALSE))
9853     goto release;
9854
9855   /* if the result is a bit */
9856   if (AOP_TYPE (result) == AOP_CRY)
9857     {
9858
9859       /* if the right size is a literal then
9860          we know what the value is */
9861       if (AOP_TYPE (right) == AOP_LIT)
9862         {
9863           if (((int) operandLitValue (right)))
9864             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
9865           else
9866             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
9867           goto release;
9868         }
9869
9870       /* the right is also a bit variable */
9871       if (AOP_TYPE (right) == AOP_CRY)
9872         {
9873           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9874           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
9875           goto release;
9876         }
9877
9878       /* we need to or */
9879       toBoolean (right);
9880       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9881       goto release;
9882     }
9883
9884   /* bit variables done */
9885   /* general case */
9886   size = AOP_SIZE (result);
9887   offset = 0;
9888   if (AOP_TYPE (right) == AOP_LIT)
9889     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9890   if ((size > 1) &&
9891       (AOP_TYPE (result) != AOP_REG) &&
9892       (AOP_TYPE (right) == AOP_LIT) &&
9893       !IS_FLOAT (operandType (right)) &&
9894       (lit < 256L))
9895     {
9896       while ((size) && (lit))
9897         {
9898           aopPut (result,
9899                   aopGet (right, offset, FALSE, FALSE),
9900                   offset,
9901                   isOperandVolatile (result, FALSE));
9902           lit >>= 8;
9903           offset++;
9904           size--;
9905         }
9906       emitcode ("clr", "a");
9907       while (size--)
9908         {
9909           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9910           offset++;
9911         }
9912     }
9913   else
9914     {
9915       while (size--)
9916         {
9917           aopPut (result,
9918                   aopGet (right, offset, FALSE, FALSE),
9919                   offset,
9920                   isOperandVolatile (result, FALSE));
9921           offset++;
9922         }
9923     }
9924
9925 release:
9926   freeAsmop (right, NULL, ic, TRUE);
9927   freeAsmop (result, NULL, ic, TRUE);
9928 }
9929
9930 /*-----------------------------------------------------------------*/
9931 /* genJumpTab - generates code for jump table                      */
9932 /*-----------------------------------------------------------------*/
9933 static void
9934 genJumpTab (iCode * ic)
9935 {
9936   symbol *jtab,*jtablo,*jtabhi;
9937   char *l;
9938   unsigned int count;
9939
9940   D(emitcode (";     genJumpTab",""));
9941
9942   count = elementsInSet( IC_JTLABELS (ic) );
9943
9944   if( count <= 16 )
9945     {
9946       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9947          if the switch argument is in a register.
9948          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9949       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9950          How will multiply by three be updated ???*/
9951       aopOp (IC_JTCOND (ic), ic, FALSE);
9952       /* get the condition into accumulator */
9953       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
9954       MOVA (l);
9955       /* multiply by three */
9956       emitcode ("add", "a,acc");
9957       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
9958       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9959
9960       jtab = newiTempLabel (NULL);
9961       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9962       emitcode ("jmp", "@a+dptr");
9963       emitcode ("", "%05d$:", jtab->key + 100);
9964       /* now generate the jump labels */
9965       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9966            jtab = setNextItem (IC_JTLABELS (ic)))
9967         emitcode ("ljmp", "%05d$", jtab->key + 100);
9968     }
9969   else
9970     {
9971       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9972          if the switch argument is in a register.
9973          For n>6 this algorithm may be more compact */
9974       jtablo = newiTempLabel (NULL);
9975       jtabhi = newiTempLabel (NULL);
9976
9977       /* get the condition into accumulator.
9978          Using b as temporary storage, if register push/pop is needed */
9979       aopOp (IC_JTCOND (ic), ic, FALSE);
9980       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
9981       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9982           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9983         {
9984           // (MB) what if B is in use???
9985           wassertl(!BINUSE, "B was in use");
9986           emitcode ("mov", "b,%s", l);
9987           l = "b";
9988         }
9989       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9990       MOVA (l);
9991       if( count <= 112 )
9992         {
9993           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9994           emitcode ("movc", "a,@a+pc");
9995           emitcode ("push", "acc");
9996
9997           MOVA (l);
9998           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9999           emitcode ("movc", "a,@a+pc");
10000           emitcode ("push", "acc");
10001         }
10002       else
10003         {
10004           /* this scales up to n<=255, but needs two more bytes
10005              and changes dptr */
10006           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10007           emitcode ("movc", "a,@a+dptr");
10008           emitcode ("push", "acc");
10009
10010           MOVA (l);
10011           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10012           emitcode ("movc", "a,@a+dptr");
10013           emitcode ("push", "acc");
10014         }
10015
10016       emitcode ("ret", "");
10017
10018       /* now generate jump table, LSB */
10019       emitcode ("", "%05d$:", jtablo->key + 100);
10020       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10021            jtab = setNextItem (IC_JTLABELS (ic)))
10022         emitcode (".db", "%05d$", jtab->key + 100);
10023
10024       /* now generate jump table, MSB */
10025       emitcode ("", "%05d$:", jtabhi->key + 100);
10026       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10027            jtab = setNextItem (IC_JTLABELS (ic)))
10028          emitcode (".db", "%05d$>>8", jtab->key + 100);
10029     }
10030 }
10031
10032 /*-----------------------------------------------------------------*/
10033 /* genCast - gen code for casting                                  */
10034 /*-----------------------------------------------------------------*/
10035 static void
10036 genCast (iCode * ic)
10037 {
10038   operand *result = IC_RESULT (ic);
10039   sym_link *ctype = operandType (IC_LEFT (ic));
10040   sym_link *rtype = operandType (IC_RIGHT (ic));
10041   operand *right = IC_RIGHT (ic);
10042   int size, offset;
10043
10044   D(emitcode(";     genCast",""));
10045
10046   /* if they are equivalent then do nothing */
10047   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10048     return;
10049
10050   aopOp (right, ic, FALSE);
10051   aopOp (result, ic, FALSE);
10052
10053   /* if the result is a bit (and not a bitfield) */
10054   // if (AOP_TYPE (result) == AOP_CRY)
10055   if (IS_BITVAR (OP_SYMBOL (result)->type)
10056       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10057     {
10058       /* if the right size is a literal then
10059          we know what the value is */
10060       if (AOP_TYPE (right) == AOP_LIT)
10061         {
10062           if (((int) operandLitValue (right)))
10063             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10064           else
10065             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10066
10067           goto release;
10068         }
10069
10070       /* the right is also a bit variable */
10071       if (AOP_TYPE (right) == AOP_CRY)
10072         {
10073           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10074           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10075           goto release;
10076         }
10077
10078       /* we need to or */
10079       toBoolean (right);
10080       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10081       goto release;
10082     }
10083
10084
10085   /* if they are the same size : or less */
10086   if (AOP_SIZE (result) <= AOP_SIZE (right))
10087     {
10088
10089       /* if they are in the same place */
10090       if (sameRegs (AOP (right), AOP (result)))
10091         goto release;
10092
10093       /* if they in different places then copy */
10094       size = AOP_SIZE (result);
10095       offset = 0;
10096       while (size--)
10097         {
10098           aopPut (result,
10099                   aopGet (right, offset, FALSE, FALSE),
10100                   offset,
10101                   isOperandVolatile (result, FALSE));
10102           offset++;
10103         }
10104       goto release;
10105     }
10106
10107
10108   /* if the result is of type pointer */
10109   if (IS_PTR (ctype))
10110     {
10111
10112       int p_type;
10113       sym_link *type = operandType (right);
10114       sym_link *etype = getSpec (type);
10115
10116       /* pointer to generic pointer */
10117       if (IS_GENPTR (ctype))
10118         {
10119           if (IS_PTR (type))
10120             p_type = DCL_TYPE (type);
10121           else
10122             {
10123               if (SPEC_SCLS(etype)==S_REGISTER) {
10124                 // let's assume it is a generic pointer
10125                 p_type=GPOINTER;
10126               } else {
10127                 /* we have to go by the storage class */
10128                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10129               }
10130             }
10131
10132           /* the first two bytes are known */
10133           size = GPTRSIZE - 1;
10134           offset = 0;
10135           while (size--)
10136             {
10137               aopPut (result,
10138                       aopGet (right, offset, FALSE, FALSE),
10139                       offset,
10140                       isOperandVolatile (result, FALSE));
10141               offset++;
10142             }
10143           /* the last byte depending on type */
10144             {
10145                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10146                 char gpValStr[10];
10147
10148                 if (gpVal == -1)
10149                 {
10150                     // pointerTypeToGPByte will have bitched.
10151                     exit(1);
10152                 }
10153
10154                 sprintf(gpValStr, "#0x%x", gpVal);
10155                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10156             }
10157           goto release;
10158         }
10159
10160       /* just copy the pointers */
10161       size = AOP_SIZE (result);
10162       offset = 0;
10163       while (size--)
10164         {
10165           aopPut (result,
10166                   aopGet (right, offset, FALSE, FALSE),
10167                   offset,
10168                   isOperandVolatile (result, FALSE));
10169           offset++;
10170         }
10171       goto release;
10172     }
10173
10174   /* so we now know that the size of destination is greater
10175      than the size of the source */
10176   /* we move to result for the size of source */
10177   size = AOP_SIZE (right);
10178   offset = 0;
10179   while (size--)
10180     {
10181       aopPut (result,
10182               aopGet (right, offset, FALSE, FALSE),
10183               offset,
10184               isOperandVolatile (result, FALSE));
10185       offset++;
10186     }
10187
10188   /* now depending on the sign of the source && destination */
10189   size = AOP_SIZE (result) - AOP_SIZE (right);
10190   /* if unsigned or not an integral type */
10191   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10192     {
10193       while (size--)
10194         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10195     }
10196   else
10197     {
10198       /* we need to extend the sign :{ */
10199       char *l = aopGet (right, AOP_SIZE (right) - 1,
10200                         FALSE, FALSE);
10201       MOVA (l);
10202       emitcode ("rlc", "a");
10203       emitcode ("subb", "a,acc");
10204       while (size--)
10205         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10206     }
10207
10208   /* we are done hurray !!!! */
10209
10210 release:
10211   freeAsmop (right, NULL, ic, TRUE);
10212   freeAsmop (result, NULL, ic, TRUE);
10213
10214 }
10215
10216 /*-----------------------------------------------------------------*/
10217 /* genDjnz - generate decrement & jump if not zero instrucion      */
10218 /*-----------------------------------------------------------------*/
10219 static int
10220 genDjnz (iCode * ic, iCode * ifx)
10221 {
10222   symbol *lbl, *lbl1;
10223   if (!ifx)
10224     return 0;
10225
10226   D(emitcode (";     genDjnz",""));
10227
10228   /* if the if condition has a false label
10229      then we cannot save */
10230   if (IC_FALSE (ifx))
10231     return 0;
10232
10233   /* if the minus is not of the form
10234      a = a - 1 */
10235   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10236       !IS_OP_LITERAL (IC_RIGHT (ic)))
10237     return 0;
10238
10239   if (operandLitValue (IC_RIGHT (ic)) != 1)
10240     return 0;
10241
10242   /* if the size of this greater than one then no
10243      saving */
10244   if (getSize (operandType (IC_RESULT (ic))) > 1)
10245     return 0;
10246
10247   /* otherwise we can save BIG */
10248   lbl = newiTempLabel (NULL);
10249   lbl1 = newiTempLabel (NULL);
10250
10251   aopOp (IC_RESULT (ic), ic, FALSE);
10252
10253   if (AOP_NEEDSACC(IC_RESULT(ic)))
10254   {
10255       /* If the result is accessed indirectly via
10256        * the accumulator, we must explicitly write
10257        * it back after the decrement.
10258        */
10259       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10260
10261       if (strcmp(rByte, "a"))
10262       {
10263            /* Something is hopelessly wrong */
10264            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10265                    __FILE__, __LINE__);
10266            /* We can just give up; the generated code will be inefficient,
10267             * but what the hey.
10268             */
10269            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10270            return 0;
10271       }
10272       emitcode ("dec", "%s", rByte);
10273       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10274       emitcode ("jnz", "%05d$", lbl->key + 100);
10275   }
10276   else if (IS_AOP_PREG (IC_RESULT (ic)))
10277     {
10278       emitcode ("dec", "%s",
10279                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10280       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10281       emitcode ("jnz", "%05d$", lbl->key + 100);
10282     }
10283   else
10284     {
10285       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10286                 lbl->key + 100);
10287     }
10288   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10289   emitcode ("", "%05d$:", lbl->key + 100);
10290   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10291   emitcode ("", "%05d$:", lbl1->key + 100);
10292
10293   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10294   ifx->generated = 1;
10295   return 1;
10296 }
10297
10298 /*-----------------------------------------------------------------*/
10299 /* genReceive - generate code for a receive iCode                  */
10300 /*-----------------------------------------------------------------*/
10301 static void
10302 genReceive (iCode * ic)
10303 {
10304     int size = getSize (operandType (IC_RESULT (ic)));
10305     int offset = 0;
10306   D(emitcode (";     genReceive",""));
10307
10308   if (ic->argreg == 1) { /* first parameter */
10309       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10310           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10311            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10312
10313           regs *tempRegs[4];
10314           int receivingA = 0;
10315           int roffset = 0;
10316
10317           for (offset = 0; offset<size; offset++)
10318             if (!strcmp (fReturn[offset], "a"))
10319               receivingA = 1;
10320
10321           if (!receivingA)
10322             {
10323               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10324                 {
10325                   for (offset = size-1; offset>0; offset--)
10326                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10327                   emitcode("mov","a,%s", fReturn[0]);
10328                   _G.accInUse++;
10329                   aopOp (IC_RESULT (ic), ic, FALSE);
10330                   _G.accInUse--;
10331                   aopPut (IC_RESULT (ic), "a", offset,
10332                           isOperandVolatile (IC_RESULT (ic), FALSE));
10333                   for (offset = 1; offset<size; offset++)
10334                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10335                             isOperandVolatile (IC_RESULT (ic), FALSE));
10336                   goto release;
10337                 }
10338             }
10339           else
10340             {
10341               if (getTempRegs(tempRegs, size, ic))
10342                 {
10343                   for (offset = 0; offset<size; offset++)
10344                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10345                   aopOp (IC_RESULT (ic), ic, FALSE);
10346                   for (offset = 0; offset<size; offset++)
10347                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10348                             isOperandVolatile (IC_RESULT (ic), FALSE));
10349                   goto release;
10350                 }
10351             }
10352
10353           offset = fReturnSizeMCS51 - size;
10354           while (size--) {
10355               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10356                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10357               offset++;
10358           }
10359           aopOp (IC_RESULT (ic), ic, FALSE);
10360           size = AOP_SIZE (IC_RESULT (ic));
10361           offset = 0;
10362           while (size--) {
10363               emitcode ("pop", "acc");
10364               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10365           }
10366
10367       } else {
10368           _G.accInUse++;
10369           aopOp (IC_RESULT (ic), ic, FALSE);
10370           _G.accInUse--;
10371           assignResultValue (IC_RESULT (ic));
10372       }
10373   } else { /* second receive onwards */
10374       int rb1off ;
10375       aopOp (IC_RESULT (ic), ic, FALSE);
10376       rb1off = ic->argreg;
10377       while (size--) {
10378           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10379       }
10380   }
10381
10382 release:
10383   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10384 }
10385
10386 /*-----------------------------------------------------------------*/
10387 /* genDummyRead - generate code for dummy read of volatiles        */
10388 /*-----------------------------------------------------------------*/
10389 static void
10390 genDummyRead (iCode * ic)
10391 {
10392   operand *op;
10393   int size, offset;
10394
10395   D(emitcode(";     genDummyRead",""));
10396
10397   op = IC_RIGHT (ic);
10398   if (op && IS_SYMOP (op))
10399     {
10400       aopOp (op, ic, FALSE);
10401
10402       /* if the result is a bit */
10403       if (AOP_TYPE (op) == AOP_CRY)
10404         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10405       else
10406         {
10407           /* bit variables done */
10408           /* general case */
10409           size = AOP_SIZE (op);
10410           offset = 0;
10411           while (size--)
10412           {
10413             MOVA (aopGet (op, offset, FALSE, FALSE));
10414             offset++;
10415           }
10416         }
10417
10418       freeAsmop (op, NULL, ic, TRUE);
10419     }
10420
10421   op = IC_LEFT (ic);
10422   if (op && IS_SYMOP (op))
10423     {
10424       aopOp (op, ic, FALSE);
10425
10426       /* if the result is a bit */
10427       if (AOP_TYPE (op) == AOP_CRY)
10428         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10429       else
10430         {
10431           /* bit variables done */
10432           /* general case */
10433           size = AOP_SIZE (op);
10434           offset = 0;
10435           while (size--)
10436           {
10437             MOVA (aopGet (op, offset, FALSE, FALSE));
10438             offset++;
10439           }
10440         }
10441
10442       freeAsmop (op, NULL, ic, TRUE);
10443     }
10444 }
10445
10446 /*-----------------------------------------------------------------*/
10447 /* genCritical - generate code for start of a critical sequence    */
10448 /*-----------------------------------------------------------------*/
10449 static void
10450 genCritical (iCode *ic)
10451 {
10452   symbol *tlbl = newiTempLabel (NULL);
10453
10454   D(emitcode(";     genCritical",""));
10455
10456   if (IC_RESULT (ic))
10457     {
10458       aopOp (IC_RESULT (ic), ic, TRUE);
10459       aopPut (IC_RESULT (ic), one, 0, 0);
10460       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10461       aopPut (IC_RESULT (ic), zero, 0, 0);
10462       emitcode ("", "%05d$:", (tlbl->key + 100));
10463       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10464     }
10465   else
10466     {
10467       emitcode ("setb", "c");
10468       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10469       emitcode ("clr", "c");
10470       emitcode ("", "%05d$:", (tlbl->key + 100));
10471       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10472     }
10473 }
10474
10475 /*-----------------------------------------------------------------*/
10476 /* genEndCritical - generate code for end of a critical sequence   */
10477 /*-----------------------------------------------------------------*/
10478 static void
10479 genEndCritical (iCode *ic)
10480 {
10481   D(emitcode(";     genEndCritical",""));
10482
10483   if (IC_RIGHT (ic))
10484     {
10485       aopOp (IC_RIGHT (ic), ic, FALSE);
10486       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10487         {
10488           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10489           emitcode ("mov", "ea,c");
10490         }
10491       else
10492         {
10493           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10494             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
10495           emitcode ("rrc", "a");
10496           emitcode ("mov", "ea,c");
10497         }
10498       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10499     }
10500   else
10501     {
10502       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10503       emitcode ("mov", "ea,c");
10504     }
10505 }
10506
10507 /*-----------------------------------------------------------------*/
10508 /* gen51Code - generate code for 8051 based controllers            */
10509 /*-----------------------------------------------------------------*/
10510 void
10511 gen51Code (iCode * lic)
10512 {
10513   iCode *ic;
10514   int cln = 0;
10515   /* int cseq = 0; */
10516
10517   _G.currentFunc = NULL;
10518   lineHead = lineCurr = NULL;
10519
10520   /* print the allocation information */
10521   if (allocInfo && currFunc)
10522     printAllocInfo (currFunc, codeOutFile);
10523   /* if debug information required */
10524   if (options.debug && currFunc)
10525     {
10526       debugFile->writeFunction (currFunc, lic);
10527     }
10528   /* stack pointer name */
10529   if (options.useXstack)
10530     spname = "_spx";
10531   else
10532     spname = "sp";
10533
10534
10535   for (ic = lic; ic; ic = ic->next)
10536     {
10537       _G.current_iCode = ic;
10538
10539       if (ic->lineno && cln != ic->lineno)
10540         {
10541           if (options.debug)
10542             {
10543               debugFile->writeCLine (ic);
10544             }
10545           if (!options.noCcodeInAsm) {
10546             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10547                       printCLine(ic->filename, ic->lineno));
10548           }
10549           cln = ic->lineno;
10550         }
10551       #if 0
10552       if (ic->seqPoint && ic->seqPoint != cseq)
10553         {
10554           emitcode ("", "; sequence point %d", ic->seqPoint);
10555           cseq = ic->seqPoint;
10556         }
10557       #endif
10558       if (options.iCodeInAsm) {
10559         char regsInUse[80];
10560         int i;
10561
10562         for (i=0; i<8; i++) {
10563           sprintf (&regsInUse[i],
10564                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10565         }
10566         regsInUse[i]=0;
10567         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10568       }
10569       /* if the result is marked as
10570          spilt and rematerializable or code for
10571          this has already been generated then
10572          do nothing */
10573       if (resultRemat (ic) || ic->generated)
10574         continue;
10575
10576       /* depending on the operation */
10577       switch (ic->op)
10578         {
10579         case '!':
10580           genNot (ic);
10581           break;
10582
10583         case '~':
10584           genCpl (ic);
10585           break;
10586
10587         case UNARYMINUS:
10588           genUminus (ic);
10589           break;
10590
10591         case IPUSH:
10592           genIpush (ic);
10593           break;
10594
10595         case IPOP:
10596           /* IPOP happens only when trying to restore a
10597              spilt live range, if there is an ifx statement
10598              following this pop then the if statement might
10599              be using some of the registers being popped which
10600              would destory the contents of the register so
10601              we need to check for this condition and handle it */
10602           if (ic->next &&
10603               ic->next->op == IFX &&
10604               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10605             genIfx (ic->next, ic);
10606           else
10607             genIpop (ic);
10608           break;
10609
10610         case CALL:
10611           genCall (ic);
10612           break;
10613
10614         case PCALL:
10615           genPcall (ic);
10616           break;
10617
10618         case FUNCTION:
10619           genFunction (ic);
10620           break;
10621
10622         case ENDFUNCTION:
10623           genEndFunction (ic);
10624           break;
10625
10626         case RETURN:
10627           genRet (ic);
10628           break;
10629
10630         case LABEL:
10631           genLabel (ic);
10632           break;
10633
10634         case GOTO:
10635           genGoto (ic);
10636           break;
10637
10638         case '+':
10639           genPlus (ic);
10640           break;
10641
10642         case '-':
10643           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10644             genMinus (ic);
10645           break;
10646
10647         case '*':
10648           genMult (ic);
10649           break;
10650
10651         case '/':
10652           genDiv (ic);
10653           break;
10654
10655         case '%':
10656           genMod (ic);
10657           break;
10658
10659         case '>':
10660           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10661           break;
10662
10663         case '<':
10664           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10665           break;
10666
10667         case LE_OP:
10668         case GE_OP:
10669         case NE_OP:
10670
10671           /* note these two are xlated by algebraic equivalence
10672              during parsing SDCC.y */
10673           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10674                   "got '>=' or '<=' shouldn't have come here");
10675           break;
10676
10677         case EQ_OP:
10678           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10679           break;
10680
10681         case AND_OP:
10682           genAndOp (ic);
10683           break;
10684
10685         case OR_OP:
10686           genOrOp (ic);
10687           break;
10688
10689         case '^':
10690           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10691           break;
10692
10693         case '|':
10694           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10695           break;
10696
10697         case BITWISEAND:
10698           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10699           break;
10700
10701         case INLINEASM:
10702           genInline (ic);
10703           break;
10704
10705         case RRC:
10706           genRRC (ic);
10707           break;
10708
10709         case RLC:
10710           genRLC (ic);
10711           break;
10712
10713         case GETHBIT:
10714           genGetHbit (ic);
10715           break;
10716
10717         case LEFT_OP:
10718           genLeftShift (ic);
10719           break;
10720
10721         case RIGHT_OP:
10722           genRightShift (ic);
10723           break;
10724
10725         case GET_VALUE_AT_ADDRESS:
10726           genPointerGet (ic,
10727                          hasInc (IC_LEFT (ic), ic,
10728                                  getSize (operandType (IC_RESULT (ic)))),
10729                          ifxForOp (IC_RESULT (ic), ic) );
10730           break;
10731
10732         case '=':
10733           if (POINTER_SET (ic))
10734             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10735           else
10736             genAssign (ic);
10737           break;
10738
10739         case IFX:
10740           genIfx (ic, NULL);
10741           break;
10742
10743         case ADDRESS_OF:
10744           genAddrOf (ic);
10745           break;
10746
10747         case JUMPTABLE:
10748           genJumpTab (ic);
10749           break;
10750
10751         case CAST:
10752           genCast (ic);
10753           break;
10754
10755         case RECEIVE:
10756           genReceive (ic);
10757           break;
10758
10759         case SEND:
10760           addSet (&_G.sendSet, ic);
10761           break;
10762
10763         case DUMMY_READ_VOLATILE:
10764           genDummyRead (ic);
10765           break;
10766
10767         case CRITICAL:
10768           genCritical (ic);
10769           break;
10770
10771         case ENDCRITICAL:
10772           genEndCritical (ic);
10773           break;
10774
10775         case SWAP:
10776           genSwap (ic);
10777           break;
10778
10779         default:
10780           ic = ic;
10781         }
10782     }
10783
10784   _G.current_iCode = NULL;
10785
10786   /* now we are ready to call the
10787      peep hole optimizer */
10788   if (!options.nopeep)
10789     peepHole (&lineHead);
10790
10791   /* now do the actual printing */
10792   printLine (lineHead, codeOutFile);
10793   return;
10794 }