* as/mcs51/asexpr.c (expr): disabled warning "not in .flat24 mode",
[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       (size > 1) &&
3500       (icount == 1))
3501     {
3502       symbol *tlbl;
3503       int emitTlbl;
3504       int labelRange;
3505
3506       /* If the next instruction is a goto and the goto target
3507        * is < 10 instructions previous to this, we can generate
3508        * jumps straight to that target.
3509        */
3510       if (ic->next && ic->next->op == GOTO
3511           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3512           && labelRange <= 10)
3513         {
3514           emitcode (";", "tail increment optimized");
3515           tlbl = IC_LABEL (ic->next);
3516           emitTlbl = 0;
3517         }
3518       else
3519         {
3520           tlbl = newiTempLabel (NULL);
3521           emitTlbl = 1;
3522         }
3523       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3524       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3525           IS_AOP_PREG (IC_RESULT (ic)))
3526         emitcode ("cjne", "%s,#0x00,%05d$",
3527                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3528                   tlbl->key + 100);
3529       else
3530         {
3531           emitcode ("clr", "a");
3532           emitcode ("cjne", "a,%s,%05d$",
3533                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3534                     tlbl->key + 100);
3535         }
3536
3537       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3538       if (size > 2)
3539         {
3540           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3541               IS_AOP_PREG (IC_RESULT (ic)))
3542             emitcode ("cjne", "%s,#0x00,%05d$",
3543                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3544                       tlbl->key + 100);
3545           else
3546             emitcode ("cjne", "a,%s,%05d$",
3547                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3548                       tlbl->key + 100);
3549
3550           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3551         }
3552       if (size > 3)
3553         {
3554           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3555               IS_AOP_PREG (IC_RESULT (ic)))
3556             emitcode ("cjne", "%s,#0x00,%05d$",
3557                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3558                       tlbl->key + 100);
3559           else
3560             {
3561               emitcode ("cjne", "a,%s,%05d$",
3562                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3563                         tlbl->key + 100);
3564             }
3565           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3566         }
3567
3568       if (emitTlbl)
3569         {
3570           emitcode ("", "%05d$:", tlbl->key + 100);
3571         }
3572       return TRUE;
3573     }
3574
3575   /* if the sizes are greater than 1 then we cannot */
3576   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3577       AOP_SIZE (IC_LEFT (ic)) > 1)
3578     return FALSE;
3579
3580   /* we can if the aops of the left & result match or
3581      if they are in registers and the registers are the
3582      same */
3583   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3584     {
3585
3586       if (icount > 3)
3587         {
3588           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3589           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3590           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3591         }
3592       else
3593         {
3594
3595           while (icount--)
3596             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3597         }
3598
3599       return TRUE;
3600     }
3601
3602   return FALSE;
3603 }
3604
3605 /*-----------------------------------------------------------------*/
3606 /* outBitAcc - output a bit in acc                                 */
3607 /*-----------------------------------------------------------------*/
3608 static void
3609 outBitAcc (operand * result)
3610 {
3611   symbol *tlbl = newiTempLabel (NULL);
3612   /* if the result is a bit */
3613   if (AOP_TYPE (result) == AOP_CRY)
3614     {
3615       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
3616     }
3617   else
3618     {
3619       emitcode ("jz", "%05d$", tlbl->key + 100);
3620       emitcode ("mov", "a,%s", one);
3621       emitcode ("", "%05d$:", tlbl->key + 100);
3622       outAcc (result);
3623     }
3624 }
3625
3626 /*-----------------------------------------------------------------*/
3627 /* genPlusBits - generates code for addition of two bits           */
3628 /*-----------------------------------------------------------------*/
3629 static void
3630 genPlusBits (iCode * ic)
3631 {
3632   D(emitcode (";     genPlusBits",""));
3633
3634   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3635     {
3636       symbol *lbl = newiTempLabel (NULL);
3637       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3638       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3639       emitcode ("cpl", "c");
3640       emitcode ("", "%05d$:", (lbl->key + 100));
3641       outBitC (IC_RESULT (ic));
3642     }
3643   else
3644     {
3645       emitcode ("clr", "a");
3646       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3647       emitcode ("rlc", "a");
3648       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3649       emitcode ("addc", "a,#0x00");
3650       outAcc (IC_RESULT (ic));
3651     }
3652 }
3653
3654 #if 0
3655 /* This is the original version of this code.
3656
3657  * This is being kept around for reference,
3658  * because I am not entirely sure I got it right...
3659  */
3660 static void
3661 adjustArithmeticResult (iCode * ic)
3662 {
3663   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3664       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3665       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3666     aopPut (IC_RESULT (ic),
3667             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
3668             2,
3669             isOperandVolatile (IC_RESULT (ic), FALSE));
3670
3671   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3672       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3673       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3674     aopPut (IC_RESULT (ic),
3675             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
3676             2,
3677             isOperandVolatile (IC_RESULT (ic), FALSE));
3678
3679   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3680       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3681       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3682       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3683       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3684     {
3685       char buffer[5];
3686       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3687       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3688     }
3689 }
3690 #else
3691 /* This is the pure and virtuous version of this code.
3692  * I'm pretty certain it's right, but not enough to toss the old
3693  * code just yet...
3694  */
3695 static void
3696 adjustArithmeticResult (iCode * ic)
3697 {
3698   if (opIsGptr (IC_RESULT (ic)) &&
3699       opIsGptr (IC_LEFT (ic)) &&
3700       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3701     {
3702       aopPut (IC_RESULT (ic),
3703               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
3704               GPTRSIZE - 1,
3705               isOperandVolatile (IC_RESULT (ic), FALSE));
3706     }
3707
3708   if (opIsGptr (IC_RESULT (ic)) &&
3709       opIsGptr (IC_RIGHT (ic)) &&
3710       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3711     {
3712       aopPut (IC_RESULT (ic),
3713               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
3714               GPTRSIZE - 1,
3715               isOperandVolatile (IC_RESULT (ic), FALSE));
3716     }
3717
3718   if (opIsGptr (IC_RESULT (ic)) &&
3719       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3720       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3721       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3722       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3723     {
3724       char buffer[5];
3725       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3726       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3727     }
3728 }
3729 #endif
3730
3731 /*-----------------------------------------------------------------*/
3732 /* genPlus - generates code for addition                           */
3733 /*-----------------------------------------------------------------*/
3734 static void
3735 genPlus (iCode * ic)
3736 {
3737   int size, offset = 0;
3738   int skip_bytes = 0;
3739   char *add = "add";
3740   operand *leftOp, *rightOp;
3741   operand * op;
3742
3743   /* special cases :- */
3744
3745   D(emitcode (";     genPlus",""));
3746
3747   aopOp (IC_LEFT (ic), ic, FALSE);
3748   aopOp (IC_RIGHT (ic), ic, FALSE);
3749   aopOp (IC_RESULT (ic), ic, TRUE);
3750
3751   /* if literal, literal on the right or
3752      if left requires ACC or right is already
3753      in ACC */
3754   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3755       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3756       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3757     {
3758       operand *t = IC_RIGHT (ic);
3759       IC_RIGHT (ic) = IC_LEFT (ic);
3760       IC_LEFT (ic) = t;
3761     }
3762
3763   /* if both left & right are in bit
3764      space */
3765   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3766       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3767     {
3768       genPlusBits (ic);
3769       goto release;
3770     }
3771
3772   /* if left in bit space & right literal */
3773   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3774       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3775     {
3776       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3777       /* if result in bit space */
3778       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3779         {
3780           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3781             emitcode ("cpl", "c");
3782           outBitC (IC_RESULT (ic));
3783         }
3784       else
3785         {
3786           size = getDataSize (IC_RESULT (ic));
3787           while (size--)
3788             {
3789               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
3790               emitcode ("addc", "a,#00");
3791               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3792             }
3793         }
3794       goto release;
3795     }
3796
3797   /* if I can do an increment instead
3798      of add then GOOD for ME */
3799   if (genPlusIncr (ic) == TRUE)
3800     goto release;
3801
3802   size = getDataSize (IC_RESULT (ic));
3803   leftOp = IC_LEFT(ic);
3804   rightOp = IC_RIGHT(ic);
3805   op=IC_LEFT(ic);
3806
3807   /* if this is an add for an array access
3808      at a 256 byte boundary */
3809   if ( 2 == size
3810        && AOP_TYPE (op) == AOP_IMMD
3811        && IS_SYMOP (op)
3812        && IS_SPEC (OP_SYM_ETYPE (op))
3813        && SPEC_ABSA (OP_SYM_ETYPE (op))
3814        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3815      )
3816     {
3817       D(emitcode (";     genPlus aligned array",""));
3818       aopPut (IC_RESULT (ic),
3819               aopGet (rightOp, 0, FALSE, FALSE),
3820               0,
3821               isOperandVolatile (IC_RESULT (ic), FALSE));
3822
3823       if( 1 == getDataSize (IC_RIGHT (ic)) )
3824         {
3825           aopPut (IC_RESULT (ic),
3826                   aopGet (leftOp, 1, FALSE, FALSE),
3827                   1,
3828                   isOperandVolatile (IC_RESULT (ic), FALSE));
3829         }
3830       else
3831         {
3832           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
3833           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3834           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3835         }
3836       goto release;
3837     }
3838
3839   /* if the lower bytes of a literal are zero skip the addition */
3840   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3841     {
3842        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3843               (skip_bytes+1 < size))
3844          {
3845            skip_bytes++;
3846          }
3847        if (skip_bytes)
3848          D(emitcode (";     genPlus shortcut",""));
3849     }
3850
3851   while (size--)
3852     {
3853       if( offset >= skip_bytes )
3854         {
3855           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3856             {
3857               bool pushedB;
3858               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3859               pushedB = pushB ();
3860               emitcode("xch", "a,b");
3861               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3862               emitcode (add, "a,b");
3863               popB (pushedB);
3864             }
3865           else if (aopGetUsesAcc (leftOp, offset))
3866             {
3867               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3868               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3869             }
3870           else
3871             {
3872               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3873               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3874             }
3875           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3876           add = "addc";  /* further adds must propagate carry */
3877         }
3878       else
3879         {
3880           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3881               isOperandVolatile (IC_RESULT (ic), FALSE))
3882             {
3883               /* just move */
3884               aopPut (IC_RESULT (ic),
3885                       aopGet (leftOp, offset, FALSE, FALSE),
3886                       offset,
3887                       isOperandVolatile (IC_RESULT (ic), FALSE));
3888             }
3889         }
3890       offset++;
3891     }
3892
3893   adjustArithmeticResult (ic);
3894
3895 release:
3896   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3897   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3898   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3899 }
3900
3901 /*-----------------------------------------------------------------*/
3902 /* genMinusDec :- does subtraction with deccrement if possible     */
3903 /*-----------------------------------------------------------------*/
3904 static bool
3905 genMinusDec (iCode * ic)
3906 {
3907   unsigned int icount;
3908   unsigned int size = getDataSize (IC_RESULT (ic));
3909
3910   /* will try to generate an increment */
3911   /* if the right side is not a literal
3912      we cannot */
3913   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3914     return FALSE;
3915
3916   /* if the literal value of the right hand side
3917      is greater than 4 then it is not worth it */
3918   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3919     return FALSE;
3920
3921   D(emitcode (";     genMinusDec",""));
3922
3923   /* if decrement >=16 bits in register or direct space */
3924   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3925       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3926       (size > 1) &&
3927       (icount == 1))
3928     {
3929       symbol *tlbl;
3930       int emitTlbl;
3931       int labelRange;
3932
3933       /* If the next instruction is a goto and the goto target
3934        * is <= 10 instructions previous to this, we can generate
3935        * jumps straight to that target.
3936        */
3937       if (ic->next && ic->next->op == GOTO
3938           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3939           && labelRange <= 10)
3940         {
3941           emitcode (";", "tail decrement optimized");
3942           tlbl = IC_LABEL (ic->next);
3943           emitTlbl = 0;
3944         }
3945       else
3946         {
3947           tlbl = newiTempLabel (NULL);
3948           emitTlbl = 1;
3949         }
3950
3951       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3952       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3953           IS_AOP_PREG (IC_RESULT (ic)))
3954         emitcode ("cjne", "%s,#0xff,%05d$"
3955                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
3956                   ,tlbl->key + 100);
3957       else
3958         {
3959           emitcode ("mov", "a,#0xff");
3960           emitcode ("cjne", "a,%s,%05d$"
3961                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
3962                     ,tlbl->key + 100);
3963         }
3964       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3965       if (size > 2)
3966         {
3967           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3968               IS_AOP_PREG (IC_RESULT (ic)))
3969             emitcode ("cjne", "%s,#0xff,%05d$"
3970                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
3971                       ,tlbl->key + 100);
3972           else
3973             {
3974               emitcode ("cjne", "a,%s,%05d$"
3975                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
3976                         ,tlbl->key + 100);
3977             }
3978           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3979         }
3980       if (size > 3)
3981         {
3982           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3983               IS_AOP_PREG (IC_RESULT (ic)))
3984             emitcode ("cjne", "%s,#0xff,%05d$"
3985                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
3986                       ,tlbl->key + 100);
3987           else
3988             {
3989               emitcode ("cjne", "a,%s,%05d$"
3990                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
3991                         ,tlbl->key + 100);
3992             }
3993           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3994         }
3995       if (emitTlbl)
3996         {
3997           emitcode ("", "%05d$:", tlbl->key + 100);
3998         }
3999       return TRUE;
4000     }
4001
4002   /* if the sizes are greater than 1 then we cannot */
4003   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4004       AOP_SIZE (IC_LEFT (ic)) > 1)
4005     return FALSE;
4006
4007   /* we can if the aops of the left & result match or
4008      if they are in registers and the registers are the
4009      same */
4010   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4011     {
4012
4013       while (icount--)
4014         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4015
4016       return TRUE;
4017     }
4018
4019   return FALSE;
4020 }
4021
4022 /*-----------------------------------------------------------------*/
4023 /* addSign - complete with sign                                    */
4024 /*-----------------------------------------------------------------*/
4025 static void
4026 addSign (operand * result, int offset, int sign)
4027 {
4028   int size = (getDataSize (result) - offset);
4029   if (size > 0)
4030     {
4031       if (sign)
4032         {
4033           emitcode ("rlc", "a");
4034           emitcode ("subb", "a,acc");
4035           while (size--)
4036             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4037         }
4038       else
4039         while (size--)
4040           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4041     }
4042 }
4043
4044 /*-----------------------------------------------------------------*/
4045 /* genMinusBits - generates code for subtraction  of two bits      */
4046 /*-----------------------------------------------------------------*/
4047 static void
4048 genMinusBits (iCode * ic)
4049 {
4050   symbol *lbl = newiTempLabel (NULL);
4051
4052   D(emitcode (";     genMinusBits",""));
4053
4054   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4055     {
4056       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4057       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4058       emitcode ("cpl", "c");
4059       emitcode ("", "%05d$:", (lbl->key + 100));
4060       outBitC (IC_RESULT (ic));
4061     }
4062   else
4063     {
4064       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4065       emitcode ("subb", "a,acc");
4066       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4067       emitcode ("inc", "a");
4068       emitcode ("", "%05d$:", (lbl->key + 100));
4069       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4070       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4071     }
4072 }
4073
4074 /*-----------------------------------------------------------------*/
4075 /* genMinus - generates code for subtraction                       */
4076 /*-----------------------------------------------------------------*/
4077 static void
4078 genMinus (iCode * ic)
4079 {
4080   int size, offset = 0;
4081
4082   D(emitcode (";     genMinus",""));
4083
4084   aopOp (IC_LEFT (ic), ic, FALSE);
4085   aopOp (IC_RIGHT (ic), ic, FALSE);
4086   aopOp (IC_RESULT (ic), ic, TRUE);
4087
4088   /* special cases :- */
4089   /* if both left & right are in bit space */
4090   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4091       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4092     {
4093       genMinusBits (ic);
4094       goto release;
4095     }
4096
4097   /* if I can do an decrement instead
4098      of subtract then GOOD for ME */
4099   if (genMinusDec (ic) == TRUE)
4100     goto release;
4101
4102   size = getDataSize (IC_RESULT (ic));
4103
4104   /* if literal, add a,#-lit, else normal subb */
4105   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4106     {
4107       unsigned long lit = 0L;
4108       bool useCarry = FALSE;
4109
4110       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4111       lit = -(long) lit;
4112
4113       while (size--)
4114         {
4115           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL)) {
4116             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4117             if (!offset && !size && lit== (unsigned long) -1) {
4118               emitcode ("dec", "a");
4119             } else if (!useCarry) {
4120           /* first add without previous c */
4121               emitcode ("add", "a,#0x%02x",
4122                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4123               useCarry = TRUE;
4124           } else {
4125             emitcode ("addc", "a,#0x%02x",
4126                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4127           }
4128             aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4129             } else {
4130               /* no need to add zeroes */
4131               offset++;
4132             }
4133         }
4134     }
4135   else
4136     {
4137       operand *leftOp, *rightOp;
4138
4139       leftOp = IC_LEFT(ic);
4140       rightOp = IC_RIGHT(ic);
4141
4142       while (size--)
4143         {
4144           if (aopGetUsesAcc(rightOp, offset)) {
4145             if (aopGetUsesAcc(leftOp, offset)) {
4146               bool pushedB;
4147
4148               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4149               pushedB = pushB ();
4150               emitcode ("mov", "b,a");
4151               if (offset == 0)
4152                 CLRC;
4153               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4154               emitcode ("subb", "a,b");
4155               popB (pushedB);
4156             } else {
4157               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4158               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4159               if (offset == 0) {
4160                 emitcode( "setb", "c");
4161               }
4162               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4163               emitcode("cpl", "a");
4164             }
4165           } else {
4166             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4167             if (offset == 0)
4168               CLRC;
4169             emitcode ("subb", "a,%s",
4170                       aopGet(rightOp, offset, FALSE, TRUE));
4171           }
4172
4173           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4174         }
4175     }
4176
4177
4178   adjustArithmeticResult (ic);
4179
4180 release:
4181   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4182   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4183   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4184 }
4185
4186
4187 /*-----------------------------------------------------------------*/
4188 /* genMultbits :- multiplication of bits                           */
4189 /*-----------------------------------------------------------------*/
4190 static void
4191 genMultbits (operand * left,
4192              operand * right,
4193              operand * result)
4194 {
4195   D(emitcode (";     genMultbits",""));
4196
4197   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4198   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4199   outBitC (result);
4200 }
4201
4202 /*-----------------------------------------------------------------*/
4203 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4204 /*-----------------------------------------------------------------*/
4205 static void
4206 genMultOneByte (operand * left,
4207                 operand * right,
4208                 operand * result)
4209 {
4210   symbol *lbl;
4211   int size = AOP_SIZE (result);
4212   bool runtimeSign, compiletimeSign;
4213   bool lUnsigned, rUnsigned, pushedB;
4214
4215   D(emitcode (";     genMultOneByte",""));
4216
4217   if (size < 1 || size > 2)
4218     {
4219       /* this should never happen */
4220       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4221                AOP_SIZE(result), __FILE__, lineno);
4222       exit (1);
4223     }
4224
4225   /* (if two literals: the value is computed before) */
4226   /* if one literal, literal on the right */
4227   if (AOP_TYPE (left) == AOP_LIT)
4228     {
4229       operand *t = right;
4230       right = left;
4231       left = t;
4232       /* emitcode (";", "swapped left and right"); */
4233     }
4234   /* if no literal, unsigned on the right: shorter code */
4235   if (   AOP_TYPE (right) != AOP_LIT
4236       && SPEC_USIGN (getSpec (operandType (left))))
4237     {
4238       operand *t = right;
4239       right = left;
4240       left = t;
4241     }
4242
4243   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4244   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4245
4246   pushedB = pushB ();
4247
4248   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4249                    no need to take care about the signedness! */
4250       || (lUnsigned && rUnsigned))
4251     {
4252       /* just an unsigned 8 * 8 = 8 multiply
4253          or 8u * 8u = 16u */
4254       /* emitcode (";","unsigned"); */
4255       /* TODO: check for accumulator clash between left & right aops? */
4256
4257       if (AOP_TYPE (right) == AOP_LIT)
4258         {
4259           /* moving to accumulator first helps peepholes */
4260           MOVA (aopGet (left, 0, FALSE, FALSE));
4261           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4262         }
4263       else
4264         {
4265           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4266           MOVA (aopGet (left, 0, FALSE, FALSE));
4267         }
4268
4269       emitcode ("mul", "ab");
4270       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4271       if (size == 2)
4272         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4273
4274       popB (pushedB);
4275       return;
4276     }
4277
4278   /* we have to do a signed multiply */
4279   /* emitcode (";", "signed"); */
4280
4281   /* now sign adjust for both left & right */
4282
4283   /* let's see what's needed: */
4284   /* apply negative sign during runtime */
4285   runtimeSign = FALSE;
4286   /* negative sign from literals */
4287   compiletimeSign = FALSE;
4288
4289   if (!lUnsigned)
4290     {
4291       if (AOP_TYPE(left) == AOP_LIT)
4292         {
4293           /* signed literal */
4294           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4295           if (val < 0)
4296             compiletimeSign = TRUE;
4297         }
4298       else
4299         /* signed but not literal */
4300         runtimeSign = TRUE;
4301     }
4302
4303   if (!rUnsigned)
4304     {
4305       if (AOP_TYPE(right) == AOP_LIT)
4306         {
4307           /* signed literal */
4308           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4309           if (val < 0)
4310             compiletimeSign ^= TRUE;
4311         }
4312       else
4313         /* signed but not literal */
4314         runtimeSign = TRUE;
4315     }
4316
4317   /* initialize F0, which stores the runtime sign */
4318   if (runtimeSign)
4319     {
4320       if (compiletimeSign)
4321         emitcode ("setb", "F0"); /* set sign flag */
4322       else
4323         emitcode ("clr", "F0"); /* reset sign flag */
4324     }
4325
4326   /* save the signs of the operands */
4327   if (AOP_TYPE(right) == AOP_LIT)
4328     {
4329       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4330
4331       if (!rUnsigned && val < 0)
4332         emitcode ("mov", "b,#0x%02x", -val);
4333       else
4334         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4335     }
4336   else /* ! literal */
4337     {
4338       if (rUnsigned)  /* emitcode (";", "signed"); */
4339
4340         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4341       else
4342         {
4343           MOVA (aopGet (right, 0, FALSE, FALSE));
4344           lbl = newiTempLabel (NULL);
4345           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4346           emitcode ("cpl", "F0"); /* complement sign flag */
4347           emitcode ("cpl", "a");  /* 2's complement */
4348           emitcode ("inc", "a");
4349           emitcode ("", "%05d$:", (lbl->key + 100));
4350           emitcode ("mov", "b,a");
4351         }
4352     }
4353
4354   if (AOP_TYPE(left) == AOP_LIT)
4355     {
4356       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4357
4358       if (!lUnsigned && val < 0)
4359         emitcode ("mov", "a,#0x%02x", -val);
4360       else
4361         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4362     }
4363   else /* ! literal */
4364     {
4365       MOVA (aopGet (left, 0, FALSE, FALSE));
4366
4367       if (!lUnsigned)
4368         {
4369           lbl = newiTempLabel (NULL);
4370           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4371           emitcode ("cpl", "F0"); /* complement sign flag */
4372           emitcode ("cpl", "a"); /* 2's complement */
4373           emitcode ("inc", "a");
4374           emitcode ("", "%05d$:", (lbl->key + 100));
4375         }
4376     }
4377
4378   /* now the multiplication */
4379   emitcode ("mul", "ab");
4380   if (runtimeSign || compiletimeSign)
4381     {
4382       lbl = newiTempLabel (NULL);
4383       if (runtimeSign)
4384         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4385       emitcode ("cpl", "a"); /* lsb 2's complement */
4386       if (size != 2)
4387         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4388       else
4389         {
4390           emitcode ("add", "a,#1"); /* this sets carry flag */
4391           emitcode ("xch", "a,b");
4392           emitcode ("cpl", "a"); /* msb 2's complement */
4393           emitcode ("addc", "a,#0");
4394           emitcode ("xch", "a,b");
4395         }
4396       emitcode ("", "%05d$:", (lbl->key + 100));
4397     }
4398   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4399   if (size == 2)
4400     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4401
4402   popB (pushedB);
4403 }
4404
4405 /*-----------------------------------------------------------------*/
4406 /* genMult - generates code for multiplication                     */
4407 /*-----------------------------------------------------------------*/
4408 static void
4409 genMult (iCode * ic)
4410 {
4411   operand *left = IC_LEFT (ic);
4412   operand *right = IC_RIGHT (ic);
4413   operand *result = IC_RESULT (ic);
4414
4415   D(emitcode (";     genMult",""));
4416
4417   /* assign the amsops */
4418   aopOp (left, ic, FALSE);
4419   aopOp (right, ic, FALSE);
4420   aopOp (result, ic, TRUE);
4421
4422   /* special cases first */
4423   /* both are bits */
4424   if (AOP_TYPE (left) == AOP_CRY &&
4425       AOP_TYPE (right) == AOP_CRY)
4426     {
4427       genMultbits (left, right, result);
4428       goto release;
4429     }
4430
4431   /* if both are of size == 1 */
4432 #if 0 // one of them can be a sloc shared with the result
4433     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4434 #else
4435   if (getSize(operandType(left)) == 1 &&
4436       getSize(operandType(right)) == 1)
4437 #endif
4438     {
4439       genMultOneByte (left, right, result);
4440       goto release;
4441     }
4442
4443   /* should have been converted to function call */
4444     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4445              getSize(OP_SYMBOL(right)->type));
4446   assert (0);
4447
4448 release:
4449   freeAsmop (result, NULL, ic, TRUE);
4450   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4451   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4452 }
4453
4454 /*-----------------------------------------------------------------*/
4455 /* genDivbits :- division of bits                                  */
4456 /*-----------------------------------------------------------------*/
4457 static void
4458 genDivbits (operand * left,
4459             operand * right,
4460             operand * result)
4461 {
4462   char *l;
4463   bool pushedB;
4464
4465   D(emitcode (";     genDivbits",""));
4466
4467   pushedB = pushB ();
4468
4469   /* the result must be bit */
4470   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4471   l = aopGet (left, 0, FALSE, FALSE);
4472
4473   MOVA (l);
4474
4475   emitcode ("div", "ab");
4476   emitcode ("rrc", "a");
4477
4478   popB (pushedB);
4479
4480   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4481 }
4482
4483 /*-----------------------------------------------------------------*/
4484 /* genDivOneByte : 8 bit division                                  */
4485 /*-----------------------------------------------------------------*/
4486 static void
4487 genDivOneByte (operand * left,
4488                operand * right,
4489                operand * result)
4490 {
4491   bool lUnsigned, rUnsigned, pushedB;
4492   bool runtimeSign, compiletimeSign;
4493   symbol *lbl;
4494   int size, offset;
4495
4496   D(emitcode (";     genDivOneByte",""));
4497
4498   /* Why is it necessary that genDivOneByte() can return an int result?
4499      Have a look at:
4500
4501         volatile unsigned char uc;
4502         volatile signed char sc1, sc2;
4503         volatile int i;
4504
4505         uc  = 255;
4506         sc1 = -1;
4507         i = uc / sc1;
4508
4509      Or:
4510
4511         sc1 = -128;
4512         sc2 = -1;
4513         i = sc1 / sc2;
4514
4515      In all cases a one byte result would overflow, the following cast to int
4516      would return the wrong result.
4517
4518      Two possible solution:
4519         a) cast operands to int, if ((unsigned) / (signed)) or
4520            ((signed) / (signed))
4521         b) return an 16 bit signed int; this is what we're doing here!
4522   */
4523
4524   size = AOP_SIZE (result) - 1;
4525   offset = 1;
4526   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4527   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4528
4529   pushedB = pushB ();
4530
4531   /* signed or unsigned */
4532   if (lUnsigned && rUnsigned)
4533     {
4534       /* unsigned is easy */
4535       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4536       MOVA (aopGet (left, 0, FALSE, FALSE));
4537       emitcode ("div", "ab");
4538       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4539       while (size--)
4540         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4541
4542       popB (pushedB);
4543       return;
4544     }
4545
4546   /* signed is a little bit more difficult */
4547
4548   /* now sign adjust for both left & right */
4549
4550   /* let's see what's needed: */
4551   /* apply negative sign during runtime */
4552   runtimeSign = FALSE;
4553   /* negative sign from literals */
4554   compiletimeSign = FALSE;
4555
4556   if (!lUnsigned)
4557     {
4558       if (AOP_TYPE(left) == AOP_LIT)
4559         {
4560           /* signed literal */
4561           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4562           if (val < 0)
4563             compiletimeSign = TRUE;
4564         }
4565       else
4566         /* signed but not literal */
4567         runtimeSign = TRUE;
4568     }
4569
4570   if (!rUnsigned)
4571     {
4572       if (AOP_TYPE(right) == AOP_LIT)
4573         {
4574           /* signed literal */
4575           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4576           if (val < 0)
4577             compiletimeSign ^= TRUE;
4578         }
4579       else
4580         /* signed but not literal */
4581         runtimeSign = TRUE;
4582     }
4583
4584   /* initialize F0, which stores the runtime sign */
4585   if (runtimeSign)
4586     {
4587       if (compiletimeSign)
4588         emitcode ("setb", "F0"); /* set sign flag */
4589       else
4590         emitcode ("clr", "F0"); /* reset sign flag */
4591     }
4592
4593   /* save the signs of the operands */
4594   if (AOP_TYPE(right) == AOP_LIT)
4595     {
4596       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4597
4598       if (!rUnsigned && val < 0)
4599         emitcode ("mov", "b,#0x%02x", -val);
4600       else
4601         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4602     }
4603   else /* ! literal */
4604     {
4605       if (rUnsigned)
4606         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4607       else
4608         {
4609           MOVA (aopGet (right, 0, FALSE, FALSE));
4610           lbl = newiTempLabel (NULL);
4611           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4612           emitcode ("cpl", "F0"); /* complement sign flag */
4613           emitcode ("cpl", "a");  /* 2's complement */
4614           emitcode ("inc", "a");
4615           emitcode ("", "%05d$:", (lbl->key + 100));
4616           emitcode ("mov", "b,a");
4617         }
4618     }
4619
4620   if (AOP_TYPE(left) == AOP_LIT)
4621     {
4622       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4623
4624       if (!lUnsigned && val < 0)
4625         emitcode ("mov", "a,#0x%02x", -val);
4626       else
4627         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4628     }
4629   else /* ! literal */
4630     {
4631       MOVA (aopGet (left, 0, FALSE, FALSE));
4632
4633       if (!lUnsigned)
4634         {
4635           lbl = newiTempLabel (NULL);
4636           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4637           emitcode ("cpl", "F0"); /* complement sign flag */
4638           emitcode ("cpl", "a");  /* 2's complement */
4639           emitcode ("inc", "a");
4640           emitcode ("", "%05d$:", (lbl->key + 100));
4641         }
4642     }
4643
4644   /* now the division */
4645   emitcode ("div", "ab");
4646
4647   if (runtimeSign || compiletimeSign)
4648     {
4649       lbl = newiTempLabel (NULL);
4650       if (runtimeSign)
4651         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4652       emitcode ("cpl", "a"); /* lsb 2's complement */
4653       emitcode ("inc", "a");
4654       emitcode ("", "%05d$:", (lbl->key + 100));
4655
4656       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4657       if (size > 0)
4658         {
4659           /* msb is 0x00 or 0xff depending on the sign */
4660           if (runtimeSign)
4661             {
4662               emitcode ("mov", "c,F0");
4663               emitcode ("subb", "a,acc");
4664               while (size--)
4665                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4666             }
4667           else /* compiletimeSign */
4668             while (size--)
4669               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4670         }
4671     }
4672   else
4673     {
4674       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4675       while (size--)
4676         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4677     }
4678
4679   popB (pushedB);
4680 }
4681
4682 /*-----------------------------------------------------------------*/
4683 /* genDiv - generates code for division                            */
4684 /*-----------------------------------------------------------------*/
4685 static void
4686 genDiv (iCode * ic)
4687 {
4688   operand *left = IC_LEFT (ic);
4689   operand *right = IC_RIGHT (ic);
4690   operand *result = IC_RESULT (ic);
4691
4692   D(emitcode (";     genDiv",""));
4693
4694   /* assign the amsops */
4695   aopOp (left, ic, FALSE);
4696   aopOp (right, ic, FALSE);
4697   aopOp (result, ic, TRUE);
4698
4699   /* special cases first */
4700   /* both are bits */
4701   if (AOP_TYPE (left) == AOP_CRY &&
4702       AOP_TYPE (right) == AOP_CRY)
4703     {
4704       genDivbits (left, right, result);
4705       goto release;
4706     }
4707
4708   /* if both are of size == 1 */
4709   if (AOP_SIZE (left) == 1 &&
4710       AOP_SIZE (right) == 1)
4711     {
4712       genDivOneByte (left, right, result);
4713       goto release;
4714     }
4715
4716   /* should have been converted to function call */
4717   assert (0);
4718 release:
4719   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4720   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4721   freeAsmop (result, NULL, ic, TRUE);
4722 }
4723
4724 /*-----------------------------------------------------------------*/
4725 /* genModbits :- modulus of bits                                   */
4726 /*-----------------------------------------------------------------*/
4727 static void
4728 genModbits (operand * left,
4729             operand * right,
4730             operand * result)
4731 {
4732   char *l;
4733   bool pushedB;
4734
4735   D(emitcode (";     genModbits",""));
4736
4737   pushedB = pushB ();
4738
4739   /* the result must be bit */
4740   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4741   l = aopGet (left, 0, FALSE, FALSE);
4742
4743   MOVA (l);
4744
4745   emitcode ("div", "ab");
4746   emitcode ("mov", "a,b");
4747   emitcode ("rrc", "a");
4748
4749   popB (pushedB);
4750
4751   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4752 }
4753
4754 /*-----------------------------------------------------------------*/
4755 /* genModOneByte : 8 bit modulus                                   */
4756 /*-----------------------------------------------------------------*/
4757 static void
4758 genModOneByte (operand * left,
4759                operand * right,
4760                operand * result)
4761 {
4762   bool lUnsigned, rUnsigned, pushedB;
4763   bool runtimeSign, compiletimeSign;
4764   symbol *lbl;
4765   int size, offset;
4766
4767   D(emitcode (";     genModOneByte",""));
4768
4769   size = AOP_SIZE (result) - 1;
4770   offset = 1;
4771   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4772   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4773
4774   /* if right is a literal, check it for 2^n */
4775   if (AOP_TYPE(right) == AOP_LIT)
4776     {
4777       unsigned char val = abs((int) operandLitValue(right));
4778       symbol *lbl2 = NULL;
4779
4780       switch (val)
4781         {
4782           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4783           case 2:
4784           case 4:
4785           case 8:
4786           case 16:
4787           case 32:
4788           case 64:
4789           case 128:
4790             if (lUnsigned)
4791               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4792                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4793               /* because iCode should have been changed to genAnd  */
4794               /* see file "SDCCopt.c", function "convertToFcall()" */
4795
4796             MOVA (aopGet (left, 0, FALSE, FALSE));
4797             emitcode ("mov", "c,acc.7");
4798             emitcode ("anl", "a,#0x%02x", val - 1);
4799             lbl = newiTempLabel (NULL);
4800             emitcode ("jz", "%05d$", (lbl->key + 100));
4801             emitcode ("jnc", "%05d$", (lbl->key + 100));
4802             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4803             if (size)
4804               {
4805                 int size2 = size;
4806                 int offs2 = offset;
4807
4808                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4809                 while (size2--)
4810                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
4811                 lbl2 = newiTempLabel (NULL);
4812                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4813               }
4814             emitcode ("", "%05d$:", (lbl->key + 100));
4815             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4816             while (size--)
4817               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4818             if (lbl2)
4819               {
4820                 emitcode ("", "%05d$:", (lbl2->key + 100));
4821               }
4822             return;
4823
4824           default:
4825             break;
4826         }
4827     }
4828
4829   pushedB = pushB ();
4830
4831   /* signed or unsigned */
4832   if (lUnsigned && rUnsigned)
4833     {
4834       /* unsigned is easy */
4835       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4836       MOVA (aopGet (left, 0, FALSE, FALSE));
4837       emitcode ("div", "ab");
4838       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4839       while (size--)
4840         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4841
4842       popB (pushedB);
4843       return;
4844     }
4845
4846   /* signed is a little bit more difficult */
4847
4848   /* now sign adjust for both left & right */
4849
4850   /* modulus: sign of the right operand has no influence on the result! */
4851   if (AOP_TYPE(right) == AOP_LIT)
4852     {
4853       signed char val = (char) operandLitValue(right);
4854
4855       if (!rUnsigned && val < 0)
4856         emitcode ("mov", "b,#0x%02x", -val);
4857       else
4858         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4859     }
4860   else /* not literal */
4861     {
4862       if (rUnsigned)
4863         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4864       else
4865         {
4866           MOVA (aopGet (right, 0, FALSE, FALSE));
4867           lbl = newiTempLabel (NULL);
4868           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4869           emitcode ("cpl", "a"); /* 2's complement */
4870           emitcode ("inc", "a");
4871           emitcode ("", "%05d$:", (lbl->key + 100));
4872           emitcode ("mov", "b,a");
4873         }
4874     }
4875
4876   /* let's see what's needed: */
4877   /* apply negative sign during runtime */
4878   runtimeSign = FALSE;
4879   /* negative sign from literals */
4880   compiletimeSign = FALSE;
4881
4882   /* sign adjust left side */
4883   if (AOP_TYPE(left) == AOP_LIT)
4884     {
4885       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4886
4887       if (!lUnsigned && val < 0)
4888         {
4889           compiletimeSign = TRUE; /* set sign flag */
4890           emitcode ("mov", "a,#0x%02x", -val);
4891         }
4892       else
4893         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4894     }
4895   else /* ! literal */
4896     {
4897       MOVA (aopGet (left, 0, FALSE, FALSE));
4898
4899       if (!lUnsigned)
4900         {
4901           runtimeSign = TRUE;
4902           emitcode ("clr", "F0"); /* clear sign flag */
4903
4904           lbl = newiTempLabel (NULL);
4905           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4906           emitcode ("setb", "F0"); /* set sign flag */
4907           emitcode ("cpl", "a");   /* 2's complement */
4908           emitcode ("inc", "a");
4909           emitcode ("", "%05d$:", (lbl->key + 100));
4910         }
4911     }
4912
4913   /* now the modulus */
4914   emitcode ("div", "ab");
4915
4916   if (runtimeSign || compiletimeSign)
4917     {
4918       emitcode ("mov", "a,b");
4919       lbl = newiTempLabel (NULL);
4920       if (runtimeSign)
4921         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4922       emitcode ("cpl", "a"); /* 2's complement */
4923       emitcode ("inc", "a");
4924       emitcode ("", "%05d$:", (lbl->key + 100));
4925
4926       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4927       if (size > 0)
4928         {
4929           /* msb is 0x00 or 0xff depending on the sign */
4930           if (runtimeSign)
4931             {
4932               emitcode ("mov", "c,F0");
4933               emitcode ("subb", "a,acc");
4934               while (size--)
4935                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4936             }
4937           else /* compiletimeSign */
4938             while (size--)
4939               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4940         }
4941     }
4942   else
4943     {
4944       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4945       while (size--)
4946         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4947     }
4948
4949   popB (pushedB);
4950 }
4951
4952 /*-----------------------------------------------------------------*/
4953 /* genMod - generates code for division                            */
4954 /*-----------------------------------------------------------------*/
4955 static void
4956 genMod (iCode * ic)
4957 {
4958   operand *left = IC_LEFT (ic);
4959   operand *right = IC_RIGHT (ic);
4960   operand *result = IC_RESULT (ic);
4961
4962   D(emitcode (";     genMod",""));
4963
4964   /* assign the asmops */
4965   aopOp (left, ic, FALSE);
4966   aopOp (right, ic, FALSE);
4967   aopOp (result, ic, TRUE);
4968
4969   /* special cases first */
4970   /* both are bits */
4971   if (AOP_TYPE (left) == AOP_CRY &&
4972       AOP_TYPE (right) == AOP_CRY)
4973     {
4974       genModbits (left, right, result);
4975       goto release;
4976     }
4977
4978   /* if both are of size == 1 */
4979   if (AOP_SIZE (left) == 1 &&
4980       AOP_SIZE (right) == 1)
4981     {
4982       genModOneByte (left, right, result);
4983       goto release;
4984     }
4985
4986   /* should have been converted to function call */
4987   assert (0);
4988
4989 release:
4990   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4991   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4992   freeAsmop (result, NULL, ic, TRUE);
4993 }
4994
4995 /*-----------------------------------------------------------------*/
4996 /* genIfxJump :- will create a jump depending on the ifx           */
4997 /*-----------------------------------------------------------------*/
4998 static void
4999 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5000 {
5001   symbol *jlbl;
5002   symbol *tlbl = newiTempLabel (NULL);
5003   char *inst;
5004
5005   D(emitcode (";     genIfxJump",""));
5006
5007   /* if true label then we jump if condition
5008      supplied is true */
5009   if (IC_TRUE (ic))
5010     {
5011       jlbl = IC_TRUE (ic);
5012       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5013                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5014     }
5015   else
5016     {
5017       /* false label is present */
5018       jlbl = IC_FALSE (ic);
5019       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5020                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5021     }
5022   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5023     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5024   else
5025     emitcode (inst, "%05d$", tlbl->key + 100);
5026   freeForBranchAsmop (result);
5027   freeForBranchAsmop (right);
5028   freeForBranchAsmop (left);
5029   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5030   emitcode ("", "%05d$:", tlbl->key + 100);
5031
5032   /* mark the icode as generated */
5033   ic->generated = 1;
5034 }
5035
5036 /*-----------------------------------------------------------------*/
5037 /* genCmp :- greater or less than comparison                       */
5038 /*-----------------------------------------------------------------*/
5039 static void
5040 genCmp (operand * left, operand * right,
5041         operand * result, iCode * ifx, int sign, iCode *ic)
5042 {
5043   int size, offset = 0;
5044   unsigned long lit = 0L;
5045   bool rightInB;
5046
5047   D(emitcode (";     genCmp",""));
5048
5049   /* if left & right are bit variables */
5050   if (AOP_TYPE (left) == AOP_CRY &&
5051       AOP_TYPE (right) == AOP_CRY)
5052     {
5053       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5054       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5055     }
5056   else
5057     {
5058       /* subtract right from left if at the
5059          end the carry flag is set then we know that
5060          left is greater than right */
5061       size = max (AOP_SIZE (left), AOP_SIZE (right));
5062
5063       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5064       if ((size == 1) && !sign &&
5065           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5066         {
5067           symbol *lbl = newiTempLabel (NULL);
5068           emitcode ("cjne", "%s,%s,%05d$",
5069                     aopGet (left, offset, FALSE, FALSE),
5070                     aopGet (right, offset, FALSE, FALSE),
5071                     lbl->key + 100);
5072           emitcode ("", "%05d$:", lbl->key + 100);
5073         }
5074       else
5075         {
5076           if (AOP_TYPE (right) == AOP_LIT)
5077             {
5078               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5079               /* optimize if(x < 0) or if(x >= 0) */
5080               if (lit == 0L)
5081                 {
5082                   if (!sign)
5083                     {
5084                       CLRC;
5085                     }
5086                   else
5087                     {
5088                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5089                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5090                         {
5091                           genIfxJump (ifx, "acc.7", left, right, result);
5092                           freeAsmop (right, NULL, ic, TRUE);
5093                           freeAsmop (left, NULL, ic, TRUE);
5094
5095                           return;
5096                         }
5097                       else
5098                         emitcode ("rlc", "a");
5099                     }
5100                   goto release;
5101                 }
5102             }
5103           CLRC;
5104           while (size--)
5105             {
5106               bool pushedB = FALSE;
5107               rightInB = aopGetUsesAcc(right, offset);
5108               if (rightInB)
5109                 {
5110                   pushedB = pushB ();
5111                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5112                 }
5113               MOVA (aopGet (left, offset, FALSE, FALSE));
5114               if (sign && size == 0)
5115                 {
5116                   emitcode ("xrl", "a,#0x80");
5117                   if (AOP_TYPE (right) == AOP_LIT)
5118                     {
5119                       unsigned long lit = (unsigned long)
5120                       floatFromVal (AOP (right)->aopu.aop_lit);
5121                       emitcode ("subb", "a,#0x%02x",
5122                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5123                     }
5124                   else
5125                     {
5126                       if (!rightInB)
5127                         {
5128                           pushedB = pushB ();
5129                           rightInB++;
5130                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5131                         }
5132                       emitcode ("xrl", "b,#0x80");
5133                       emitcode ("subb", "a,b");
5134                     }
5135                 }
5136               else
5137                 {
5138                   if (rightInB)
5139                     emitcode ("subb", "a,b");
5140                   else
5141                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5142                 }
5143               if (rightInB)
5144                 popB (pushedB);
5145               offset++;
5146             }
5147         }
5148     }
5149
5150 release:
5151   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5152   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5153   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5154     {
5155       outBitC (result);
5156     }
5157   else
5158     {
5159       /* if the result is used in the next
5160          ifx conditional branch then generate
5161          code a little differently */
5162       if (ifx)
5163         genIfxJump (ifx, "c", NULL, NULL, result);
5164       else
5165         outBitC (result);
5166       /* leave the result in acc */
5167     }
5168 }
5169
5170 /*-----------------------------------------------------------------*/
5171 /* genCmpGt :- greater than comparison                             */
5172 /*-----------------------------------------------------------------*/
5173 static void
5174 genCmpGt (iCode * ic, iCode * ifx)
5175 {
5176   operand *left, *right, *result;
5177   sym_link *letype, *retype;
5178   int sign;
5179
5180   D(emitcode (";     genCmpGt",""));
5181
5182   left = IC_LEFT (ic);
5183   right = IC_RIGHT (ic);
5184   result = IC_RESULT (ic);
5185
5186   letype = getSpec (operandType (left));
5187   retype = getSpec (operandType (right));
5188   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5189            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5190   /* assign the amsops */
5191   aopOp (left, ic, FALSE);
5192   aopOp (right, ic, FALSE);
5193   aopOp (result, ic, TRUE);
5194
5195   genCmp (right, left, result, ifx, sign, ic);
5196
5197   freeAsmop (result, NULL, ic, TRUE);
5198 }
5199
5200 /*-----------------------------------------------------------------*/
5201 /* genCmpLt - less than comparisons                                */
5202 /*-----------------------------------------------------------------*/
5203 static void
5204 genCmpLt (iCode * ic, iCode * ifx)
5205 {
5206   operand *left, *right, *result;
5207   sym_link *letype, *retype;
5208   int sign;
5209
5210   D(emitcode (";     genCmpLt",""));
5211
5212   left = IC_LEFT (ic);
5213   right = IC_RIGHT (ic);
5214   result = IC_RESULT (ic);
5215
5216   letype = getSpec (operandType (left));
5217   retype = getSpec (operandType (right));
5218   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5219            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5220   /* assign the amsops */
5221   aopOp (left, ic, FALSE);
5222   aopOp (right, ic, FALSE);
5223   aopOp (result, ic, TRUE);
5224
5225   genCmp (left, right, result, ifx, sign,ic);
5226
5227   freeAsmop (result, NULL, ic, TRUE);
5228 }
5229
5230 /*-----------------------------------------------------------------*/
5231 /* gencjneshort - compare and jump if not equal                    */
5232 /*-----------------------------------------------------------------*/
5233 static void
5234 gencjneshort (operand * left, operand * right, symbol * lbl)
5235 {
5236   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5237   int offset = 0;
5238   unsigned long lit = 0L;
5239
5240   /* if the left side is a literal or
5241      if the right is in a pointer register and left
5242      is not */
5243   if ((AOP_TYPE (left) == AOP_LIT) ||
5244       (AOP_TYPE (left) == AOP_IMMD) ||
5245       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5246     {
5247       operand *t = right;
5248       right = left;
5249       left = t;
5250     }
5251
5252   if (AOP_TYPE (right) == AOP_LIT)
5253     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5254
5255   /* if the right side is a literal then anything goes */
5256   if (AOP_TYPE (right) == AOP_LIT &&
5257       AOP_TYPE (left) != AOP_DIR  &&
5258       AOP_TYPE (left) != AOP_IMMD)
5259     {
5260       while (size--)
5261         {
5262           emitcode ("cjne", "%s,%s,%05d$",
5263                     aopGet (left, offset, FALSE, FALSE),
5264                     aopGet (right, offset, FALSE, FALSE),
5265                     lbl->key + 100);
5266           offset++;
5267         }
5268     }
5269
5270   /* if the right side is in a register or in direct space or
5271      if the left is a pointer register & right is not */
5272   else if (AOP_TYPE (right) == AOP_REG ||
5273            AOP_TYPE (right) == AOP_DIR ||
5274            AOP_TYPE (right) == AOP_LIT ||
5275            AOP_TYPE (right) == AOP_IMMD ||
5276            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5277            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5278     {
5279       while (size--)
5280         {
5281           MOVA (aopGet (left, offset, FALSE, FALSE));
5282           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5283               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5284             emitcode ("jnz", "%05d$", lbl->key + 100);
5285           else
5286             emitcode ("cjne", "a,%s,%05d$",
5287                       aopGet (right, offset, FALSE, TRUE),
5288                       lbl->key + 100);
5289           offset++;
5290         }
5291     }
5292   else
5293     {
5294       /* right is a pointer reg need both a & b */
5295       while (size--)
5296         {
5297           char *l;
5298           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5299           wassertl(!BINUSE, "B was in use");
5300           l = aopGet (left, offset, FALSE, FALSE);
5301           if (strcmp (l, "b"))
5302             emitcode ("mov", "b,%s", l);
5303           MOVA (aopGet (right, offset, FALSE, FALSE));
5304           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5305           offset++;
5306         }
5307     }
5308 }
5309
5310 /*-----------------------------------------------------------------*/
5311 /* gencjne - compare and jump if not equal                         */
5312 /*-----------------------------------------------------------------*/
5313 static void
5314 gencjne (operand * left, operand * right, symbol * lbl)
5315 {
5316   symbol *tlbl = newiTempLabel (NULL);
5317
5318   gencjneshort (left, right, lbl);
5319
5320   emitcode ("mov", "a,%s", one);
5321   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5322   emitcode ("", "%05d$:", lbl->key + 100);
5323   emitcode ("clr", "a");
5324   emitcode ("", "%05d$:", tlbl->key + 100);
5325 }
5326
5327 /*-----------------------------------------------------------------*/
5328 /* genCmpEq - generates code for equal to                          */
5329 /*-----------------------------------------------------------------*/
5330 static void
5331 genCmpEq (iCode * ic, iCode * ifx)
5332 {
5333   operand *left, *right, *result;
5334
5335   D(emitcode (";     genCmpEq",""));
5336
5337   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5338   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5339   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5340
5341   /* if literal, literal on the right or
5342      if the right is in a pointer register and left
5343      is not */
5344   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5345       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5346     {
5347       operand *t = IC_RIGHT (ic);
5348       IC_RIGHT (ic) = IC_LEFT (ic);
5349       IC_LEFT (ic) = t;
5350     }
5351
5352   if (ifx && !AOP_SIZE (result))
5353     {
5354       symbol *tlbl;
5355       /* if they are both bit variables */
5356       if (AOP_TYPE (left) == AOP_CRY &&
5357           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5358         {
5359           if (AOP_TYPE (right) == AOP_LIT)
5360             {
5361               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5362               if (lit == 0L)
5363                 {
5364                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5365                   emitcode ("cpl", "c");
5366                 }
5367               else if (lit == 1L)
5368                 {
5369                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5370                 }
5371               else
5372                 {
5373                   emitcode ("clr", "c");
5374                 }
5375               /* AOP_TYPE(right) == AOP_CRY */
5376             }
5377           else
5378             {
5379               symbol *lbl = newiTempLabel (NULL);
5380               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5381               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5382               emitcode ("cpl", "c");
5383               emitcode ("", "%05d$:", (lbl->key + 100));
5384             }
5385           /* if true label then we jump if condition
5386              supplied is true */
5387           tlbl = newiTempLabel (NULL);
5388           if (IC_TRUE (ifx))
5389             {
5390               emitcode ("jnc", "%05d$", tlbl->key + 100);
5391               freeForBranchAsmop (result);
5392               freeForBranchAsmop (right);
5393               freeForBranchAsmop (left);
5394               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5395             }
5396           else
5397             {
5398               emitcode ("jc", "%05d$", tlbl->key + 100);
5399               freeForBranchAsmop (result);
5400               freeForBranchAsmop (right);
5401               freeForBranchAsmop (left);
5402               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5403             }
5404           emitcode ("", "%05d$:", tlbl->key + 100);
5405         }
5406       else
5407         {
5408           tlbl = newiTempLabel (NULL);
5409           gencjneshort (left, right, tlbl);
5410           if (IC_TRUE (ifx))
5411             {
5412               freeForBranchAsmop (result);
5413               freeForBranchAsmop (right);
5414               freeForBranchAsmop (left);
5415               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5416               emitcode ("", "%05d$:", tlbl->key + 100);
5417             }
5418           else
5419             {
5420               symbol *lbl = newiTempLabel (NULL);
5421               emitcode ("sjmp", "%05d$", lbl->key + 100);
5422               emitcode ("", "%05d$:", tlbl->key + 100);
5423               freeForBranchAsmop (result);
5424               freeForBranchAsmop (right);
5425               freeForBranchAsmop (left);
5426               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5427               emitcode ("", "%05d$:", lbl->key + 100);
5428             }
5429         }
5430       /* mark the icode as generated */
5431       ifx->generated = 1;
5432       goto release;
5433     }
5434
5435   /* if they are both bit variables */
5436   if (AOP_TYPE (left) == AOP_CRY &&
5437       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5438     {
5439       if (AOP_TYPE (right) == AOP_LIT)
5440         {
5441           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5442           if (lit == 0L)
5443             {
5444               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5445               emitcode ("cpl", "c");
5446             }
5447           else if (lit == 1L)
5448             {
5449               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5450             }
5451           else
5452             {
5453               emitcode ("clr", "c");
5454             }
5455           /* AOP_TYPE(right) == AOP_CRY */
5456         }
5457       else
5458         {
5459           symbol *lbl = newiTempLabel (NULL);
5460           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5461           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5462           emitcode ("cpl", "c");
5463           emitcode ("", "%05d$:", (lbl->key + 100));
5464         }
5465       /* c = 1 if egal */
5466       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5467         {
5468           outBitC (result);
5469           goto release;
5470         }
5471       if (ifx)
5472         {
5473           genIfxJump (ifx, "c", left, right, result);
5474           goto release;
5475         }
5476       /* if the result is used in an arithmetic operation
5477          then put the result in place */
5478       outBitC (result);
5479     }
5480   else
5481     {
5482       gencjne (left, right, newiTempLabel (NULL));
5483       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5484         {
5485           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5486           goto release;
5487         }
5488       if (ifx)
5489         {
5490           genIfxJump (ifx, "a", left, right, result);
5491           goto release;
5492         }
5493       /* if the result is used in an arithmetic operation
5494          then put the result in place */
5495       if (AOP_TYPE (result) != AOP_CRY)
5496         outAcc (result);
5497       /* leave the result in acc */
5498     }
5499
5500 release:
5501   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5502   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5503   freeAsmop (result, NULL, ic, TRUE);
5504 }
5505
5506 /*-----------------------------------------------------------------*/
5507 /* ifxForOp - returns the icode containing the ifx for operand     */
5508 /*-----------------------------------------------------------------*/
5509 static iCode *
5510 ifxForOp (operand * op, iCode * ic)
5511 {
5512   /* if true symbol then needs to be assigned */
5513   if (IS_TRUE_SYMOP (op))
5514     return NULL;
5515
5516   /* if this has register type condition and
5517      the next instruction is ifx with the same operand
5518      and live to of the operand is upto the ifx only then */
5519   if (ic->next &&
5520       ic->next->op == IFX &&
5521       IC_COND (ic->next)->key == op->key &&
5522       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5523     return ic->next;
5524
5525   return NULL;
5526 }
5527
5528 /*-----------------------------------------------------------------*/
5529 /* hasInc - operand is incremented before any other use            */
5530 /*-----------------------------------------------------------------*/
5531 static iCode *
5532 hasInc (operand *op, iCode *ic,int osize)
5533 {
5534   sym_link *type = operandType(op);
5535   sym_link *retype = getSpec (type);
5536   iCode *lic = ic->next;
5537   int isize ;
5538
5539   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5540   if (!IS_SYMOP(op)) return NULL;
5541
5542   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5543   if (IS_AGGREGATE(type->next)) return NULL;
5544   if (osize != (isize = getSize(type->next))) return NULL;
5545
5546   while (lic) {
5547     /* if operand of the form op = op + <sizeof *op> */
5548     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5549         isOperandEqual(IC_RESULT(lic),op) &&
5550         isOperandLiteral(IC_RIGHT(lic)) &&
5551         operandLitValue(IC_RIGHT(lic)) == isize) {
5552       return lic;
5553     }
5554     /* if the operand used or deffed */
5555     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5556       return NULL;
5557     }
5558     /* if GOTO or IFX */
5559     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5560     lic = lic->next;
5561   }
5562   return NULL;
5563 }
5564
5565 /*-----------------------------------------------------------------*/
5566 /* genAndOp - for && operation                                     */
5567 /*-----------------------------------------------------------------*/
5568 static void
5569 genAndOp (iCode * ic)
5570 {
5571   operand *left, *right, *result;
5572   symbol *tlbl;
5573
5574   D(emitcode (";     genAndOp",""));
5575
5576   /* note here that && operations that are in an
5577      if statement are taken away by backPatchLabels
5578      only those used in arthmetic operations remain */
5579   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5580   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5581   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5582
5583   /* if both are bit variables */
5584   if (AOP_TYPE (left) == AOP_CRY &&
5585       AOP_TYPE (right) == AOP_CRY)
5586     {
5587       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5588       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5589       outBitC (result);
5590     }
5591   else
5592     {
5593       tlbl = newiTempLabel (NULL);
5594       toBoolean (left);
5595       emitcode ("jz", "%05d$", tlbl->key + 100);
5596       toBoolean (right);
5597       emitcode ("", "%05d$:", tlbl->key + 100);
5598       outBitAcc (result);
5599     }
5600
5601   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5602   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5603   freeAsmop (result, NULL, ic, TRUE);
5604 }
5605
5606
5607 /*-----------------------------------------------------------------*/
5608 /* genOrOp - for || operation                                      */
5609 /*-----------------------------------------------------------------*/
5610 static void
5611 genOrOp (iCode * ic)
5612 {
5613   operand *left, *right, *result;
5614   symbol *tlbl;
5615
5616   D(emitcode (";     genOrOp",""));
5617
5618   /* note here that || operations that are in an
5619      if statement are taken away by backPatchLabels
5620      only those used in arthmetic operations remain */
5621   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5622   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5623   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5624
5625   /* if both are bit variables */
5626   if (AOP_TYPE (left) == AOP_CRY &&
5627       AOP_TYPE (right) == AOP_CRY)
5628     {
5629       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5630       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5631       outBitC (result);
5632     }
5633   else
5634     {
5635       tlbl = newiTempLabel (NULL);
5636       toBoolean (left);
5637       emitcode ("jnz", "%05d$", tlbl->key + 100);
5638       toBoolean (right);
5639       emitcode ("", "%05d$:", tlbl->key + 100);
5640       outBitAcc (result);
5641     }
5642
5643   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5644   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5645   freeAsmop (result, NULL, ic, TRUE);
5646 }
5647
5648 /*-----------------------------------------------------------------*/
5649 /* isLiteralBit - test if lit == 2^n                               */
5650 /*-----------------------------------------------------------------*/
5651 static int
5652 isLiteralBit (unsigned long lit)
5653 {
5654   unsigned long pw[32] =
5655   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5656    0x100L, 0x200L, 0x400L, 0x800L,
5657    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5658    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5659    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5660    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5661    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5662   int idx;
5663
5664   for (idx = 0; idx < 32; idx++)
5665     if (lit == pw[idx])
5666       return idx + 1;
5667   return 0;
5668 }
5669
5670 /*-----------------------------------------------------------------*/
5671 /* continueIfTrue -                                                */
5672 /*-----------------------------------------------------------------*/
5673 static void
5674 continueIfTrue (iCode * ic)
5675 {
5676   if (IC_TRUE (ic))
5677     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5678   ic->generated = 1;
5679 }
5680
5681 /*-----------------------------------------------------------------*/
5682 /* jmpIfTrue -                                                     */
5683 /*-----------------------------------------------------------------*/
5684 static void
5685 jumpIfTrue (iCode * ic)
5686 {
5687   if (!IC_TRUE (ic))
5688     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5689   ic->generated = 1;
5690 }
5691
5692 /*-----------------------------------------------------------------*/
5693 /* jmpTrueOrFalse -                                                */
5694 /*-----------------------------------------------------------------*/
5695 static void
5696 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5697 {
5698   // ugly but optimized by peephole
5699   if (IC_TRUE (ic))
5700     {
5701       symbol *nlbl = newiTempLabel (NULL);
5702       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5703       emitcode ("", "%05d$:", tlbl->key + 100);
5704       freeForBranchAsmop (result);
5705       freeForBranchAsmop (right);
5706       freeForBranchAsmop (left);
5707       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5708       emitcode ("", "%05d$:", nlbl->key + 100);
5709     }
5710   else
5711     {
5712       freeForBranchAsmop (result);
5713       freeForBranchAsmop (right);
5714       freeForBranchAsmop (left);
5715       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5716       emitcode ("", "%05d$:", tlbl->key + 100);
5717     }
5718   ic->generated = 1;
5719 }
5720
5721 /*-----------------------------------------------------------------*/
5722 /* genAnd  - code for and                                          */
5723 /*-----------------------------------------------------------------*/
5724 static void
5725 genAnd (iCode * ic, iCode * ifx)
5726 {
5727   operand *left, *right, *result;
5728   int size, offset = 0;
5729   unsigned long lit = 0L;
5730   int bytelit = 0;
5731   char buffer[10];
5732
5733   D(emitcode (";     genAnd",""));
5734
5735   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5736   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5737   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5738
5739 #ifdef DEBUG_TYPE
5740   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5741             AOP_TYPE (result),
5742             AOP_TYPE (left), AOP_TYPE (right));
5743   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5744             AOP_SIZE (result),
5745             AOP_SIZE (left), AOP_SIZE (right));
5746 #endif
5747
5748   /* if left is a literal & right is not then exchange them */
5749   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5750       AOP_NEEDSACC (left))
5751     {
5752       operand *tmp = right;
5753       right = left;
5754       left = tmp;
5755     }
5756
5757   /* if result = right then exchange left and right */
5758   if (sameRegs (AOP (result), AOP (right)))
5759     {
5760       operand *tmp = right;
5761       right = left;
5762       left = tmp;
5763     }
5764
5765   /* if right is bit then exchange them */
5766   if (AOP_TYPE (right) == AOP_CRY &&
5767       AOP_TYPE (left) != AOP_CRY)
5768     {
5769       operand *tmp = right;
5770       right = left;
5771       left = tmp;
5772     }
5773   if (AOP_TYPE (right) == AOP_LIT)
5774     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5775
5776   size = AOP_SIZE (result);
5777
5778   // if(bit & yy)
5779   // result = bit & yy;
5780   if (AOP_TYPE (left) == AOP_CRY)
5781     {
5782       // c = bit & literal;
5783       if (AOP_TYPE (right) == AOP_LIT)
5784         {
5785           if (lit & 1)
5786             {
5787               if (size && sameRegs (AOP (result), AOP (left)))
5788                 // no change
5789                 goto release;
5790               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5791             }
5792           else
5793             {
5794               // bit(result) = 0;
5795               if (size && (AOP_TYPE (result) == AOP_CRY))
5796                 {
5797                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5798                   goto release;
5799                 }
5800               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5801                 {
5802                   jumpIfTrue (ifx);
5803                   goto release;
5804                 }
5805               emitcode ("clr", "c");
5806             }
5807         }
5808       else
5809         {
5810           if (AOP_TYPE (right) == AOP_CRY)
5811             {
5812               // c = bit & bit;
5813               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5814               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5815             }
5816           else
5817             {
5818               // c = bit & val;
5819               MOVA (aopGet (right, 0, FALSE, FALSE));
5820               // c = lsb
5821               emitcode ("rrc", "a");
5822               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5823             }
5824         }
5825       // bit = c
5826       // val = c
5827       if (size)
5828         outBitC (result);
5829       // if(bit & ...)
5830       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5831         genIfxJump (ifx, "c", left, right, result);
5832       goto release;
5833     }
5834
5835   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5836   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5837   if ((AOP_TYPE (right) == AOP_LIT) &&
5838       (AOP_TYPE (result) == AOP_CRY) &&
5839       (AOP_TYPE (left) != AOP_CRY))
5840     {
5841       int posbit = isLiteralBit (lit);
5842       /* left &  2^n */
5843       if (posbit)
5844         {
5845           posbit--;
5846           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
5847           // bit = left & 2^n
5848           if (size)
5849             {
5850               switch (posbit & 0x07)
5851                 {
5852                   case 0: emitcode ("rrc", "a");
5853                           break;
5854                   case 7: emitcode ("rlc", "a");
5855                           break;
5856                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5857                           break;
5858                 }
5859             }
5860           // if(left &  2^n)
5861           else
5862             {
5863               if (ifx)
5864                 {
5865                   SNPRINTF (buffer, sizeof(buffer),
5866                             "acc.%d", posbit & 0x07);
5867                   genIfxJump (ifx, buffer, left, right, result);
5868                 }
5869               else
5870                 {// what is this case? just found it in ds390/gen.c
5871                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5872                 }
5873               goto release;
5874             }
5875         }
5876       else
5877         {
5878           symbol *tlbl = newiTempLabel (NULL);
5879           int sizel = AOP_SIZE (left);
5880           if (size)
5881             emitcode ("setb", "c");
5882           while (sizel--)
5883             {
5884               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5885                 {
5886                   MOVA (aopGet (left, offset, FALSE, FALSE));
5887                   // byte ==  2^n ?
5888                   if ((posbit = isLiteralBit (bytelit)) != 0)
5889                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5890                   else
5891                     {
5892                       if (bytelit != 0x0FFL)
5893                         emitcode ("anl", "a,%s",
5894                                   aopGet (right, offset, FALSE, TRUE));
5895                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5896                     }
5897                 }
5898               offset++;
5899             }
5900           // bit = left & literal
5901           if (size)
5902             {
5903               emitcode ("clr", "c");
5904               emitcode ("", "%05d$:", tlbl->key + 100);
5905             }
5906           // if(left & literal)
5907           else
5908             {
5909               if (ifx)
5910                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5911               else
5912                 emitcode ("", "%05d$:", tlbl->key + 100);
5913               goto release;
5914             }
5915         }
5916       outBitC (result);
5917       goto release;
5918     }
5919
5920   /* if left is same as result */
5921   if (sameRegs (AOP (result), AOP (left)))
5922     {
5923       for (; size--; offset++)
5924         {
5925           if (AOP_TYPE (right) == AOP_LIT)
5926             {
5927               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5928               if (bytelit == 0x0FF)
5929                 {
5930                   /* dummy read of volatile operand */
5931                   if (isOperandVolatile (left, FALSE))
5932                     MOVA (aopGet (left, offset, FALSE, FALSE));
5933                   else
5934                     continue;
5935                 }
5936               else if (bytelit == 0)
5937                 {
5938                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
5939                 }
5940               else if (IS_AOP_PREG (result))
5941                 {
5942                   MOVA (aopGet (left, offset, FALSE, TRUE));
5943                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
5944                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
5945                 }
5946               else
5947                 emitcode ("anl", "%s,%s",
5948                           aopGet (left, offset, FALSE, TRUE),
5949                           aopGet (right, offset, FALSE, FALSE));
5950             }
5951           else
5952             {
5953               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
5954                 {
5955                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
5956                 }
5957               else
5958                 {
5959                   MOVA (aopGet (right, offset, FALSE, FALSE));
5960                   if (IS_AOP_PREG (result))
5961                     {
5962                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
5963                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
5964                     }
5965                   else
5966                     emitcode ("anl", "%s,a",
5967                               aopGet (left, offset, FALSE, TRUE));
5968                 }
5969             }
5970         }
5971     }
5972   else
5973     {
5974       // left & result in different registers
5975       if (AOP_TYPE (result) == AOP_CRY)
5976         {
5977           // result = bit
5978           // if(size), result in bit
5979           // if(!size && ifx), conditional oper: if(left & right)
5980           symbol *tlbl = newiTempLabel (NULL);
5981           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5982           if (size)
5983             emitcode ("setb", "c");
5984           while (sizer--)
5985             {
5986               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
5987                   && AOP_TYPE(left)==AOP_ACC)
5988                 {
5989                   if (offset)
5990                     emitcode("mov", "a,b");
5991                   emitcode ("anl", "a,%s",
5992                             aopGet (right, offset, FALSE, FALSE));
5993                 } else {
5994                   if (AOP_TYPE(left)==AOP_ACC)
5995                     {
5996                       if (!offset)
5997                         {
5998                           bool pushedB = pushB ();
5999                           emitcode("mov", "b,a");
6000                           MOVA (aopGet (right, offset, FALSE, FALSE));
6001                           emitcode("anl", "a,b");
6002                           popB (pushedB);
6003                         }
6004                       else
6005                         {
6006                           MOVA (aopGet (right, offset, FALSE, FALSE));
6007                           emitcode("anl", "a,b");
6008                         }
6009                 } else {
6010                       MOVA (aopGet (right, offset, FALSE, FALSE));
6011                   emitcode ("anl", "a,%s",
6012                                 aopGet (left, offset, FALSE, FALSE));
6013                 }
6014               }
6015               emitcode ("jnz", "%05d$", tlbl->key + 100);
6016               offset++;
6017             }
6018           if (size)
6019             {
6020               CLRC;
6021               emitcode ("", "%05d$:", tlbl->key + 100);
6022               outBitC (result);
6023             }
6024           else if (ifx)
6025             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6026           else
6027             emitcode ("", "%05d$:", tlbl->key + 100);
6028         }
6029       else
6030         {
6031           for (; (size--); offset++)
6032             {
6033               // normal case
6034               // result = left & right
6035               if (AOP_TYPE (right) == AOP_LIT)
6036                 {
6037                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6038                   if (bytelit == 0x0FF)
6039                     {
6040                       aopPut (result,
6041                               aopGet (left, offset, FALSE, FALSE),
6042                               offset,
6043                               isOperandVolatile (result, FALSE));
6044                       continue;
6045                     }
6046                   else if (bytelit == 0)
6047                     {
6048                       /* dummy read of volatile operand */
6049                       if (isOperandVolatile (left, FALSE))
6050                         MOVA (aopGet (left, offset, FALSE, FALSE));
6051                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6052                       continue;
6053                     }
6054                   else if (AOP_TYPE (left) == AOP_ACC)
6055                     {
6056                       if (!offset)
6057                         {
6058                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6059                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6060                           continue;
6061                         }
6062                       else
6063                         {
6064                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6065                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6066                           continue;
6067                         }
6068                     }
6069                 }
6070               // faster than result <- left, anl result,right
6071               // and better if result is SFR
6072               if (AOP_TYPE (left) == AOP_ACC)
6073                 {
6074                   if (offset)
6075                     emitcode("mov", "a,b");
6076                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6077                 }
6078               else
6079                 {
6080                   MOVA (aopGet (right, offset, FALSE, FALSE));
6081                   emitcode ("anl", "a,%s",
6082                             aopGet (left, offset, FALSE, FALSE));
6083                 }
6084               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6085             }
6086         }
6087     }
6088
6089 release:
6090   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6091   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6092   freeAsmop (result, NULL, ic, TRUE);
6093 }
6094
6095 /*-----------------------------------------------------------------*/
6096 /* genOr  - code for or                                            */
6097 /*-----------------------------------------------------------------*/
6098 static void
6099 genOr (iCode * ic, iCode * ifx)
6100 {
6101   operand *left, *right, *result;
6102   int size, offset = 0;
6103   unsigned long lit = 0L;
6104   int bytelit = 0;
6105
6106   D(emitcode (";     genOr",""));
6107
6108   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6109   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6110   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6111
6112 #ifdef DEBUG_TYPE
6113   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6114             AOP_TYPE (result),
6115             AOP_TYPE (left), AOP_TYPE (right));
6116   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6117             AOP_SIZE (result),
6118             AOP_SIZE (left), AOP_SIZE (right));
6119 #endif
6120
6121   /* if left is a literal & right is not then exchange them */
6122   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6123       AOP_NEEDSACC (left))
6124     {
6125       operand *tmp = right;
6126       right = left;
6127       left = tmp;
6128     }
6129
6130   /* if result = right then exchange them */
6131   if (sameRegs (AOP (result), AOP (right)))
6132     {
6133       operand *tmp = right;
6134       right = left;
6135       left = tmp;
6136     }
6137
6138   /* if right is bit then exchange them */
6139   if (AOP_TYPE (right) == AOP_CRY &&
6140       AOP_TYPE (left) != AOP_CRY)
6141     {
6142       operand *tmp = right;
6143       right = left;
6144       left = tmp;
6145     }
6146   if (AOP_TYPE (right) == AOP_LIT)
6147     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6148
6149   size = AOP_SIZE (result);
6150
6151   // if(bit | yy)
6152   // xx = bit | yy;
6153   if (AOP_TYPE (left) == AOP_CRY)
6154     {
6155       if (AOP_TYPE (right) == AOP_LIT)
6156         {
6157           // c = bit | literal;
6158           if (lit)
6159             {
6160               // lit != 0 => result = 1
6161               if (AOP_TYPE (result) == AOP_CRY)
6162                 {
6163                   if (size)
6164                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6165                   else if (ifx)
6166                     continueIfTrue (ifx);
6167                   goto release;
6168                 }
6169               emitcode ("setb", "c");
6170             }
6171           else
6172             {
6173               // lit == 0 => result = left
6174               if (size && sameRegs (AOP (result), AOP (left)))
6175                 goto release;
6176               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6177             }
6178         }
6179       else
6180         {
6181           if (AOP_TYPE (right) == AOP_CRY)
6182             {
6183               // c = bit | bit;
6184               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6185               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6186             }
6187           else
6188             {
6189               // c = bit | val;
6190               symbol *tlbl = newiTempLabel (NULL);
6191               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6192                 emitcode ("setb", "c");
6193               emitcode ("jb", "%s,%05d$",
6194                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6195               toBoolean (right);
6196               emitcode ("jnz", "%05d$", tlbl->key + 100);
6197               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6198                 {
6199                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6200                   goto release;
6201                 }
6202               else
6203                 {
6204                   CLRC;
6205                   emitcode ("", "%05d$:", tlbl->key + 100);
6206                 }
6207             }
6208         }
6209       // bit = c
6210       // val = c
6211       if (size)
6212         outBitC (result);
6213       // if(bit | ...)
6214       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6215         genIfxJump (ifx, "c", left, right, result);
6216       goto release;
6217     }
6218
6219   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6220   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6221   if ((AOP_TYPE (right) == AOP_LIT) &&
6222       (AOP_TYPE (result) == AOP_CRY) &&
6223       (AOP_TYPE (left) != AOP_CRY))
6224     {
6225       if (lit)
6226         {
6227           // result = 1
6228           if (size)
6229             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6230           else
6231             continueIfTrue (ifx);
6232           goto release;
6233         }
6234       else
6235         {
6236           // lit = 0, result = boolean(left)
6237           if (size)
6238             emitcode ("setb", "c");
6239           toBoolean (right);
6240           if (size)
6241             {
6242               symbol *tlbl = newiTempLabel (NULL);
6243               emitcode ("jnz", "%05d$", tlbl->key + 100);
6244               CLRC;
6245               emitcode ("", "%05d$:", tlbl->key + 100);
6246             }
6247           else
6248             {
6249               genIfxJump (ifx, "a", left, right, result);
6250               goto release;
6251             }
6252         }
6253       outBitC (result);
6254       goto release;
6255     }
6256
6257   /* if left is same as result */
6258   if (sameRegs (AOP (result), AOP (left)))
6259     {
6260       for (; size--; offset++)
6261         {
6262           if (AOP_TYPE (right) == AOP_LIT)
6263             {
6264               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6265               if (bytelit == 0)
6266                 {
6267                   /* dummy read of volatile operand */
6268                   if (isOperandVolatile (left, FALSE))
6269                     MOVA (aopGet (left, offset, FALSE, FALSE));
6270                   else
6271                     continue;
6272                 }
6273               else if (bytelit == 0x0FF)
6274                 {
6275                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6276                 }
6277               else if (IS_AOP_PREG (left))
6278                 {
6279                   MOVA (aopGet (left, offset, FALSE, TRUE));
6280                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6281                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6282                 }
6283               else
6284                 {
6285                   emitcode ("orl", "%s,%s",
6286                             aopGet (left, offset, FALSE, TRUE),
6287                             aopGet (right, offset, FALSE, FALSE));
6288                 }
6289             }
6290           else
6291             {
6292               if (AOP_TYPE (left) == AOP_ACC)
6293                 {
6294                   if (offset)
6295                     emitcode("mov", "a,b");
6296                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6297                 }
6298               else
6299                 {
6300                   MOVA (aopGet (right, offset, FALSE, FALSE));
6301                   if (IS_AOP_PREG (left))
6302                     {
6303                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6304                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6305                     }
6306                   else
6307                     {
6308                       emitcode ("orl", "%s,a",
6309                                 aopGet (left, offset, FALSE, TRUE));
6310                     }
6311                 }
6312             }
6313         }
6314     }
6315   else
6316     {
6317       // left & result in different registers
6318       if (AOP_TYPE (result) == AOP_CRY)
6319         {
6320           // result = bit
6321           // if(size), result in bit
6322           // if(!size && ifx), conditional oper: if(left | right)
6323           symbol *tlbl = newiTempLabel (NULL);
6324           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6325           if (size)
6326             emitcode ("setb", "c");
6327           while (sizer--)
6328             {
6329               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6330                 if (offset)
6331                   emitcode("mov", "a,b");
6332                 emitcode ("orl", "a,%s",
6333                           aopGet (right, offset, FALSE, FALSE));
6334               } else {
6335                 MOVA (aopGet (right, offset, FALSE, FALSE));
6336                 emitcode ("orl", "a,%s",
6337                           aopGet (left, offset, FALSE, FALSE));
6338               }
6339               emitcode ("jnz", "%05d$", tlbl->key + 100);
6340               offset++;
6341             }
6342           if (size)
6343             {
6344               CLRC;
6345               emitcode ("", "%05d$:", tlbl->key + 100);
6346               outBitC (result);
6347             }
6348           else if (ifx)
6349             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6350           else
6351             emitcode ("", "%05d$:", tlbl->key + 100);
6352         }
6353       else
6354         {
6355           for (; (size--); offset++)
6356             {
6357               // normal case
6358               // result = left | right
6359               if (AOP_TYPE (right) == AOP_LIT)
6360                 {
6361                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6362                   if (bytelit == 0)
6363                     {
6364                       aopPut (result,
6365                               aopGet (left, offset, FALSE, FALSE),
6366                               offset,
6367                               isOperandVolatile (result, FALSE));
6368                       continue;
6369                     }
6370                   else if (bytelit == 0x0FF)
6371                     {
6372                       /* dummy read of volatile operand */
6373                       if (isOperandVolatile (left, FALSE))
6374                         MOVA (aopGet (left, offset, FALSE, FALSE));
6375                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6376                       continue;
6377                     }
6378                 }
6379               // faster than result <- left, anl result,right
6380               // and better if result is SFR
6381               if (AOP_TYPE (left) == AOP_ACC)
6382                 {
6383                   if (offset)
6384                     emitcode("mov", "a,b");
6385                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6386                 }
6387               else
6388                 {
6389                   MOVA (aopGet (right, offset, FALSE, FALSE));
6390                   emitcode ("orl", "a,%s",
6391                             aopGet (left, offset, FALSE, FALSE));
6392                 }
6393               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6394             }
6395         }
6396     }
6397
6398 release:
6399   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6400   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6401   freeAsmop (result, NULL, ic, TRUE);
6402 }
6403
6404 /*-----------------------------------------------------------------*/
6405 /* genXor - code for xclusive or                                   */
6406 /*-----------------------------------------------------------------*/
6407 static void
6408 genXor (iCode * ic, iCode * ifx)
6409 {
6410   operand *left, *right, *result;
6411   int size, offset = 0;
6412   unsigned long lit = 0L;
6413   int bytelit = 0;
6414
6415   D(emitcode (";     genXor",""));
6416
6417   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6418   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6419   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6420
6421 #ifdef DEBUG_TYPE
6422   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6423             AOP_TYPE (result),
6424             AOP_TYPE (left), AOP_TYPE (right));
6425   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6426             AOP_SIZE (result),
6427             AOP_SIZE (left), AOP_SIZE (right));
6428 #endif
6429
6430   /* if left is a literal & right is not ||
6431      if left needs acc & right does not */
6432   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6433       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6434     {
6435       operand *tmp = right;
6436       right = left;
6437       left = tmp;
6438     }
6439
6440   /* if result = right then exchange them */
6441   if (sameRegs (AOP (result), AOP (right)))
6442     {
6443       operand *tmp = right;
6444       right = left;
6445       left = tmp;
6446     }
6447
6448   /* if right is bit then exchange them */
6449   if (AOP_TYPE (right) == AOP_CRY &&
6450       AOP_TYPE (left) != AOP_CRY)
6451     {
6452       operand *tmp = right;
6453       right = left;
6454       left = tmp;
6455     }
6456   if (AOP_TYPE (right) == AOP_LIT)
6457     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6458
6459   size = AOP_SIZE (result);
6460
6461   // if(bit ^ yy)
6462   // xx = bit ^ yy;
6463   if (AOP_TYPE (left) == AOP_CRY)
6464     {
6465       if (AOP_TYPE (right) == AOP_LIT)
6466         {
6467           // c = bit & literal;
6468           if (lit >> 1)
6469             {
6470               // lit>>1  != 0 => result = 1
6471               if (AOP_TYPE (result) == AOP_CRY)
6472                 {
6473                   if (size)
6474                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6475                   else if (ifx)
6476                     continueIfTrue (ifx);
6477                   goto release;
6478                 }
6479               emitcode ("setb", "c");
6480             }
6481           else
6482             {
6483               // lit == (0 or 1)
6484               if (lit == 0)
6485                 {
6486                   // lit == 0, result = left
6487                   if (size && sameRegs (AOP (result), AOP (left)))
6488                     goto release;
6489                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6490                 }
6491               else
6492                 {
6493                   // lit == 1, result = not(left)
6494                   if (size && sameRegs (AOP (result), AOP (left)))
6495                     {
6496                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6497                       goto release;
6498                     }
6499                   else
6500                     {
6501                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6502                       emitcode ("cpl", "c");
6503                     }
6504                 }
6505             }
6506
6507         }
6508       else
6509         {
6510           // right != literal
6511           symbol *tlbl = newiTempLabel (NULL);
6512           if (AOP_TYPE (right) == AOP_CRY)
6513             {
6514               // c = bit ^ bit;
6515               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6516             }
6517           else
6518             {
6519               int sizer = AOP_SIZE (right);
6520               // c = bit ^ val
6521               // if val>>1 != 0, result = 1
6522               emitcode ("setb", "c");
6523               while (sizer)
6524                 {
6525                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6526                   if (sizer == 1)
6527                     // test the msb of the lsb
6528                     emitcode ("anl", "a,#0xfe");
6529                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6530                   sizer--;
6531                 }
6532               // val = (0,1)
6533               emitcode ("rrc", "a");
6534             }
6535           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6536           emitcode ("cpl", "c");
6537           emitcode ("", "%05d$:", (tlbl->key + 100));
6538         }
6539       // bit = c
6540       // val = c
6541       if (size)
6542         outBitC (result);
6543       // if(bit | ...)
6544       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6545         genIfxJump (ifx, "c", left, right, result);
6546       goto release;
6547     }
6548
6549   /* if left is same as result */
6550   if (sameRegs (AOP (result), AOP (left)))
6551     {
6552       for (; size--; offset++)
6553         {
6554           if (AOP_TYPE (right) == AOP_LIT)
6555             {
6556               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6557               if (bytelit == 0)
6558                 {
6559                   /* dummy read of volatile operand */
6560                   if (isOperandVolatile (left, FALSE))
6561                     MOVA (aopGet (left, offset, FALSE, FALSE));
6562                   else
6563                     continue;
6564                 }
6565               else if (IS_AOP_PREG (left))
6566                 {
6567                   MOVA (aopGet (left, offset, FALSE, TRUE));
6568                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6569                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6570                 }
6571               else
6572                 {
6573                   emitcode ("xrl", "%s,%s",
6574                             aopGet (left, offset, FALSE, TRUE),
6575                             aopGet (right, offset, FALSE, FALSE));
6576                 }
6577             }
6578           else
6579             {
6580               if (AOP_TYPE (left) == AOP_ACC)
6581                 {
6582                   if (offset)
6583                     emitcode("mov", "a,b");
6584                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6585                 }
6586               else
6587                 {
6588                   MOVA (aopGet (right, offset, FALSE, FALSE));
6589                   if (IS_AOP_PREG (left))
6590                     {
6591                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6592                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6593                     }
6594                   else
6595                     emitcode ("xrl", "%s,a",
6596                               aopGet (left, offset, FALSE, TRUE));
6597                 }
6598             }
6599         }
6600     }
6601   else
6602     {
6603       // left & result in different registers
6604       if (AOP_TYPE (result) == AOP_CRY)
6605         {
6606           // result = bit
6607           // if(size), result in bit
6608           // if(!size && ifx), conditional oper: if(left ^ right)
6609           symbol *tlbl = newiTempLabel (NULL);
6610           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6611           if (size)
6612             emitcode ("setb", "c");
6613           while (sizer--)
6614             {
6615               if ((AOP_TYPE (right) == AOP_LIT) &&
6616                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6617                 {
6618                   MOVA (aopGet (left, offset, FALSE, FALSE));
6619                 }
6620               else
6621                 {
6622                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6623                     if (offset)
6624                       emitcode("mov", "a,b");
6625                     emitcode ("xrl", "a,%s",
6626                               aopGet (right, offset, FALSE, FALSE));
6627                   } else {
6628                     MOVA (aopGet (right, offset, FALSE, FALSE));
6629                     emitcode ("xrl", "a,%s",
6630                               aopGet (left, offset, FALSE, FALSE));
6631                   }
6632                 }
6633               emitcode ("jnz", "%05d$", tlbl->key + 100);
6634               offset++;
6635             }
6636           if (size)
6637             {
6638               CLRC;
6639               emitcode ("", "%05d$:", tlbl->key + 100);
6640               outBitC (result);
6641             }
6642           else if (ifx)
6643             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6644         }
6645       else
6646         {
6647           for (; (size--); offset++)
6648             {
6649               // normal case
6650               // result = left & right
6651               if (AOP_TYPE (right) == AOP_LIT)
6652                 {
6653                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6654                   if (bytelit == 0)
6655                     {
6656                       aopPut (result,
6657                               aopGet (left, offset, FALSE, FALSE),
6658                               offset,
6659                               isOperandVolatile (result, FALSE));
6660                       continue;
6661                     }
6662                 }
6663               // faster than result <- left, anl result,right
6664               // and better if result is SFR
6665               if (AOP_TYPE (left) == AOP_ACC)
6666                 {
6667                   if (offset)
6668                     emitcode("mov", "a,b");
6669                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6670                 }
6671               else
6672                 {
6673                   MOVA (aopGet (right, offset, FALSE, FALSE));
6674                   emitcode ("xrl", "a,%s",
6675                             aopGet (left, offset, FALSE, TRUE));
6676                 }
6677               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6678             }
6679         }
6680     }
6681
6682 release:
6683   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6684   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6685   freeAsmop (result, NULL, ic, TRUE);
6686 }
6687
6688 /*-----------------------------------------------------------------*/
6689 /* genInline - write the inline code out                           */
6690 /*-----------------------------------------------------------------*/
6691 static void
6692 genInline (iCode * ic)
6693 {
6694   char *buffer, *bp, *bp1;
6695
6696   D(emitcode (";     genInline",""));
6697
6698   _G.inLine += (!options.asmpeep);
6699
6700   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6701   strcpy (buffer, IC_INLINE (ic));
6702
6703   /* emit each line as a code */
6704   while (*bp)
6705     {
6706       if (*bp == '\n')
6707         {
6708           *bp++ = '\0';
6709           emitcode (bp1, "");
6710           bp1 = bp;
6711         }
6712       else
6713         {
6714           /* Add \n for labels, not dirs such as c:\mydir */
6715           if ( (*bp == ':') && (isspace(bp[1])) )
6716             {
6717               bp++;
6718               *bp = '\0';
6719               bp++;
6720               emitcode (bp1, "");
6721               bp1 = bp;
6722             }
6723           else
6724             bp++;
6725         }
6726     }
6727   if (bp1 != bp)
6728     emitcode (bp1, "");
6729   /*     emitcode("",buffer); */
6730   _G.inLine -= (!options.asmpeep);
6731 }
6732
6733 /*-----------------------------------------------------------------*/
6734 /* genRRC - rotate right with carry                                */
6735 /*-----------------------------------------------------------------*/
6736 static void
6737 genRRC (iCode * ic)
6738 {
6739   operand *left, *result;
6740   int size, offset = 0;
6741   char *l;
6742
6743   D(emitcode (";     genRRC",""));
6744
6745   /* rotate right with carry */
6746   left = IC_LEFT (ic);
6747   result = IC_RESULT (ic);
6748   aopOp (left, ic, FALSE);
6749   aopOp (result, ic, FALSE);
6750
6751   /* move it to the result */
6752   size = AOP_SIZE (result);
6753   offset = size - 1;
6754   if (size == 1) { /* special case for 1 byte */
6755       l = aopGet (left, offset, FALSE, FALSE);
6756       MOVA (l);
6757       emitcode ("rr", "a");
6758       goto release;
6759   }
6760   /* no need to clear carry, bit7 will be written later */
6761   while (size--)
6762     {
6763       l = aopGet (left, offset, FALSE, FALSE);
6764       MOVA (l);
6765       emitcode ("rrc", "a");
6766       if (AOP_SIZE (result) > 1)
6767         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
6768     }
6769   /* now we need to put the carry into the
6770      highest order byte of the result */
6771   if (AOP_SIZE (result) > 1)
6772     {
6773       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
6774       MOVA (l);
6775     }
6776   emitcode ("mov", "acc.7,c");
6777  release:
6778   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6779   freeAsmop (left, NULL, ic, TRUE);
6780   freeAsmop (result, NULL, ic, TRUE);
6781 }
6782
6783 /*-----------------------------------------------------------------*/
6784 /* genRLC - generate code for rotate left with carry               */
6785 /*-----------------------------------------------------------------*/
6786 static void
6787 genRLC (iCode * ic)
6788 {
6789   operand *left, *result;
6790   int size, offset = 0;
6791   char *l;
6792
6793   D(emitcode (";     genRLC",""));
6794
6795   /* rotate right with carry */
6796   left = IC_LEFT (ic);
6797   result = IC_RESULT (ic);
6798   aopOp (left, ic, FALSE);
6799   aopOp (result, ic, FALSE);
6800
6801   /* move it to the result */
6802   size = AOP_SIZE (result);
6803   offset = 0;
6804   if (size--)
6805     {
6806       l = aopGet (left, offset, FALSE, FALSE);
6807       MOVA (l);
6808       if (size == 0) { /* special case for 1 byte */
6809               emitcode("rl","a");
6810               goto release;
6811       }
6812       emitcode("rlc","a"); /* bit0 will be written later */
6813       if (AOP_SIZE (result) > 1)
6814         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6815       while (size--)
6816         {
6817           l = aopGet (left, offset, FALSE, FALSE);
6818           MOVA (l);
6819           emitcode ("rlc", "a");
6820           if (AOP_SIZE (result) > 1)
6821             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6822         }
6823     }
6824   /* now we need to put the carry into the
6825      highest order byte of the result */
6826   if (AOP_SIZE (result) > 1)
6827     {
6828       l = aopGet (result, 0, FALSE, FALSE);
6829       MOVA (l);
6830     }
6831   emitcode ("mov", "acc.0,c");
6832  release:
6833   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6834   freeAsmop (left, NULL, ic, TRUE);
6835   freeAsmop (result, NULL, ic, TRUE);
6836 }
6837
6838 /*-----------------------------------------------------------------*/
6839 /* genGetHbit - generates code get highest order bit               */
6840 /*-----------------------------------------------------------------*/
6841 static void
6842 genGetHbit (iCode * ic)
6843 {
6844   operand *left, *result;
6845
6846   D(emitcode (";     genGetHbit",""));
6847
6848   left = IC_LEFT (ic);
6849   result = IC_RESULT (ic);
6850   aopOp (left, ic, FALSE);
6851   aopOp (result, ic, FALSE);
6852
6853   /* get the highest order byte into a */
6854   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
6855   if (AOP_TYPE (result) == AOP_CRY)
6856     {
6857       emitcode ("rlc", "a");
6858       outBitC (result);
6859     }
6860   else
6861     {
6862       emitcode ("rl", "a");
6863       emitcode ("anl", "a,#0x01");
6864       outAcc (result);
6865     }
6866
6867
6868   freeAsmop (left, NULL, ic, TRUE);
6869   freeAsmop (result, NULL, ic, TRUE);
6870 }
6871
6872 /*-----------------------------------------------------------------*/
6873 /* genSwap - generates code to swap nibbles or bytes               */
6874 /*-----------------------------------------------------------------*/
6875 static void
6876 genSwap (iCode * ic)
6877 {
6878   operand *left, *result;
6879
6880   D(emitcode (";     genSwap",""));
6881
6882   left = IC_LEFT (ic);
6883   result = IC_RESULT (ic);
6884   aopOp (left, ic, FALSE);
6885   aopOp (result, ic, FALSE);
6886
6887   switch (AOP_SIZE (left))
6888     {
6889     case 1: /* swap nibbles in byte */
6890       MOVA (aopGet (left, 0, FALSE, FALSE));
6891       emitcode ("swap", "a");
6892       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6893       break;
6894     case 2: /* swap bytes in word */
6895       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6896         {
6897           MOVA (aopGet (left, 0, FALSE, FALSE));
6898           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6899                   0, isOperandVolatile (result, FALSE));
6900           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
6901         }
6902       else if (operandsEqu (left, result))
6903         {
6904           char * reg = "a";
6905           bool pushedB = FALSE, leftInB = FALSE;
6906
6907           MOVA (aopGet (left, 0, FALSE, FALSE));
6908           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
6909             {
6910               pushedB = pushB ();
6911               emitcode ("mov", "b,a");
6912               reg = "b";
6913               leftInB = TRUE;
6914             }
6915           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6916                   0, isOperandVolatile (result, FALSE));
6917           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
6918
6919           if (leftInB)
6920             popB (pushedB);
6921         }
6922       else
6923         {
6924           aopPut (result, aopGet (left, 1, FALSE, FALSE),
6925                   0, isOperandVolatile (result, FALSE));
6926           aopPut (result, aopGet (left, 0, FALSE, FALSE),
6927                   1, isOperandVolatile (result, FALSE));
6928         }
6929       break;
6930     default:
6931       wassertl(FALSE, "unsupported SWAP operand size");
6932     }
6933
6934   freeAsmop (left, NULL, ic, TRUE);
6935   freeAsmop (result, NULL, ic, TRUE);
6936 }
6937
6938
6939 /*-----------------------------------------------------------------*/
6940 /* AccRol - rotate left accumulator by known count                 */
6941 /*-----------------------------------------------------------------*/
6942 static void
6943 AccRol (int shCount)
6944 {
6945   shCount &= 0x0007;            // shCount : 0..7
6946
6947   switch (shCount)
6948     {
6949     case 0:
6950       break;
6951     case 1:
6952       emitcode ("rl", "a");
6953       break;
6954     case 2:
6955       emitcode ("rl", "a");
6956       emitcode ("rl", "a");
6957       break;
6958     case 3:
6959       emitcode ("swap", "a");
6960       emitcode ("rr", "a");
6961       break;
6962     case 4:
6963       emitcode ("swap", "a");
6964       break;
6965     case 5:
6966       emitcode ("swap", "a");
6967       emitcode ("rl", "a");
6968       break;
6969     case 6:
6970       emitcode ("rr", "a");
6971       emitcode ("rr", "a");
6972       break;
6973     case 7:
6974       emitcode ("rr", "a");
6975       break;
6976     }
6977 }
6978
6979 /*-----------------------------------------------------------------*/
6980 /* AccLsh - left shift accumulator by known count                  */
6981 /*-----------------------------------------------------------------*/
6982 static void
6983 AccLsh (int shCount)
6984 {
6985   if (shCount != 0)
6986     {
6987       if (shCount == 1)
6988         emitcode ("add", "a,acc");
6989       else if (shCount == 2)
6990         {
6991           emitcode ("add", "a,acc");
6992           emitcode ("add", "a,acc");
6993         }
6994       else
6995         {
6996           /* rotate left accumulator */
6997           AccRol (shCount);
6998           /* and kill the lower order bits */
6999           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7000         }
7001     }
7002 }
7003
7004 /*-----------------------------------------------------------------*/
7005 /* AccRsh - right shift accumulator by known count                 */
7006 /*-----------------------------------------------------------------*/
7007 static void
7008 AccRsh (int shCount)
7009 {
7010   if (shCount != 0)
7011     {
7012       if (shCount == 1)
7013         {
7014           CLRC;
7015           emitcode ("rrc", "a");
7016         }
7017       else
7018         {
7019           /* rotate right accumulator */
7020           AccRol (8 - shCount);
7021           /* and kill the higher order bits */
7022           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7023         }
7024     }
7025 }
7026
7027 /*-----------------------------------------------------------------*/
7028 /* AccSRsh - signed right shift accumulator by known count                 */
7029 /*-----------------------------------------------------------------*/
7030 static void
7031 AccSRsh (int shCount)
7032 {
7033   symbol *tlbl;
7034   if (shCount != 0)
7035     {
7036       if (shCount == 1)
7037         {
7038           emitcode ("mov", "c,acc.7");
7039           emitcode ("rrc", "a");
7040         }
7041       else if (shCount == 2)
7042         {
7043           emitcode ("mov", "c,acc.7");
7044           emitcode ("rrc", "a");
7045           emitcode ("mov", "c,acc.7");
7046           emitcode ("rrc", "a");
7047         }
7048       else
7049         {
7050           tlbl = newiTempLabel (NULL);
7051           /* rotate right accumulator */
7052           AccRol (8 - shCount);
7053           /* and kill the higher order bits */
7054           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7055           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7056           emitcode ("orl", "a,#0x%02x",
7057                     (unsigned char) ~SRMask[shCount]);
7058           emitcode ("", "%05d$:", tlbl->key + 100);
7059         }
7060     }
7061 }
7062
7063 /*-----------------------------------------------------------------*/
7064 /* shiftR1Left2Result - shift right one byte from left to result   */
7065 /*-----------------------------------------------------------------*/
7066 static void
7067 shiftR1Left2Result (operand * left, int offl,
7068                     operand * result, int offr,
7069                     int shCount, int sign)
7070 {
7071   MOVA (aopGet (left, offl, FALSE, FALSE));
7072   /* shift right accumulator */
7073   if (sign)
7074     AccSRsh (shCount);
7075   else
7076     AccRsh (shCount);
7077   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7078 }
7079
7080 /*-----------------------------------------------------------------*/
7081 /* shiftL1Left2Result - shift left one byte from left to result    */
7082 /*-----------------------------------------------------------------*/
7083 static void
7084 shiftL1Left2Result (operand * left, int offl,
7085                     operand * result, int offr, int shCount)
7086 {
7087   char *l;
7088   l = aopGet (left, offl, FALSE, FALSE);
7089   MOVA (l);
7090   /* shift left accumulator */
7091   AccLsh (shCount);
7092   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7093 }
7094
7095 /*-----------------------------------------------------------------*/
7096 /* movLeft2Result - move byte from left to result                  */
7097 /*-----------------------------------------------------------------*/
7098 static void
7099 movLeft2Result (operand * left, int offl,
7100                 operand * result, int offr, int sign)
7101 {
7102   char *l;
7103   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7104     {
7105       l = aopGet (left, offl, FALSE, FALSE);
7106
7107       if (*l == '@' && (IS_AOP_PREG (result)))
7108         {
7109           emitcode ("mov", "a,%s", l);
7110           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7111         }
7112       else
7113         {
7114           if (!sign)
7115             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7116           else
7117             {
7118               /* MSB sign in acc.7 ! */
7119               if (getDataSize (left) == offl + 1)
7120                 {
7121                   emitcode ("mov", "a,%s", l);
7122                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7123                 }
7124             }
7125         }
7126     }
7127 }
7128
7129 /*-----------------------------------------------------------------*/
7130 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7131 /*-----------------------------------------------------------------*/
7132 static void
7133 AccAXRrl1 (char *x)
7134 {
7135   emitcode ("rrc", "a");
7136   emitcode ("xch", "a,%s", x);
7137   emitcode ("rrc", "a");
7138   emitcode ("xch", "a,%s", x);
7139 }
7140
7141 /*-----------------------------------------------------------------*/
7142 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7143 /*-----------------------------------------------------------------*/
7144 static void
7145 AccAXLrl1 (char *x)
7146 {
7147   emitcode ("xch", "a,%s", x);
7148   emitcode ("rlc", "a");
7149   emitcode ("xch", "a,%s", x);
7150   emitcode ("rlc", "a");
7151 }
7152
7153 /*-----------------------------------------------------------------*/
7154 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7155 /*-----------------------------------------------------------------*/
7156 static void
7157 AccAXLsh1 (char *x)
7158 {
7159   emitcode ("xch", "a,%s", x);
7160   emitcode ("add", "a,acc");
7161   emitcode ("xch", "a,%s", x);
7162   emitcode ("rlc", "a");
7163 }
7164
7165 /*-----------------------------------------------------------------*/
7166 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7167 /*-----------------------------------------------------------------*/
7168 static void
7169 AccAXLsh (char *x, int shCount)
7170 {
7171   switch (shCount)
7172     {
7173     case 0:
7174       break;
7175     case 1:
7176       AccAXLsh1 (x);
7177       break;
7178     case 2:
7179       AccAXLsh1 (x);
7180       AccAXLsh1 (x);
7181       break;
7182     case 3:
7183     case 4:
7184     case 5:                     // AAAAABBB:CCCCCDDD
7185
7186       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7187
7188       emitcode ("anl", "a,#0x%02x",
7189                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7190
7191       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7192
7193       AccRol (shCount);         // DDDCCCCC:BBB00000
7194
7195       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7196
7197       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7198
7199       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7200
7201       emitcode ("anl", "a,#0x%02x",
7202                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7203
7204       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7205
7206       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7207
7208       break;
7209     case 6:                     // AAAAAABB:CCCCCCDD
7210       emitcode ("anl", "a,#0x%02x",
7211                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7212       emitcode ("mov", "c,acc.0");      // c = B
7213       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7214 #if 0 // REMOVE ME
7215       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7216       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7217 #else
7218       emitcode("rrc","a");
7219       emitcode("xch","a,%s", x);
7220       emitcode("rrc","a");
7221       emitcode("mov","c,acc.0"); //<< get correct bit
7222       emitcode("xch","a,%s", x);
7223
7224       emitcode("rrc","a");
7225       emitcode("xch","a,%s", x);
7226       emitcode("rrc","a");
7227       emitcode("xch","a,%s", x);
7228 #endif
7229       break;
7230     case 7:                     // a:x <<= 7
7231
7232       emitcode ("anl", "a,#0x%02x",
7233                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7234
7235       emitcode ("mov", "c,acc.0");      // c = B
7236
7237       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7238
7239       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7240
7241       break;
7242     default:
7243       break;
7244     }
7245 }
7246
7247 /*-----------------------------------------------------------------*/
7248 /* AccAXRsh - right shift a:x known count (0..7)                   */
7249 /*-----------------------------------------------------------------*/
7250 static void
7251 AccAXRsh (char *x, int shCount)
7252 {
7253   switch (shCount)
7254     {
7255     case 0:
7256       break;
7257     case 1:
7258       CLRC;
7259       AccAXRrl1 (x);            // 0->a:x
7260
7261       break;
7262     case 2:
7263       CLRC;
7264       AccAXRrl1 (x);            // 0->a:x
7265
7266       CLRC;
7267       AccAXRrl1 (x);            // 0->a:x
7268
7269       break;
7270     case 3:
7271     case 4:
7272     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7273
7274       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7275
7276       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7277
7278       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7279
7280       emitcode ("anl", "a,#0x%02x",
7281                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7282
7283       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7284
7285       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7286
7287       emitcode ("anl", "a,#0x%02x",
7288                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7289
7290       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7291
7292       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7293
7294       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7295
7296       break;
7297     case 6:                     // AABBBBBB:CCDDDDDD
7298
7299       emitcode ("mov", "c,acc.7");
7300       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7301
7302       emitcode ("mov", "c,acc.7");
7303       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7304
7305       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7306
7307       emitcode ("anl", "a,#0x%02x",
7308                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7309
7310       break;
7311     case 7:                     // ABBBBBBB:CDDDDDDD
7312
7313       emitcode ("mov", "c,acc.7");      // c = A
7314
7315       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7316
7317       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7318
7319       emitcode ("anl", "a,#0x%02x",
7320                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7321
7322       break;
7323     default:
7324       break;
7325     }
7326 }
7327
7328 /*-----------------------------------------------------------------*/
7329 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7330 /*-----------------------------------------------------------------*/
7331 static void
7332 AccAXRshS (char *x, int shCount)
7333 {
7334   symbol *tlbl;
7335   switch (shCount)
7336     {
7337     case 0:
7338       break;
7339     case 1:
7340       emitcode ("mov", "c,acc.7");
7341       AccAXRrl1 (x);            // s->a:x
7342
7343       break;
7344     case 2:
7345       emitcode ("mov", "c,acc.7");
7346       AccAXRrl1 (x);            // s->a:x
7347
7348       emitcode ("mov", "c,acc.7");
7349       AccAXRrl1 (x);            // s->a:x
7350
7351       break;
7352     case 3:
7353     case 4:
7354     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7355
7356       tlbl = newiTempLabel (NULL);
7357       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7358
7359       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7360
7361       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7362
7363       emitcode ("anl", "a,#0x%02x",
7364                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7365
7366       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7367
7368       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7369
7370       emitcode ("anl", "a,#0x%02x",
7371                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7372
7373       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7374
7375       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7376
7377       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7378
7379       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7380       emitcode ("orl", "a,#0x%02x",
7381                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7382
7383       emitcode ("", "%05d$:", tlbl->key + 100);
7384       break;                    // SSSSAAAA:BBBCCCCC
7385
7386     case 6:                     // AABBBBBB:CCDDDDDD
7387
7388       tlbl = newiTempLabel (NULL);
7389       emitcode ("mov", "c,acc.7");
7390       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7391
7392       emitcode ("mov", "c,acc.7");
7393       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7394
7395       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7396
7397       emitcode ("anl", "a,#0x%02x",
7398                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7399
7400       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7401       emitcode ("orl", "a,#0x%02x",
7402                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7403
7404       emitcode ("", "%05d$:", tlbl->key + 100);
7405       break;
7406     case 7:                     // ABBBBBBB:CDDDDDDD
7407
7408       tlbl = newiTempLabel (NULL);
7409       emitcode ("mov", "c,acc.7");      // c = A
7410
7411       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7412
7413       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7414
7415       emitcode ("anl", "a,#0x%02x",
7416                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7417
7418       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7419       emitcode ("orl", "a,#0x%02x",
7420                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7421
7422       emitcode ("", "%05d$:", tlbl->key + 100);
7423       break;
7424     default:
7425       break;
7426     }
7427 }
7428
7429 /*-----------------------------------------------------------------*/
7430 /* shiftL2Left2Result - shift left two bytes from left to result   */
7431 /*-----------------------------------------------------------------*/
7432 static void
7433 shiftL2Left2Result (operand * left, int offl,
7434                     operand * result, int offr, int shCount)
7435 {
7436   if (sameRegs (AOP (result), AOP (left)) &&
7437       ((offl + MSB16) == offr))
7438     {
7439       /* don't crash result[offr] */
7440       MOVA (aopGet (left, offl, FALSE, FALSE));
7441       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7442     }
7443   else
7444     {
7445       movLeft2Result (left, offl, result, offr, 0);
7446       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7447     }
7448   /* ax << shCount (x = lsb(result)) */
7449   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
7450   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7451 }
7452
7453
7454 /*-----------------------------------------------------------------*/
7455 /* shiftR2Left2Result - shift right two bytes from left to result  */
7456 /*-----------------------------------------------------------------*/
7457 static void
7458 shiftR2Left2Result (operand * left, int offl,
7459                     operand * result, int offr,
7460                     int shCount, int sign)
7461 {
7462   if (sameRegs (AOP (result), AOP (left)) &&
7463       ((offl + MSB16) == offr))
7464     {
7465       /* don't crash result[offr] */
7466       MOVA (aopGet (left, offl, FALSE, FALSE));
7467       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7468     }
7469   else
7470     {
7471       movLeft2Result (left, offl, result, offr, 0);
7472       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7473     }
7474   /* a:x >> shCount (x = lsb(result)) */
7475   if (sign)
7476     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
7477   else
7478     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
7479   if (getDataSize (result) > 1)
7480     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7481 }
7482
7483 /*-----------------------------------------------------------------*/
7484 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7485 /*-----------------------------------------------------------------*/
7486 static void
7487 shiftLLeftOrResult (operand * left, int offl,
7488                     operand * result, int offr, int shCount)
7489 {
7490   MOVA (aopGet (left, offl, FALSE, FALSE));
7491   /* shift left accumulator */
7492   AccLsh (shCount);
7493   /* or with result */
7494   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7495   /* back to result */
7496   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7497 }
7498
7499 /*-----------------------------------------------------------------*/
7500 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7501 /*-----------------------------------------------------------------*/
7502 static void
7503 shiftRLeftOrResult (operand * left, int offl,
7504                     operand * result, int offr, int shCount)
7505 {
7506   MOVA (aopGet (left, offl, FALSE, FALSE));
7507   /* shift right accumulator */
7508   AccRsh (shCount);
7509   /* or with result */
7510   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7511   /* back to result */
7512   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7513 }
7514
7515 /*-----------------------------------------------------------------*/
7516 /* genlshOne - left shift a one byte quantity by known count       */
7517 /*-----------------------------------------------------------------*/
7518 static void
7519 genlshOne (operand * result, operand * left, int shCount)
7520 {
7521   D(emitcode (";     genlshOne",""));
7522
7523   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7524 }
7525
7526 /*-----------------------------------------------------------------*/
7527 /* genlshTwo - left shift two bytes by known amount != 0           */
7528 /*-----------------------------------------------------------------*/
7529 static void
7530 genlshTwo (operand * result, operand * left, int shCount)
7531 {
7532   int size;
7533
7534   D(emitcode (";     genlshTwo",""));
7535
7536   size = getDataSize (result);
7537
7538   /* if shCount >= 8 */
7539   if (shCount >= 8)
7540     {
7541       shCount -= 8;
7542
7543       if (size > 1)
7544         {
7545           if (shCount)
7546             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7547           else
7548             movLeft2Result (left, LSB, result, MSB16, 0);
7549         }
7550       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7551     }
7552
7553   /*  1 <= shCount <= 7 */
7554   else
7555     {
7556       if (size == 1)
7557         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7558       else
7559         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7560     }
7561 }
7562
7563 /*-----------------------------------------------------------------*/
7564 /* shiftLLong - shift left one long from left to result            */
7565 /* offl = LSB or MSB16                                             */
7566 /*-----------------------------------------------------------------*/
7567 static void
7568 shiftLLong (operand * left, operand * result, int offr)
7569 {
7570   char *l;
7571   int size = AOP_SIZE (result);
7572
7573   if (size >= LSB + offr)
7574     {
7575       l = aopGet (left, LSB, FALSE, FALSE);
7576       MOVA (l);
7577       emitcode ("add", "a,acc");
7578       if (sameRegs (AOP (left), AOP (result)) &&
7579           size >= MSB16 + offr && offr != LSB)
7580         emitcode ("xch", "a,%s",
7581                   aopGet (left, LSB + offr, FALSE, FALSE));
7582       else
7583         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
7584     }
7585
7586   if (size >= MSB16 + offr)
7587     {
7588       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7589         {
7590           l = aopGet (left, MSB16, FALSE, FALSE);
7591           MOVA (l);
7592         }
7593       emitcode ("rlc", "a");
7594       if (sameRegs (AOP (left), AOP (result)) &&
7595           size >= MSB24 + offr && offr != LSB)
7596         emitcode ("xch", "a,%s",
7597                   aopGet (left, MSB16 + offr, FALSE, FALSE));
7598       else
7599         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7600     }
7601
7602   if (size >= MSB24 + offr)
7603     {
7604       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7605         {
7606           l = aopGet (left, MSB24, FALSE, FALSE);
7607           MOVA (l);
7608         }
7609       emitcode ("rlc", "a");
7610       if (sameRegs (AOP (left), AOP (result)) &&
7611           size >= MSB32 + offr && offr != LSB)
7612         emitcode ("xch", "a,%s",
7613                   aopGet (left, MSB24 + offr, FALSE, FALSE));
7614       else
7615         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7616     }
7617
7618   if (size > MSB32 + offr)
7619     {
7620       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7621         {
7622           l = aopGet (left, MSB32, FALSE, FALSE);
7623           MOVA (l);
7624         }
7625       emitcode ("rlc", "a");
7626       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7627     }
7628   if (offr != LSB)
7629     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7630 }
7631
7632 /*-----------------------------------------------------------------*/
7633 /* genlshFour - shift four byte by a known amount != 0             */
7634 /*-----------------------------------------------------------------*/
7635 static void
7636 genlshFour (operand * result, operand * left, int shCount)
7637 {
7638   int size;
7639
7640   D(emitcode (";     genlshFour",""));
7641
7642   size = AOP_SIZE (result);
7643
7644   /* if shifting more that 3 bytes */
7645   if (shCount >= 24)
7646     {
7647       shCount -= 24;
7648       if (shCount)
7649         /* lowest order of left goes to the highest
7650            order of the destination */
7651         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7652       else
7653         movLeft2Result (left, LSB, result, MSB32, 0);
7654       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7655       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7656       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
7657       return;
7658     }
7659
7660   /* more than two bytes */
7661   else if (shCount >= 16)
7662     {
7663       /* lower order two bytes goes to higher order two bytes */
7664       shCount -= 16;
7665       /* if some more remaining */
7666       if (shCount)
7667         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7668       else
7669         {
7670           movLeft2Result (left, MSB16, result, MSB32, 0);
7671           movLeft2Result (left, LSB, result, MSB24, 0);
7672         }
7673       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7674       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7675       return;
7676     }
7677
7678   /* if more than 1 byte */
7679   else if (shCount >= 8)
7680     {
7681       /* lower order three bytes goes to higher order  three bytes */
7682       shCount -= 8;
7683       if (size == 2)
7684         {
7685           if (shCount)
7686             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7687           else
7688             movLeft2Result (left, LSB, result, MSB16, 0);
7689         }
7690       else
7691         {                       /* size = 4 */
7692           if (shCount == 0)
7693             {
7694               movLeft2Result (left, MSB24, result, MSB32, 0);
7695               movLeft2Result (left, MSB16, result, MSB24, 0);
7696               movLeft2Result (left, LSB, result, MSB16, 0);
7697               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7698             }
7699           else if (shCount == 1)
7700             shiftLLong (left, result, MSB16);
7701           else
7702             {
7703               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7704               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7705               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7706               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7707             }
7708         }
7709     }
7710
7711   /* 1 <= shCount <= 7 */
7712   else if (shCount <= 2)
7713     {
7714       shiftLLong (left, result, LSB);
7715       if (shCount == 2)
7716         shiftLLong (result, result, LSB);
7717     }
7718   /* 3 <= shCount <= 7, optimize */
7719   else
7720     {
7721       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7722       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7723       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7724     }
7725 }
7726
7727 /*-----------------------------------------------------------------*/
7728 /* genLeftShiftLiteral - left shifting by known count              */
7729 /*-----------------------------------------------------------------*/
7730 static void
7731 genLeftShiftLiteral (operand * left,
7732                      operand * right,
7733                      operand * result,
7734                      iCode * ic)
7735 {
7736   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7737   int size;
7738
7739   D(emitcode (";     genLeftShiftLiteral",""));
7740
7741   freeAsmop (right, NULL, ic, TRUE);
7742
7743   aopOp (left, ic, FALSE);
7744   aopOp (result, ic, FALSE);
7745
7746   size = getSize (operandType (result));
7747
7748 #if VIEW_SIZE
7749   emitcode ("; shift left ", "result %d, left %d", size,
7750             AOP_SIZE (left));
7751 #endif
7752
7753   /* I suppose that the left size >= result size */
7754   if (shCount == 0)
7755     {
7756       while (size--)
7757         {
7758           movLeft2Result (left, size, result, size, 0);
7759         }
7760     }
7761
7762   else if (shCount >= (size * 8))
7763     while (size--)
7764       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
7765   else
7766     {
7767       switch (size)
7768         {
7769         case 1:
7770           genlshOne (result, left, shCount);
7771           break;
7772
7773         case 2:
7774           genlshTwo (result, left, shCount);
7775           break;
7776
7777         case 4:
7778           genlshFour (result, left, shCount);
7779           break;
7780         default:
7781           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7782                   "*** ack! mystery literal shift!\n");
7783           break;
7784         }
7785     }
7786   freeAsmop (left, NULL, ic, TRUE);
7787   freeAsmop (result, NULL, ic, TRUE);
7788 }
7789
7790 /*-----------------------------------------------------------------*/
7791 /* genLeftShift - generates code for left shifting                 */
7792 /*-----------------------------------------------------------------*/
7793 static void
7794 genLeftShift (iCode * ic)
7795 {
7796   operand *left, *right, *result;
7797   int size, offset;
7798   char *l;
7799   symbol *tlbl, *tlbl1;
7800   bool pushedB;
7801
7802   D(emitcode (";     genLeftShift",""));
7803
7804   right = IC_RIGHT (ic);
7805   left = IC_LEFT (ic);
7806   result = IC_RESULT (ic);
7807
7808   aopOp (right, ic, FALSE);
7809
7810   /* if the shift count is known then do it
7811      as efficiently as possible */
7812   if (AOP_TYPE (right) == AOP_LIT)
7813     {
7814       genLeftShiftLiteral (left, right, result, ic);
7815       return;
7816     }
7817
7818   /* shift count is unknown then we have to form
7819      a loop get the loop count in B : Note: we take
7820      only the lower order byte since shifting
7821      more that 32 bits make no sense anyway, ( the
7822      largest size of an object can be only 32 bits ) */
7823
7824   pushedB = pushB ();
7825   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
7826   emitcode ("inc", "b");
7827   freeAsmop (right, NULL, ic, TRUE);
7828   aopOp (left, ic, FALSE);
7829   aopOp (result, ic, FALSE);
7830
7831   /* now move the left to the result if they are not the same */
7832   if (!sameRegs (AOP (left), AOP (result)) &&
7833       AOP_SIZE (result) > 1)
7834     {
7835
7836       size = AOP_SIZE (result);
7837       offset = 0;
7838       while (size--)
7839         {
7840           l = aopGet (left, offset, FALSE, TRUE);
7841           if (*l == '@' && (IS_AOP_PREG (result)))
7842             {
7843
7844               emitcode ("mov", "a,%s", l);
7845               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7846             }
7847           else
7848             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
7849           offset++;
7850         }
7851     }
7852
7853   tlbl = newiTempLabel (NULL);
7854   size = AOP_SIZE (result);
7855   offset = 0;
7856   tlbl1 = newiTempLabel (NULL);
7857
7858   /* if it is only one byte then */
7859   if (size == 1)
7860     {
7861       symbol *tlbl1 = newiTempLabel (NULL);
7862
7863       l = aopGet (left, 0, FALSE, FALSE);
7864       MOVA (l);
7865       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7866       emitcode ("", "%05d$:", tlbl->key + 100);
7867       emitcode ("add", "a,acc");
7868       emitcode ("", "%05d$:", tlbl1->key + 100);
7869       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7870       popB (pushedB);
7871       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7872       goto release;
7873     }
7874
7875   reAdjustPreg (AOP (result));
7876
7877   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7878   emitcode ("", "%05d$:", tlbl->key + 100);
7879   l = aopGet (result, offset, FALSE, FALSE);
7880   MOVA (l);
7881   emitcode ("add", "a,acc");
7882   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7883   while (--size)
7884     {
7885       l = aopGet (result, offset, FALSE, FALSE);
7886       MOVA (l);
7887       emitcode ("rlc", "a");
7888       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7889     }
7890   reAdjustPreg (AOP (result));
7891
7892   emitcode ("", "%05d$:", tlbl1->key + 100);
7893   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7894   popB (pushedB);
7895 release:
7896   freeAsmop (left, NULL, ic, TRUE);
7897   freeAsmop (result, NULL, ic, TRUE);
7898 }
7899
7900 /*-----------------------------------------------------------------*/
7901 /* genrshOne - right shift a one byte quantity by known count      */
7902 /*-----------------------------------------------------------------*/
7903 static void
7904 genrshOne (operand * result, operand * left,
7905            int shCount, int sign)
7906 {
7907   D(emitcode (";     genrshOne",""));
7908
7909   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7910 }
7911
7912 /*-----------------------------------------------------------------*/
7913 /* genrshTwo - right shift two bytes by known amount != 0          */
7914 /*-----------------------------------------------------------------*/
7915 static void
7916 genrshTwo (operand * result, operand * left,
7917            int shCount, int sign)
7918 {
7919   D(emitcode (";     genrshTwo",""));
7920
7921   /* if shCount >= 8 */
7922   if (shCount >= 8)
7923     {
7924       shCount -= 8;
7925       if (shCount)
7926         shiftR1Left2Result (left, MSB16, result, LSB,
7927                             shCount, sign);
7928       else
7929         movLeft2Result (left, MSB16, result, LSB, sign);
7930       addSign (result, MSB16, sign);
7931     }
7932
7933   /*  1 <= shCount <= 7 */
7934   else
7935     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7936 }
7937
7938 /*-----------------------------------------------------------------*/
7939 /* shiftRLong - shift right one long from left to result           */
7940 /* offl = LSB or MSB16                                             */
7941 /*-----------------------------------------------------------------*/
7942 static void
7943 shiftRLong (operand * left, int offl,
7944             operand * result, int sign)
7945 {
7946   int isSameRegs=sameRegs(AOP(left),AOP(result));
7947
7948   if (isSameRegs && offl>1) {
7949     // we are in big trouble, but this shouldn't happen
7950     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7951   }
7952
7953   MOVA (aopGet (left, MSB32, FALSE, FALSE));
7954
7955   if (offl==MSB16) {
7956     // shift is > 8
7957     if (sign) {
7958       emitcode ("rlc", "a");
7959       emitcode ("subb", "a,acc");
7960       if (isSameRegs)
7961         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
7962       else {
7963         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
7964         MOVA (aopGet (left, MSB32, FALSE, FALSE));
7965       }
7966     } else {
7967       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
7968     }
7969   }
7970
7971   if (!sign) {
7972     emitcode ("clr", "c");
7973   } else {
7974     emitcode ("mov", "c,acc.7");
7975   }
7976
7977   emitcode ("rrc", "a");
7978
7979   if (isSameRegs && offl==MSB16) {
7980     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
7981   } else {
7982     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
7983     MOVA (aopGet (left, MSB24, FALSE, FALSE));
7984   }
7985
7986   emitcode ("rrc", "a");
7987   if (isSameRegs && offl==1) {
7988     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
7989   } else {
7990     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
7991     MOVA (aopGet (left, MSB16, FALSE, FALSE));
7992   }
7993   emitcode ("rrc", "a");
7994   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7995
7996   if (offl == LSB)
7997     {
7998       MOVA (aopGet (left, LSB, FALSE, FALSE));
7999       emitcode ("rrc", "a");
8000       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8001     }
8002 }
8003
8004 /*-----------------------------------------------------------------*/
8005 /* genrshFour - shift four byte by a known amount != 0             */
8006 /*-----------------------------------------------------------------*/
8007 static void
8008 genrshFour (operand * result, operand * left,
8009             int shCount, int sign)
8010 {
8011   D(emitcode (";     genrshFour",""));
8012
8013   /* if shifting more that 3 bytes */
8014   if (shCount >= 24)
8015     {
8016       shCount -= 24;
8017       if (shCount)
8018         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8019       else
8020         movLeft2Result (left, MSB32, result, LSB, sign);
8021       addSign (result, MSB16, sign);
8022     }
8023   else if (shCount >= 16)
8024     {
8025       shCount -= 16;
8026       if (shCount)
8027         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8028       else
8029         {
8030           movLeft2Result (left, MSB24, result, LSB, 0);
8031           movLeft2Result (left, MSB32, result, MSB16, sign);
8032         }
8033       addSign (result, MSB24, sign);
8034     }
8035   else if (shCount >= 8)
8036     {
8037       shCount -= 8;
8038       if (shCount == 1)
8039         shiftRLong (left, MSB16, result, sign);
8040       else if (shCount == 0)
8041         {
8042           movLeft2Result (left, MSB16, result, LSB, 0);
8043           movLeft2Result (left, MSB24, result, MSB16, 0);
8044           movLeft2Result (left, MSB32, result, MSB24, sign);
8045           addSign (result, MSB32, sign);
8046         }
8047       else
8048         {
8049           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8050           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8051           /* the last shift is signed */
8052           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8053           addSign (result, MSB32, sign);
8054         }
8055     }
8056   else
8057     {                           /* 1 <= shCount <= 7 */
8058       if (shCount <= 2)
8059         {
8060           shiftRLong (left, LSB, result, sign);
8061           if (shCount == 2)
8062             shiftRLong (result, LSB, result, sign);
8063         }
8064       else
8065         {
8066           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8067           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8068           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8069         }
8070     }
8071 }
8072
8073 /*-----------------------------------------------------------------*/
8074 /* genRightShiftLiteral - right shifting by known count            */
8075 /*-----------------------------------------------------------------*/
8076 static void
8077 genRightShiftLiteral (operand * left,
8078                       operand * right,
8079                       operand * result,
8080                       iCode * ic,
8081                       int sign)
8082 {
8083   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8084   int size;
8085
8086   D(emitcode (";     genRightShiftLiteral",""));
8087
8088   freeAsmop (right, NULL, ic, TRUE);
8089
8090   aopOp (left, ic, FALSE);
8091   aopOp (result, ic, FALSE);
8092
8093 #if VIEW_SIZE
8094   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8095             AOP_SIZE (left));
8096 #endif
8097
8098   size = getDataSize (left);
8099   /* test the LEFT size !!! */
8100
8101   /* I suppose that the left size >= result size */
8102   if (shCount == 0)
8103     {
8104       size = getDataSize (result);
8105       while (size--)
8106         movLeft2Result (left, size, result, size, 0);
8107     }
8108
8109   else if (shCount >= (size * 8))
8110     {
8111       if (sign) {
8112         /* get sign in acc.7 */
8113         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8114       }
8115       addSign (result, LSB, sign);
8116     }
8117   else
8118     {
8119       switch (size)
8120         {
8121         case 1:
8122           genrshOne (result, left, shCount, sign);
8123           break;
8124
8125         case 2:
8126           genrshTwo (result, left, shCount, sign);
8127           break;
8128
8129         case 4:
8130           genrshFour (result, left, shCount, sign);
8131           break;
8132         default:
8133           break;
8134         }
8135     }
8136   freeAsmop (left, NULL, ic, TRUE);
8137   freeAsmop (result, NULL, ic, TRUE);
8138 }
8139
8140 /*-----------------------------------------------------------------*/
8141 /* genSignedRightShift - right shift of signed number              */
8142 /*-----------------------------------------------------------------*/
8143 static void
8144 genSignedRightShift (iCode * ic)
8145 {
8146   operand *right, *left, *result;
8147   int size, offset;
8148   char *l;
8149   symbol *tlbl, *tlbl1;
8150   bool pushedB;
8151
8152   D(emitcode (";     genSignedRightShift",""));
8153
8154   /* we do it the hard way put the shift count in b
8155      and loop thru preserving the sign */
8156
8157   right = IC_RIGHT (ic);
8158   left = IC_LEFT (ic);
8159   result = IC_RESULT (ic);
8160
8161   aopOp (right, ic, FALSE);
8162
8163
8164   if (AOP_TYPE (right) == AOP_LIT)
8165     {
8166       genRightShiftLiteral (left, right, result, ic, 1);
8167       return;
8168     }
8169   /* shift count is unknown then we have to form
8170      a loop get the loop count in B : Note: we take
8171      only the lower order byte since shifting
8172      more that 32 bits make no sense anyway, ( the
8173      largest size of an object can be only 32 bits ) */
8174
8175   pushedB = pushB ();
8176   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8177   emitcode ("inc", "b");
8178   freeAsmop (right, NULL, ic, TRUE);
8179   aopOp (left, ic, FALSE);
8180   aopOp (result, ic, FALSE);
8181
8182   /* now move the left to the result if they are not the
8183      same */
8184   if (!sameRegs (AOP (left), AOP (result)) &&
8185       AOP_SIZE (result) > 1)
8186     {
8187
8188       size = AOP_SIZE (result);
8189       offset = 0;
8190       while (size--)
8191         {
8192           l = aopGet (left, offset, FALSE, TRUE);
8193           if (*l == '@' && IS_AOP_PREG (result))
8194             {
8195
8196               emitcode ("mov", "a,%s", l);
8197               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8198             }
8199           else
8200             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8201           offset++;
8202         }
8203     }
8204
8205   /* mov the highest order bit to OVR */
8206   tlbl = newiTempLabel (NULL);
8207   tlbl1 = newiTempLabel (NULL);
8208
8209   size = AOP_SIZE (result);
8210   offset = size - 1;
8211   MOVA (aopGet (left, offset, FALSE, FALSE));
8212   emitcode ("rlc", "a");
8213   emitcode ("mov", "ov,c");
8214   /* if it is only one byte then */
8215   if (size == 1)
8216     {
8217       l = aopGet (left, 0, FALSE, FALSE);
8218       MOVA (l);
8219       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8220       emitcode ("", "%05d$:", tlbl->key + 100);
8221       emitcode ("mov", "c,ov");
8222       emitcode ("rrc", "a");
8223       emitcode ("", "%05d$:", tlbl1->key + 100);
8224       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8225       popB (pushedB);
8226       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8227       goto release;
8228     }
8229
8230   reAdjustPreg (AOP (result));
8231   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8232   emitcode ("", "%05d$:", tlbl->key + 100);
8233   emitcode ("mov", "c,ov");
8234   while (size--)
8235     {
8236       l = aopGet (result, offset, FALSE, FALSE);
8237       MOVA (l);
8238       emitcode ("rrc", "a");
8239       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8240     }
8241   reAdjustPreg (AOP (result));
8242   emitcode ("", "%05d$:", tlbl1->key + 100);
8243   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8244   popB (pushedB);
8245
8246 release:
8247   freeAsmop (left, NULL, ic, TRUE);
8248   freeAsmop (result, NULL, ic, TRUE);
8249 }
8250
8251 /*-----------------------------------------------------------------*/
8252 /* genRightShift - generate code for right shifting                */
8253 /*-----------------------------------------------------------------*/
8254 static void
8255 genRightShift (iCode * ic)
8256 {
8257   operand *right, *left, *result;
8258   sym_link *letype;
8259   int size, offset;
8260   char *l;
8261   symbol *tlbl, *tlbl1;
8262   bool pushedB;
8263
8264   D(emitcode (";     genRightShift",""));
8265
8266   /* if signed then we do it the hard way preserve the
8267      sign bit moving it inwards */
8268   letype = getSpec (operandType (IC_LEFT (ic)));
8269
8270   if (!SPEC_USIGN (letype))
8271     {
8272       genSignedRightShift (ic);
8273       return;
8274     }
8275
8276   /* signed & unsigned types are treated the same : i.e. the
8277      signed is NOT propagated inwards : quoting from the
8278      ANSI - standard : "for E1 >> E2, is equivalent to division
8279      by 2**E2 if unsigned or if it has a non-negative value,
8280      otherwise the result is implementation defined ", MY definition
8281      is that the sign does not get propagated */
8282
8283   right = IC_RIGHT (ic);
8284   left = IC_LEFT (ic);
8285   result = IC_RESULT (ic);
8286
8287   aopOp (right, ic, FALSE);
8288
8289   /* if the shift count is known then do it
8290      as efficiently as possible */
8291   if (AOP_TYPE (right) == AOP_LIT)
8292     {
8293       genRightShiftLiteral (left, right, result, ic, 0);
8294       return;
8295     }
8296
8297   /* shift count is unknown then we have to form
8298      a loop get the loop count in B : Note: we take
8299      only the lower order byte since shifting
8300      more that 32 bits make no sense anyway, ( the
8301      largest size of an object can be only 32 bits ) */
8302
8303   pushedB = pushB ();
8304   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8305   emitcode ("inc", "b");
8306   freeAsmop (right, NULL, ic, TRUE);
8307   aopOp (left, ic, FALSE);
8308   aopOp (result, ic, FALSE);
8309
8310   /* now move the left to the result if they are not the
8311      same */
8312   if (!sameRegs (AOP (left), AOP (result)) &&
8313       AOP_SIZE (result) > 1)
8314     {
8315
8316       size = AOP_SIZE (result);
8317       offset = 0;
8318       while (size--)
8319         {
8320           l = aopGet (left, offset, FALSE, TRUE);
8321           if (*l == '@' && IS_AOP_PREG (result))
8322             {
8323
8324               emitcode ("mov", "a,%s", l);
8325               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8326             }
8327           else
8328             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8329           offset++;
8330         }
8331     }
8332
8333   tlbl = newiTempLabel (NULL);
8334   tlbl1 = newiTempLabel (NULL);
8335   size = AOP_SIZE (result);
8336   offset = size - 1;
8337
8338   /* if it is only one byte then */
8339   if (size == 1)
8340     {
8341       l = aopGet (left, 0, FALSE, FALSE);
8342       MOVA (l);
8343       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8344       emitcode ("", "%05d$:", tlbl->key + 100);
8345       CLRC;
8346       emitcode ("rrc", "a");
8347       emitcode ("", "%05d$:", tlbl1->key + 100);
8348       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8349       popB (pushedB);
8350       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8351       goto release;
8352     }
8353
8354   reAdjustPreg (AOP (result));
8355   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8356   emitcode ("", "%05d$:", tlbl->key + 100);
8357   CLRC;
8358   while (size--)
8359     {
8360       l = aopGet (result, offset, FALSE, FALSE);
8361       MOVA (l);
8362       emitcode ("rrc", "a");
8363       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8364     }
8365   reAdjustPreg (AOP (result));
8366
8367   emitcode ("", "%05d$:", tlbl1->key + 100);
8368   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8369   popB (pushedB);
8370
8371 release:
8372   freeAsmop (left, NULL, ic, TRUE);
8373   freeAsmop (result, NULL, ic, TRUE);
8374 }
8375
8376 /*-----------------------------------------------------------------*/
8377 /* emitPtrByteGet - emits code to get a byte into A through a      */
8378 /*                  pointer register (R0, R1, or DPTR). The        */
8379 /*                  original value of A can be preserved in B.     */
8380 /*-----------------------------------------------------------------*/
8381 static void
8382 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8383 {
8384   switch (p_type)
8385     {
8386     case IPOINTER:
8387     case POINTER:
8388       if (preserveAinB)
8389         emitcode ("mov", "b,a");
8390       emitcode ("mov", "a,@%s", rname);
8391       break;
8392
8393     case PPOINTER:
8394       if (preserveAinB)
8395         emitcode ("mov", "b,a");
8396       emitcode ("movx", "a,@%s", rname);
8397       break;
8398
8399     case FPOINTER:
8400       if (preserveAinB)
8401         emitcode ("mov", "b,a");
8402       emitcode ("movx", "a,@dptr");
8403       break;
8404
8405     case CPOINTER:
8406       if (preserveAinB)
8407         emitcode ("mov", "b,a");
8408       emitcode ("clr", "a");
8409       emitcode ("movc", "a,@a+dptr");
8410       break;
8411
8412     case GPOINTER:
8413       if (preserveAinB)
8414         {
8415           emitcode ("push", "b");
8416           emitcode ("push", "acc");
8417         }
8418       emitcode ("lcall", "__gptrget");
8419       if (preserveAinB)
8420         emitcode ("pop", "b");
8421       break;
8422     }
8423 }
8424
8425 /*-----------------------------------------------------------------*/
8426 /* emitPtrByteSet - emits code to set a byte from src through a    */
8427 /*                  pointer register (R0, R1, or DPTR).            */
8428 /*-----------------------------------------------------------------*/
8429 static void
8430 emitPtrByteSet (char *rname, int p_type, char *src)
8431 {
8432   switch (p_type)
8433     {
8434     case IPOINTER:
8435     case POINTER:
8436       if (*src=='@')
8437         {
8438           MOVA (src);
8439           emitcode ("mov", "@%s,a", rname);
8440         }
8441       else
8442         emitcode ("mov", "@%s,%s", rname, src);
8443       break;
8444
8445     case PPOINTER:
8446       MOVA (src);
8447       emitcode ("movx", "@%s,a", rname);
8448       break;
8449
8450     case FPOINTER:
8451       MOVA (src);
8452       emitcode ("movx", "@dptr,a");
8453       break;
8454
8455     case GPOINTER:
8456       MOVA (src);
8457       emitcode ("lcall", "__gptrput");
8458       break;
8459     }
8460 }
8461
8462 /*-----------------------------------------------------------------*/
8463 /* genUnpackBits - generates code for unpacking bits               */
8464 /*-----------------------------------------------------------------*/
8465 static void
8466 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8467 {
8468   int offset = 0;       /* result byte offset */
8469   int rsize;            /* result size */
8470   int rlen = 0;         /* remaining bitfield length */
8471   sym_link *etype;      /* bitfield type information */
8472   int blen;             /* bitfield length */
8473   int bstr;             /* bitfield starting bit within byte */
8474   char buffer[10];
8475
8476   D(emitcode (";     genUnpackBits",""));
8477
8478   etype = getSpec (operandType (result));
8479   rsize = getSize (operandType (result));
8480   blen = SPEC_BLEN (etype);
8481   bstr = SPEC_BSTR (etype);
8482
8483   if (ifx && blen <= 8)
8484     {
8485       emitPtrByteGet (rname, ptype, FALSE);
8486       if (blen == 1)
8487         {
8488           SNPRINTF (buffer, sizeof(buffer),
8489                     "acc.%d", bstr);
8490           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8491         }
8492       else
8493         {
8494           if (blen < 8)
8495             emitcode ("anl", "a,#0x%02x",
8496                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8497           genIfxJump (ifx, "a", NULL, NULL, NULL);
8498         }
8499       return;
8500     }
8501   wassert (!ifx);
8502
8503   /* If the bitfield length is less than a byte */
8504   if (blen < 8)
8505     {
8506       emitPtrByteGet (rname, ptype, FALSE);
8507       AccRsh (bstr);
8508       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8509       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8510       goto finish;
8511     }
8512
8513   /* Bit field did not fit in a byte. Copy all
8514      but the partial byte at the end.  */
8515   for (rlen=blen;rlen>=8;rlen-=8)
8516     {
8517       emitPtrByteGet (rname, ptype, FALSE);
8518       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8519       if (rlen>8)
8520         emitcode ("inc", "%s", rname);
8521     }
8522
8523   /* Handle the partial byte at the end */
8524   if (rlen)
8525     {
8526       emitPtrByteGet (rname, ptype, FALSE);
8527       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8528       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8529     }
8530
8531 finish:
8532   if (offset < rsize)
8533     {
8534       rsize -= offset;
8535       while (rsize--)
8536         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
8537     }
8538 }
8539
8540
8541 /*-----------------------------------------------------------------*/
8542 /* genDataPointerGet - generates code when ptr offset is known     */
8543 /*-----------------------------------------------------------------*/
8544 static void
8545 genDataPointerGet (operand * left,
8546                    operand * result,
8547                    iCode * ic)
8548 {
8549   char *l;
8550   char buffer[256];
8551   int size, offset = 0;
8552
8553   D(emitcode (";     genDataPointerGet",""));
8554
8555   aopOp (result, ic, TRUE);
8556
8557   /* get the string representation of the name */
8558   l = aopGet (left, 0, FALSE, TRUE);
8559   size = AOP_SIZE (result);
8560   while (size--)
8561     {
8562       if (offset)
8563         sprintf (buffer, "(%s + %d)", l + 1, offset);
8564       else
8565         sprintf (buffer, "%s", l + 1);
8566       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
8567     }
8568
8569   freeAsmop (left, NULL, ic, TRUE);
8570   freeAsmop (result, NULL, ic, TRUE);
8571 }
8572
8573 /*-----------------------------------------------------------------*/
8574 /* genNearPointerGet - emitcode for near pointer fetch             */
8575 /*-----------------------------------------------------------------*/
8576 static void
8577 genNearPointerGet (operand * left,
8578                    operand * result,
8579                    iCode * ic,
8580                    iCode * pi,
8581                    iCode * ifx)
8582 {
8583   asmop *aop = NULL;
8584   regs *preg = NULL;
8585   char *rname;
8586   sym_link *rtype, *retype;
8587   sym_link *ltype = operandType (left);
8588   char buffer[80];
8589
8590   D(emitcode (";     genNearPointerGet",""));
8591
8592   rtype = operandType (result);
8593   retype = getSpec (rtype);
8594
8595   aopOp (left, ic, FALSE);
8596
8597   /* if left is rematerialisable and
8598      result is not bitfield variable type and
8599      the left is pointer to data space i.e
8600      lower 128 bytes of space */
8601   if (AOP_TYPE (left) == AOP_IMMD &&
8602       !IS_BITFIELD (retype) &&
8603       DCL_TYPE (ltype) == POINTER)
8604     {
8605       genDataPointerGet (left, result, ic);
8606       return;
8607     }
8608
8609  /* if the value is already in a pointer register
8610      then don't need anything more */
8611   if (!AOP_INPREG (AOP (left)))
8612     {
8613       if (IS_AOP_PREG (left))
8614         {
8615           // Aha, it is a pointer, just in disguise.
8616           rname = aopGet (left, 0, FALSE, FALSE);
8617           if (*rname != '@')
8618             {
8619               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8620                       __FILE__, __LINE__);
8621             }
8622           else
8623             {
8624               // Expected case.
8625               emitcode ("mov", "a%s,%s", rname + 1, rname);
8626               rname++;  // skip the '@'.
8627             }
8628         }
8629       else
8630         {
8631           /* otherwise get a free pointer register */
8632           aop = newAsmop (0);
8633           preg = getFreePtr (ic, &aop, FALSE);
8634           emitcode ("mov", "%s,%s",
8635                     preg->name,
8636                     aopGet (left, 0, FALSE, TRUE));
8637           rname = preg->name;
8638         }
8639     }
8640   else
8641     rname = aopGet (left, 0, FALSE, FALSE);
8642
8643   //aopOp (result, ic, FALSE);
8644   aopOp (result, ic, result?TRUE:FALSE);
8645
8646   /* if bitfield then unpack the bits */
8647   if (IS_BITFIELD (retype))
8648     genUnpackBits (result, rname, POINTER, ifx);
8649   else
8650     {
8651       /* we have can just get the values */
8652       int size = AOP_SIZE (result);
8653       int offset = 0;
8654
8655       while (size--)
8656         {
8657           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8658             {
8659
8660               emitcode ("mov", "a,@%s", rname);
8661               if (!ifx)
8662               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8663             }
8664           else
8665             {
8666               sprintf (buffer, "@%s", rname);
8667               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
8668             }
8669           offset++;
8670           if (size || pi)
8671             emitcode ("inc", "%s", rname);
8672         }
8673     }
8674
8675   /* now some housekeeping stuff */
8676   if (aop)       /* we had to allocate for this iCode */
8677     {
8678       if (pi) { /* post increment present */
8679         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8680       }
8681       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8682     }
8683   else
8684     {
8685       /* we did not allocate which means left
8686          already in a pointer register, then
8687          if size > 0 && this could be used again
8688          we have to point it back to where it
8689          belongs */
8690       if ((AOP_SIZE (result) > 1 &&
8691            !OP_SYMBOL (left)->remat &&
8692            (OP_SYMBOL (left)->liveTo > ic->seq ||
8693             ic->depth)) &&
8694           !pi)
8695         {
8696           int size = AOP_SIZE (result) - 1;
8697           while (size--)
8698             emitcode ("dec", "%s", rname);
8699         }
8700     }
8701
8702   if (ifx && !ifx->generated)
8703     {
8704       genIfxJump (ifx, "a", left, NULL, result);
8705     }
8706
8707   /* done */
8708   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8709   freeAsmop (left, NULL, ic, TRUE);
8710   if (pi) pi->generated = 1;
8711 }
8712
8713 /*-----------------------------------------------------------------*/
8714 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8715 /*-----------------------------------------------------------------*/
8716 static void
8717 genPagedPointerGet (operand * left,
8718                     operand * result,
8719                     iCode * ic,
8720                     iCode *pi,
8721                     iCode *ifx)
8722 {
8723   asmop *aop = NULL;
8724   regs *preg = NULL;
8725   char *rname;
8726   sym_link *rtype, *retype;
8727
8728   D(emitcode (";     genPagedPointerGet",""));
8729
8730   rtype = operandType (result);
8731   retype = getSpec (rtype);
8732
8733   aopOp (left, ic, FALSE);
8734
8735   /* if the value is already in a pointer register
8736      then don't need anything more */
8737   if (!AOP_INPREG (AOP (left)))
8738     {
8739       /* otherwise get a free pointer register */
8740       aop = newAsmop (0);
8741       preg = getFreePtr (ic, &aop, FALSE);
8742       emitcode ("mov", "%s,%s",
8743                 preg->name,
8744                 aopGet (left, 0, FALSE, TRUE));
8745       rname = preg->name;
8746     }
8747   else
8748     rname = aopGet (left, 0, FALSE, FALSE);
8749
8750   aopOp (result, ic, FALSE);
8751
8752   /* if bitfield then unpack the bits */
8753   if (IS_BITFIELD (retype))
8754     genUnpackBits (result, rname, PPOINTER, ifx);
8755   else
8756     {
8757       /* we have can just get the values */
8758       int size = AOP_SIZE (result);
8759       int offset = 0;
8760
8761       while (size--)
8762         {
8763
8764           emitcode ("movx", "a,@%s", rname);
8765           if (!ifx)
8766           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8767
8768           offset++;
8769
8770           if (size || pi)
8771             emitcode ("inc", "%s", rname);
8772         }
8773     }
8774
8775   /* now some housekeeping stuff */
8776   if (aop) /* we had to allocate for this iCode */
8777     {
8778       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8779       freeAsmop (NULL, aop, ic, TRUE);
8780     }
8781   else
8782     {
8783       /* we did not allocate which means left
8784          already in a pointer register, then
8785          if size > 0 && this could be used again
8786          we have to point it back to where it
8787          belongs */
8788       if ((AOP_SIZE (result) > 1 &&
8789            !OP_SYMBOL (left)->remat &&
8790            (OP_SYMBOL (left)->liveTo > ic->seq ||
8791             ic->depth)) &&
8792           !pi)
8793         {
8794           int size = AOP_SIZE (result) - 1;
8795           while (size--)
8796             emitcode ("dec", "%s", rname);
8797         }
8798     }
8799
8800   if (ifx && !ifx->generated)
8801     {
8802       genIfxJump (ifx, "a", left, NULL, result);
8803     }
8804
8805   /* done */
8806   freeAsmop (left, NULL, ic, TRUE);
8807   freeAsmop (result, NULL, ic, TRUE);
8808   if (pi) pi->generated = 1;
8809
8810 }
8811
8812 /*--------------------------------------------------------------------*/
8813 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8814 /*--------------------------------------------------------------------*/
8815 static void
8816 loadDptrFromOperand (operand *op, bool loadBToo)
8817 {
8818   if (AOP_TYPE (op) != AOP_STR)
8819     {
8820       /* if this is rematerializable */
8821       if (AOP_TYPE (op) == AOP_IMMD)
8822         {
8823           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
8824           if (loadBToo)
8825             {
8826               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8827                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
8828               else
8829                 {
8830                   wassertl(FALSE, "need pointerCode");
8831                   emitcode ("", "; mov b,???");
8832                   /* genPointerGet and genPointerSet originally did different
8833                   ** things for this case. Both seem wrong.
8834                   ** from genPointerGet:
8835                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8836                   ** from genPointerSet:
8837                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
8838                   */
8839                 }
8840             }
8841         }
8842       else if (AOP_TYPE (op) == AOP_DPTR)
8843         {
8844           if (loadBToo)
8845             {
8846               MOVA (aopGet (op, 0, FALSE, FALSE));
8847               emitcode ("push", "acc");
8848               MOVA (aopGet (op, 1, FALSE, FALSE));
8849               emitcode ("push", "acc");
8850               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8851               emitcode ("pop", "dph");
8852               emitcode ("pop", "dpl");
8853             }
8854           else
8855             {
8856               MOVA (aopGet (op, 0, FALSE, FALSE));
8857               emitcode ("push", "acc");
8858               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
8859               emitcode ("pop", "dpl");
8860             }
8861         }
8862       else
8863         {                       /* we need to get it byte by byte */
8864           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
8865           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
8866           if (loadBToo)
8867             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8868         }
8869     }
8870 }
8871
8872 /*-----------------------------------------------------------------*/
8873 /* genFarPointerGet - gget value from far space                    */
8874 /*-----------------------------------------------------------------*/
8875 static void
8876 genFarPointerGet (operand * left,
8877                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8878 {
8879   int size, offset;
8880   sym_link *retype = getSpec (operandType (result));
8881
8882   D(emitcode (";     genFarPointerGet",""));
8883
8884   aopOp (left, ic, FALSE);
8885   loadDptrFromOperand (left, FALSE);
8886
8887   /* so dptr now contains the address */
8888   aopOp (result, ic, FALSE);
8889
8890   /* if bit then unpack */
8891   if (IS_BITFIELD (retype))
8892     genUnpackBits (result, "dptr", FPOINTER, ifx);
8893   else
8894     {
8895       size = AOP_SIZE (result);
8896       offset = 0;
8897
8898       while (size--)
8899         {
8900           emitcode ("movx", "a,@dptr");
8901           if (!ifx)
8902             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8903           if (size || pi)
8904             emitcode ("inc", "dptr");
8905         }
8906     }
8907
8908   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8909     {
8910     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
8911     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
8912     pi->generated = 1;
8913   }
8914
8915   if (ifx && !ifx->generated)
8916     {
8917       genIfxJump (ifx, "a", left, NULL, result);
8918     }
8919
8920   freeAsmop (left, NULL, ic, TRUE);
8921   freeAsmop (result, NULL, ic, TRUE);
8922 }
8923
8924 /*-----------------------------------------------------------------*/
8925 /* genCodePointerGet - gget value from code space                  */
8926 /*-----------------------------------------------------------------*/
8927 static void
8928 genCodePointerGet (operand * left,
8929                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8930 {
8931   int size, offset;
8932   sym_link *retype = getSpec (operandType (result));
8933
8934   D(emitcode (";     genCodePointerGet",""));
8935
8936   aopOp (left, ic, FALSE);
8937   loadDptrFromOperand (left, FALSE);
8938
8939   /* so dptr now contains the address */
8940   aopOp (result, ic, FALSE);
8941
8942   /* if bit then unpack */
8943   if (IS_BITFIELD (retype))
8944     genUnpackBits (result, "dptr", CPOINTER, ifx);
8945   else
8946     {
8947       size = AOP_SIZE (result);
8948       offset = 0;
8949
8950       while (size--)
8951         {
8952           if (pi)
8953             {
8954               emitcode ("clr", "a");
8955               emitcode ("movc", "a,@a+dptr");
8956               if (!ifx)
8957               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8958               emitcode ("inc", "dptr");
8959             }
8960           else
8961             {
8962               emitcode ("mov", "a,#0x%02x", offset);
8963               emitcode ("movc", "a,@a+dptr");
8964               if (!ifx)
8965               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8966             }
8967         }
8968     }
8969
8970   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8971     {
8972     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
8973     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
8974     pi->generated = 1;
8975   }
8976
8977   if (ifx && !ifx->generated)
8978     {
8979       genIfxJump (ifx, "a", left, NULL, result);
8980     }
8981
8982   freeAsmop (left, NULL, ic, TRUE);
8983   freeAsmop (result, NULL, ic, TRUE);
8984 }
8985
8986 /*-----------------------------------------------------------------*/
8987 /* genGenPointerGet - gget value from generic pointer space        */
8988 /*-----------------------------------------------------------------*/
8989 static void
8990 genGenPointerGet (operand * left,
8991                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8992 {
8993   int size, offset;
8994   sym_link *retype = getSpec (operandType (result));
8995
8996   D(emitcode (";     genGenPointerGet",""));
8997
8998   aopOp (left, ic, FALSE);
8999   loadDptrFromOperand (left, TRUE);
9000
9001   /* so dptr know contains the address */
9002   aopOp (result, ic, FALSE);
9003
9004   /* if bit then unpack */
9005   if (IS_BITFIELD (retype))
9006     genUnpackBits (result, "dptr", GPOINTER, ifx);
9007   else
9008     {
9009       size = AOP_SIZE (result);
9010       offset = 0;
9011
9012       while (size--)
9013         {
9014           emitcode ("lcall", "__gptrget");
9015           if (!ifx)
9016           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9017           if (size || pi)
9018             emitcode ("inc", "dptr");
9019         }
9020     }
9021
9022   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9023     {
9024     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9025     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9026     pi->generated = 1;
9027   }
9028
9029   if (ifx && !ifx->generated)
9030     {
9031       genIfxJump (ifx, "a", left, NULL, result);
9032     }
9033
9034
9035   freeAsmop (left, NULL, ic, TRUE);
9036   freeAsmop (result, NULL, ic, TRUE);
9037 }
9038
9039 /*-----------------------------------------------------------------*/
9040 /* genPointerGet - generate code for pointer get                   */
9041 /*-----------------------------------------------------------------*/
9042 static void
9043 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9044 {
9045   operand *left, *result;
9046   sym_link *type, *etype;
9047   int p_type;
9048
9049   D(emitcode (";     genPointerGet",""));
9050
9051   left = IC_LEFT (ic);
9052   result = IC_RESULT (ic);
9053
9054   if (getSize (operandType (result))>1)
9055     ifx = NULL;
9056
9057   /* depending on the type of pointer we need to
9058      move it to the correct pointer register */
9059   type = operandType (left);
9060   etype = getSpec (type);
9061   /* if left is of type of pointer then it is simple */
9062   if (IS_PTR (type) && !IS_FUNC (type->next))
9063     p_type = DCL_TYPE (type);
9064   else
9065     {
9066       /* we have to go by the storage class */
9067       p_type = PTR_TYPE (SPEC_OCLS (etype));
9068     }
9069
9070   /* special case when cast remat */
9071   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9072       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9073           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9074           type = operandType (left);
9075           p_type = DCL_TYPE (type);
9076   }
9077   /* now that we have the pointer type we assign
9078      the pointer values */
9079   switch (p_type)
9080     {
9081
9082     case POINTER:
9083     case IPOINTER:
9084       genNearPointerGet (left, result, ic, pi, ifx);
9085       break;
9086
9087     case PPOINTER:
9088       genPagedPointerGet (left, result, ic, pi, ifx);
9089       break;
9090
9091     case FPOINTER:
9092       genFarPointerGet (left, result, ic, pi, ifx);
9093       break;
9094
9095     case CPOINTER:
9096       genCodePointerGet (left, result, ic, pi, ifx);
9097       break;
9098
9099     case GPOINTER:
9100       genGenPointerGet (left, result, ic, pi, ifx);
9101       break;
9102     }
9103
9104 }
9105
9106
9107
9108 /*-----------------------------------------------------------------*/
9109 /* genPackBits - generates code for packed bit storage             */
9110 /*-----------------------------------------------------------------*/
9111 static void
9112 genPackBits (sym_link * etype,
9113              operand * right,
9114              char *rname, int p_type)
9115 {
9116   int offset = 0;       /* source byte offset */
9117   int rlen = 0;         /* remaining bitfield length */
9118   int blen;             /* bitfield length */
9119   int bstr;             /* bitfield starting bit within byte */
9120   int litval;           /* source literal value (if AOP_LIT) */
9121   unsigned char mask;   /* bitmask within current byte */
9122
9123   D(emitcode (";     genPackBits",""));
9124
9125   blen = SPEC_BLEN (etype);
9126   bstr = SPEC_BSTR (etype);
9127
9128   /* If the bitfield length is less than a byte */
9129   if (blen < 8)
9130     {
9131       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9132               (unsigned char) (0xFF >> (8 - bstr)));
9133
9134       if (AOP_TYPE (right) == AOP_LIT)
9135         {
9136           /* Case with a bitfield length <8 and literal source
9137           */
9138           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9139           litval <<= bstr;
9140           litval &= (~mask) & 0xff;
9141           emitPtrByteGet (rname, p_type, FALSE);
9142           if ((mask|litval)!=0xff)
9143             emitcode ("anl","a,#0x%02x", mask);
9144           if (litval)
9145             emitcode ("orl","a,#0x%02x", litval);
9146         }
9147       else
9148         {
9149           if ((blen==1) && (p_type!=GPOINTER))
9150             {
9151               /* Case with a bitfield length == 1 and no generic pointer
9152               */
9153               if (AOP_TYPE (right) == AOP_CRY)
9154                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9155               else
9156                 {
9157                   MOVA (aopGet (right, 0, FALSE, FALSE));
9158                   emitcode ("rrc","a");
9159                 }
9160               emitPtrByteGet (rname, p_type, FALSE);
9161               emitcode ("mov","acc.%d,c",bstr);
9162             }
9163           else
9164             {
9165               bool pushedB;
9166               /* Case with a bitfield length < 8 and arbitrary source
9167               */
9168               MOVA (aopGet (right, 0, FALSE, FALSE));
9169               /* shift and mask source value */
9170               AccLsh (bstr);
9171               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9172
9173               pushedB = pushB ();
9174               /* transfer A to B and get next byte */
9175               emitPtrByteGet (rname, p_type, TRUE);
9176
9177               emitcode ("anl", "a,#0x%02x", mask);
9178               emitcode ("orl", "a,b");
9179               if (p_type == GPOINTER)
9180                 emitcode ("pop", "b");
9181
9182               popB (pushedB);
9183            }
9184         }
9185
9186       emitPtrByteSet (rname, p_type, "a");
9187       return;
9188     }
9189
9190   /* Bit length is greater than 7 bits. In this case, copy  */
9191   /* all except the partial byte at the end                 */
9192   for (rlen=blen;rlen>=8;rlen-=8)
9193     {
9194       emitPtrByteSet (rname, p_type,
9195                       aopGet (right, offset++, FALSE, TRUE) );
9196       if (rlen>8)
9197         emitcode ("inc", "%s", rname);
9198     }
9199
9200   /* If there was a partial byte at the end */
9201   if (rlen)
9202     {
9203       mask = (((unsigned char) -1 << rlen) & 0xff);
9204
9205       if (AOP_TYPE (right) == AOP_LIT)
9206         {
9207           /* Case with partial byte and literal source
9208           */
9209           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9210           litval >>= (blen-rlen);
9211           litval &= (~mask) & 0xff;
9212           emitPtrByteGet (rname, p_type, FALSE);
9213           if ((mask|litval)!=0xff)
9214             emitcode ("anl","a,#0x%02x", mask);
9215           if (litval)
9216             emitcode ("orl","a,#0x%02x", litval);
9217         }
9218       else
9219         {
9220           bool pushedB;
9221           /* Case with partial byte and arbitrary source
9222           */
9223           MOVA (aopGet (right, offset++, FALSE, FALSE));
9224           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9225
9226           pushedB = pushB ();
9227           /* transfer A to B and get next byte */
9228           emitPtrByteGet (rname, p_type, TRUE);
9229
9230           emitcode ("anl", "a,#0x%02x", mask);
9231           emitcode ("orl", "a,b");
9232           if (p_type == GPOINTER)
9233             emitcode ("pop", "b");
9234
9235           popB (pushedB);
9236         }
9237       emitPtrByteSet (rname, p_type, "a");
9238     }
9239
9240 }
9241
9242
9243 /*-----------------------------------------------------------------*/
9244 /* genDataPointerSet - remat pointer to data space                 */
9245 /*-----------------------------------------------------------------*/
9246 static void
9247 genDataPointerSet (operand * right,
9248                    operand * result,
9249                    iCode * ic)
9250 {
9251   int size, offset = 0;
9252   char *l, buffer[256];
9253
9254   D(emitcode (";     genDataPointerSet",""));
9255
9256   aopOp (right, ic, FALSE);
9257
9258   l = aopGet (result, 0, FALSE, TRUE);
9259   size = AOP_SIZE (right);
9260   while (size--)
9261     {
9262       if (offset)
9263         sprintf (buffer, "(%s + %d)", l + 1, offset);
9264       else
9265         sprintf (buffer, "%s", l + 1);
9266       emitcode ("mov", "%s,%s", buffer,
9267                 aopGet (right, offset++, FALSE, FALSE));
9268     }
9269
9270   freeAsmop (right, NULL, ic, TRUE);
9271   freeAsmop (result, NULL, ic, TRUE);
9272 }
9273
9274 /*-----------------------------------------------------------------*/
9275 /* genNearPointerSet - emitcode for near pointer put                */
9276 /*-----------------------------------------------------------------*/
9277 static void
9278 genNearPointerSet (operand * right,
9279                    operand * result,
9280                    iCode * ic,
9281                    iCode * pi)
9282 {
9283   asmop *aop = NULL;
9284   regs *preg = NULL;
9285   char *rname, *l;
9286   sym_link *retype, *letype;
9287   sym_link *ptype = operandType (result);
9288
9289   D(emitcode (";     genNearPointerSet",""));
9290
9291   retype = getSpec (operandType (right));
9292   letype = getSpec (ptype);
9293   aopOp (result, ic, FALSE);
9294
9295   /* if the result is rematerializable &
9296      in data space & not a bit variable */
9297   if (AOP_TYPE (result) == AOP_IMMD &&
9298       DCL_TYPE (ptype) == POINTER &&
9299       !IS_BITVAR (retype) &&
9300       !IS_BITVAR (letype))
9301     {
9302       genDataPointerSet (right, result, ic);
9303       return;
9304     }
9305
9306   /* if the value is already in a pointer register
9307      then don't need anything more */
9308   if (!AOP_INPREG (AOP (result)))
9309     {
9310         if (
9311             //AOP_TYPE (result) == AOP_STK
9312             IS_AOP_PREG(result)
9313             )
9314         {
9315             // Aha, it is a pointer, just in disguise.
9316             rname = aopGet (result, 0, FALSE, FALSE);
9317             if (*rname != '@')
9318             {
9319                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9320                         __FILE__, __LINE__);
9321             }
9322             else
9323             {
9324                 // Expected case.
9325                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9326                 rname++;  // skip the '@'.
9327             }
9328         }
9329         else
9330         {
9331             /* otherwise get a free pointer register */
9332             aop = newAsmop (0);
9333             preg = getFreePtr (ic, &aop, FALSE);
9334             emitcode ("mov", "%s,%s",
9335                       preg->name,
9336                       aopGet (result, 0, FALSE, TRUE));
9337             rname = preg->name;
9338         }
9339     }
9340     else
9341     {
9342         rname = aopGet (result, 0, FALSE, FALSE);
9343     }
9344
9345   aopOp (right, ic, FALSE);
9346
9347   /* if bitfield then unpack the bits */
9348   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9349     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9350   else
9351     {
9352       /* we have can just get the values */
9353       int size = AOP_SIZE (right);
9354       int offset = 0;
9355
9356       while (size--)
9357         {
9358           l = aopGet (right, offset, FALSE, TRUE);
9359           if (*l == '@')
9360             {
9361               MOVA (l);
9362               emitcode ("mov", "@%s,a", rname);
9363             }
9364           else
9365             emitcode ("mov", "@%s,%s", rname, l);
9366           if (size || pi)
9367             emitcode ("inc", "%s", rname);
9368           offset++;
9369         }
9370     }
9371
9372   /* now some housekeeping stuff */
9373   if (aop) /* we had to allocate for this iCode */
9374     {
9375       if (pi)
9376         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9377       freeAsmop (NULL, aop, ic, TRUE);
9378     }
9379   else
9380     {
9381       /* we did not allocate which means left
9382          already in a pointer register, then
9383          if size > 0 && this could be used again
9384          we have to point it back to where it
9385          belongs */
9386       if ((AOP_SIZE (right) > 1 &&
9387            !OP_SYMBOL (result)->remat &&
9388            (OP_SYMBOL (result)->liveTo > ic->seq ||
9389             ic->depth)) &&
9390           !pi)
9391         {
9392           int size = AOP_SIZE (right) - 1;
9393           while (size--)
9394             emitcode ("dec", "%s", rname);
9395         }
9396     }
9397
9398   /* done */
9399   if (pi) pi->generated = 1;
9400   freeAsmop (result, NULL, ic, TRUE);
9401   freeAsmop (right, NULL, ic, TRUE);
9402 }
9403
9404 /*-----------------------------------------------------------------*/
9405 /* genPagedPointerSet - emitcode for Paged pointer put             */
9406 /*-----------------------------------------------------------------*/
9407 static void
9408 genPagedPointerSet (operand * right,
9409                     operand * result,
9410                     iCode * ic,
9411                     iCode * pi)
9412 {
9413   asmop *aop = NULL;
9414   regs *preg = NULL;
9415   char *rname, *l;
9416   sym_link *retype, *letype;
9417
9418   D(emitcode (";     genPagedPointerSet",""));
9419
9420   retype = getSpec (operandType (right));
9421   letype = getSpec (operandType (result));
9422
9423   aopOp (result, ic, FALSE);
9424
9425   /* if the value is already in a pointer register
9426      then don't need anything more */
9427   if (!AOP_INPREG (AOP (result)))
9428     {
9429       /* otherwise get a free pointer register */
9430       aop = newAsmop (0);
9431       preg = getFreePtr (ic, &aop, FALSE);
9432       emitcode ("mov", "%s,%s",
9433                 preg->name,
9434                 aopGet (result, 0, FALSE, TRUE));
9435       rname = preg->name;
9436     }
9437   else
9438     rname = aopGet (result, 0, FALSE, FALSE);
9439
9440   aopOp (right, ic, FALSE);
9441
9442   /* if bitfield then unpack the bits */
9443   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9444     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9445   else
9446     {
9447       /* we have can just get the values */
9448       int size = AOP_SIZE (right);
9449       int offset = 0;
9450
9451       while (size--)
9452         {
9453           l = aopGet (right, offset, FALSE, TRUE);
9454
9455           MOVA (l);
9456           emitcode ("movx", "@%s,a", rname);
9457
9458           if (size || pi)
9459             emitcode ("inc", "%s", rname);
9460
9461           offset++;
9462         }
9463     }
9464
9465   /* now some housekeeping stuff */
9466   if (aop) /* we had to allocate for this iCode */
9467     {
9468       if (pi)
9469         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9470       freeAsmop (NULL, aop, ic, TRUE);
9471     }
9472   else
9473     {
9474       /* we did not allocate which means left
9475          already in a pointer register, then
9476          if size > 0 && this could be used again
9477          we have to point it back to where it
9478          belongs */
9479       if (AOP_SIZE (right) > 1 &&
9480           !OP_SYMBOL (result)->remat &&
9481           (OP_SYMBOL (result)->liveTo > ic->seq ||
9482            ic->depth))
9483         {
9484           int size = AOP_SIZE (right) - 1;
9485           while (size--)
9486             emitcode ("dec", "%s", rname);
9487         }
9488     }
9489
9490   /* done */
9491   if (pi) pi->generated = 1;
9492   freeAsmop (result, NULL, ic, TRUE);
9493   freeAsmop (right, NULL, ic, TRUE);
9494
9495
9496 }
9497
9498 /*-----------------------------------------------------------------*/
9499 /* genFarPointerSet - set value from far space                     */
9500 /*-----------------------------------------------------------------*/
9501 static void
9502 genFarPointerSet (operand * right,
9503                   operand * result, iCode * ic, iCode * pi)
9504 {
9505   int size, offset;
9506   sym_link *retype = getSpec (operandType (right));
9507   sym_link *letype = getSpec (operandType (result));
9508
9509   D(emitcode (";     genFarPointerSet",""));
9510
9511   aopOp (result, ic, FALSE);
9512   loadDptrFromOperand (result, FALSE);
9513
9514   /* so dptr know contains the address */
9515   aopOp (right, ic, FALSE);
9516
9517   /* if bit then unpack */
9518   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9519     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9520   else
9521     {
9522       size = AOP_SIZE (right);
9523       offset = 0;
9524
9525       while (size--)
9526         {
9527           char *l = aopGet (right, offset++, FALSE, FALSE);
9528           MOVA (l);
9529           emitcode ("movx", "@dptr,a");
9530           if (size || pi)
9531             emitcode ("inc", "dptr");
9532         }
9533     }
9534   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9535     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9536     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9537     pi->generated=1;
9538   }
9539   freeAsmop (result, NULL, ic, TRUE);
9540   freeAsmop (right, NULL, ic, TRUE);
9541 }
9542
9543 /*-----------------------------------------------------------------*/
9544 /* genGenPointerSet - set value from generic pointer space         */
9545 /*-----------------------------------------------------------------*/
9546 static void
9547 genGenPointerSet (operand * right,
9548                   operand * result, iCode * ic, iCode * pi)
9549 {
9550   int size, offset;
9551   sym_link *retype = getSpec (operandType (right));
9552   sym_link *letype = getSpec (operandType (result));
9553
9554   D(emitcode (";     genGenPointerSet",""));
9555
9556   aopOp (result, ic, FALSE);
9557   loadDptrFromOperand (result, TRUE);
9558
9559   /* so dptr know contains the address */
9560   aopOp (right, ic, FALSE);
9561
9562   /* if bit then unpack */
9563   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9564     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9565   else
9566     {
9567       size = AOP_SIZE (right);
9568       offset = 0;
9569
9570       while (size--)
9571         {
9572           char *l = aopGet (right, offset++, FALSE, FALSE);
9573           MOVA (l);
9574           emitcode ("lcall", "__gptrput");
9575           if (size || pi)
9576             emitcode ("inc", "dptr");
9577         }
9578     }
9579
9580   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9581     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9582     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9583     pi->generated=1;
9584   }
9585   freeAsmop (result, NULL, ic, TRUE);
9586   freeAsmop (right, NULL, ic, TRUE);
9587 }
9588
9589 /*-----------------------------------------------------------------*/
9590 /* genPointerSet - stores the value into a pointer location        */
9591 /*-----------------------------------------------------------------*/
9592 static void
9593 genPointerSet (iCode * ic, iCode *pi)
9594 {
9595   operand *right, *result;
9596   sym_link *type, *etype;
9597   int p_type;
9598
9599   D(emitcode (";     genPointerSet",""));
9600
9601   right = IC_RIGHT (ic);
9602   result = IC_RESULT (ic);
9603
9604   /* depending on the type of pointer we need to
9605      move it to the correct pointer register */
9606   type = operandType (result);
9607   etype = getSpec (type);
9608   /* if left is of type of pointer then it is simple */
9609   if (IS_PTR (type) && !IS_FUNC (type->next))
9610     {
9611       p_type = DCL_TYPE (type);
9612     }
9613   else
9614     {
9615       /* we have to go by the storage class */
9616       p_type = PTR_TYPE (SPEC_OCLS (etype));
9617     }
9618
9619   /* special case when cast remat */
9620   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9621       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9622           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9623           type = operandType (result);
9624           p_type = DCL_TYPE (type);
9625   }
9626   /* now that we have the pointer type we assign
9627      the pointer values */
9628   switch (p_type)
9629     {
9630
9631     case POINTER:
9632     case IPOINTER:
9633       genNearPointerSet (right, result, ic, pi);
9634       break;
9635
9636     case PPOINTER:
9637       genPagedPointerSet (right, result, ic, pi);
9638       break;
9639
9640     case FPOINTER:
9641       genFarPointerSet (right, result, ic, pi);
9642       break;
9643
9644     case GPOINTER:
9645       genGenPointerSet (right, result, ic, pi);
9646       break;
9647
9648     default:
9649       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9650               "genPointerSet: illegal pointer type");
9651     }
9652
9653 }
9654
9655 /*-----------------------------------------------------------------*/
9656 /* genIfx - generate code for Ifx statement                        */
9657 /*-----------------------------------------------------------------*/
9658 static void
9659 genIfx (iCode * ic, iCode * popIc)
9660 {
9661   operand *cond = IC_COND (ic);
9662   int isbit = 0;
9663
9664   D(emitcode (";     genIfx",""));
9665
9666   aopOp (cond, ic, FALSE);
9667
9668   /* get the value into acc */
9669   if (AOP_TYPE (cond) != AOP_CRY)
9670     toBoolean (cond);
9671   else
9672     isbit = 1;
9673   /* the result is now in the accumulator */
9674   freeAsmop (cond, NULL, ic, TRUE);
9675
9676   /* if there was something to be popped then do it */
9677   if (popIc)
9678     genIpop (popIc);
9679
9680   /* if the condition is a bit variable */
9681   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9682     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9683   else if (isbit && !IS_ITEMP (cond))
9684     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9685   else
9686     genIfxJump (ic, "a", NULL, NULL, NULL);
9687
9688   ic->generated = 1;
9689 }
9690
9691 /*-----------------------------------------------------------------*/
9692 /* genAddrOf - generates code for address of                       */
9693 /*-----------------------------------------------------------------*/
9694 static void
9695 genAddrOf (iCode * ic)
9696 {
9697   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9698   int size, offset;
9699
9700   D(emitcode (";     genAddrOf",""));
9701
9702   aopOp (IC_RESULT (ic), ic, FALSE);
9703
9704   /* if the operand is on the stack then we
9705      need to get the stack offset of this
9706      variable */
9707   if (sym->onStack)
9708     {
9709       /* if it has an offset then we need to compute
9710          it */
9711       if (sym->stack)
9712         {
9713           emitcode ("mov", "a,%s", SYM_BP (sym));
9714           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9715                                          ((char) (sym->stack - _G.nRegsSaved)) :
9716                                          ((char) sym->stack)) & 0xff);
9717           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9718         }
9719       else
9720         {
9721           /* we can just move _bp */
9722           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9723         }
9724       /* fill the result with zero */
9725       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9726
9727       offset = 1;
9728       while (size--)
9729         {
9730           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9731         }
9732
9733       goto release;
9734     }
9735
9736   /* object not on stack then we need the name */
9737   size = AOP_SIZE (IC_RESULT (ic));
9738   offset = 0;
9739
9740   while (size--)
9741     {
9742       char s[SDCC_NAME_MAX];
9743       if (offset)
9744         sprintf (s, "#(%s >> %d)",
9745                  sym->rname,
9746                  offset * 8);
9747       else
9748         sprintf (s, "#%s", sym->rname);
9749       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9750     }
9751
9752 release:
9753   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9754
9755 }
9756
9757 /*-----------------------------------------------------------------*/
9758 /* genFarFarAssign - assignment when both are in far space         */
9759 /*-----------------------------------------------------------------*/
9760 static void
9761 genFarFarAssign (operand * result, operand * right, iCode * ic)
9762 {
9763   int size = AOP_SIZE (right);
9764   int offset = 0;
9765   char *l;
9766
9767   D(emitcode (";     genFarFarAssign",""));
9768
9769   /* first push the right side on to the stack */
9770   while (size--)
9771     {
9772       l = aopGet (right, offset++, FALSE, FALSE);
9773       MOVA (l);
9774       emitcode ("push", "acc");
9775     }
9776
9777   freeAsmop (right, NULL, ic, FALSE);
9778   /* now assign DPTR to result */
9779   aopOp (result, ic, FALSE);
9780   size = AOP_SIZE (result);
9781   while (size--)
9782     {
9783       emitcode ("pop", "acc");
9784       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
9785     }
9786   freeAsmop (result, NULL, ic, FALSE);
9787
9788 }
9789
9790 /*-----------------------------------------------------------------*/
9791 /* genAssign - generate code for assignment                        */
9792 /*-----------------------------------------------------------------*/
9793 static void
9794 genAssign (iCode * ic)
9795 {
9796   operand *result, *right;
9797   int size, offset;
9798   unsigned long lit = 0L;
9799
9800   D(emitcode(";     genAssign",""));
9801
9802   result = IC_RESULT (ic);
9803   right = IC_RIGHT (ic);
9804
9805   /* if they are the same */
9806   if (operandsEqu (result, right) &&
9807       !isOperandVolatile (result, FALSE) &&
9808       !isOperandVolatile (right, FALSE))
9809     return;
9810
9811   aopOp (right, ic, FALSE);
9812
9813   /* special case both in far space */
9814   if (AOP_TYPE (right) == AOP_DPTR &&
9815       IS_TRUE_SYMOP (result) &&
9816       isOperandInFarSpace (result))
9817     {
9818
9819       genFarFarAssign (result, right, ic);
9820       return;
9821     }
9822
9823   aopOp (result, ic, TRUE);
9824
9825   /* if they are the same registers */
9826   if (sameRegs (AOP (right), AOP (result)) &&
9827       !isOperandVolatile (result, FALSE) &&
9828       !isOperandVolatile (right, FALSE))
9829     goto release;
9830
9831   /* if the result is a bit */
9832   if (AOP_TYPE (result) == AOP_CRY)
9833     {
9834
9835       /* if the right size is a literal then
9836          we know what the value is */
9837       if (AOP_TYPE (right) == AOP_LIT)
9838         {
9839           if (((int) operandLitValue (right)))
9840             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
9841           else
9842             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
9843           goto release;
9844         }
9845
9846       /* the right is also a bit variable */
9847       if (AOP_TYPE (right) == AOP_CRY)
9848         {
9849           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9850           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
9851           goto release;
9852         }
9853
9854       /* we need to or */
9855       toBoolean (right);
9856       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9857       goto release;
9858     }
9859
9860   /* bit variables done */
9861   /* general case */
9862   size = AOP_SIZE (result);
9863   offset = 0;
9864   if (AOP_TYPE (right) == AOP_LIT)
9865     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9866   if ((size > 1) &&
9867       (AOP_TYPE (result) != AOP_REG) &&
9868       (AOP_TYPE (right) == AOP_LIT) &&
9869       !IS_FLOAT (operandType (right)) &&
9870       (lit < 256L))
9871     {
9872       while ((size) && (lit))
9873         {
9874           aopPut (result,
9875                   aopGet (right, offset, FALSE, FALSE),
9876                   offset,
9877                   isOperandVolatile (result, FALSE));
9878           lit >>= 8;
9879           offset++;
9880           size--;
9881         }
9882       emitcode ("clr", "a");
9883       while (size--)
9884         {
9885           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9886           offset++;
9887         }
9888     }
9889   else
9890     {
9891       while (size--)
9892         {
9893           aopPut (result,
9894                   aopGet (right, offset, FALSE, FALSE),
9895                   offset,
9896                   isOperandVolatile (result, FALSE));
9897           offset++;
9898         }
9899     }
9900
9901 release:
9902   freeAsmop (right, NULL, ic, TRUE);
9903   freeAsmop (result, NULL, ic, TRUE);
9904 }
9905
9906 /*-----------------------------------------------------------------*/
9907 /* genJumpTab - generates code for jump table                      */
9908 /*-----------------------------------------------------------------*/
9909 static void
9910 genJumpTab (iCode * ic)
9911 {
9912   symbol *jtab,*jtablo,*jtabhi;
9913   char *l;
9914   unsigned int count;
9915
9916   D(emitcode (";     genJumpTab",""));
9917
9918   count = elementsInSet( IC_JTLABELS (ic) );
9919
9920   if( count <= 16 )
9921     {
9922       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9923          if the switch argument is in a register.
9924          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9925       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9926          How will multiply by three be updated ???*/
9927       aopOp (IC_JTCOND (ic), ic, FALSE);
9928       /* get the condition into accumulator */
9929       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
9930       MOVA (l);
9931       /* multiply by three */
9932       emitcode ("add", "a,acc");
9933       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
9934       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9935
9936       jtab = newiTempLabel (NULL);
9937       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9938       emitcode ("jmp", "@a+dptr");
9939       emitcode ("", "%05d$:", jtab->key + 100);
9940       /* now generate the jump labels */
9941       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9942            jtab = setNextItem (IC_JTLABELS (ic)))
9943         emitcode ("ljmp", "%05d$", jtab->key + 100);
9944     }
9945   else
9946     {
9947       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9948          if the switch argument is in a register.
9949          For n>6 this algorithm may be more compact */
9950       jtablo = newiTempLabel (NULL);
9951       jtabhi = newiTempLabel (NULL);
9952
9953       /* get the condition into accumulator.
9954          Using b as temporary storage, if register push/pop is needed */
9955       aopOp (IC_JTCOND (ic), ic, FALSE);
9956       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
9957       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9958           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9959         {
9960           // (MB) what if B is in use???
9961           wassertl(!BINUSE, "B was in use");
9962           emitcode ("mov", "b,%s", l);
9963           l = "b";
9964         }
9965       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9966       MOVA (l);
9967       if( count <= 112 )
9968         {
9969           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9970           emitcode ("movc", "a,@a+pc");
9971           emitcode ("push", "acc");
9972
9973           MOVA (l);
9974           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9975           emitcode ("movc", "a,@a+pc");
9976           emitcode ("push", "acc");
9977         }
9978       else
9979         {
9980           /* this scales up to n<=255, but needs two more bytes
9981              and changes dptr */
9982           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9983           emitcode ("movc", "a,@a+dptr");
9984           emitcode ("push", "acc");
9985
9986           MOVA (l);
9987           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9988           emitcode ("movc", "a,@a+dptr");
9989           emitcode ("push", "acc");
9990         }
9991
9992       emitcode ("ret", "");
9993
9994       /* now generate jump table, LSB */
9995       emitcode ("", "%05d$:", jtablo->key + 100);
9996       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9997            jtab = setNextItem (IC_JTLABELS (ic)))
9998         emitcode (".db", "%05d$", jtab->key + 100);
9999
10000       /* now generate jump table, MSB */
10001       emitcode ("", "%05d$:", jtabhi->key + 100);
10002       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10003            jtab = setNextItem (IC_JTLABELS (ic)))
10004          emitcode (".db", "%05d$>>8", jtab->key + 100);
10005     }
10006 }
10007
10008 /*-----------------------------------------------------------------*/
10009 /* genCast - gen code for casting                                  */
10010 /*-----------------------------------------------------------------*/
10011 static void
10012 genCast (iCode * ic)
10013 {
10014   operand *result = IC_RESULT (ic);
10015   sym_link *ctype = operandType (IC_LEFT (ic));
10016   sym_link *rtype = operandType (IC_RIGHT (ic));
10017   operand *right = IC_RIGHT (ic);
10018   int size, offset;
10019
10020   D(emitcode(";     genCast",""));
10021
10022   /* if they are equivalent then do nothing */
10023   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10024     return;
10025
10026   aopOp (right, ic, FALSE);
10027   aopOp (result, ic, FALSE);
10028
10029   /* if the result is a bit (and not a bitfield) */
10030   // if (AOP_TYPE (result) == AOP_CRY)
10031   if (IS_BITVAR (OP_SYMBOL (result)->type)
10032       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10033     {
10034       /* if the right size is a literal then
10035          we know what the value is */
10036       if (AOP_TYPE (right) == AOP_LIT)
10037         {
10038           if (((int) operandLitValue (right)))
10039             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10040           else
10041             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10042
10043           goto release;
10044         }
10045
10046       /* the right is also a bit variable */
10047       if (AOP_TYPE (right) == AOP_CRY)
10048         {
10049           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10050           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10051           goto release;
10052         }
10053
10054       /* we need to or */
10055       toBoolean (right);
10056       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10057       goto release;
10058     }
10059
10060
10061   /* if they are the same size : or less */
10062   if (AOP_SIZE (result) <= AOP_SIZE (right))
10063     {
10064
10065       /* if they are in the same place */
10066       if (sameRegs (AOP (right), AOP (result)))
10067         goto release;
10068
10069       /* if they in different places then copy */
10070       size = AOP_SIZE (result);
10071       offset = 0;
10072       while (size--)
10073         {
10074           aopPut (result,
10075                   aopGet (right, offset, FALSE, FALSE),
10076                   offset,
10077                   isOperandVolatile (result, FALSE));
10078           offset++;
10079         }
10080       goto release;
10081     }
10082
10083
10084   /* if the result is of type pointer */
10085   if (IS_PTR (ctype))
10086     {
10087
10088       int p_type;
10089       sym_link *type = operandType (right);
10090       sym_link *etype = getSpec (type);
10091
10092       /* pointer to generic pointer */
10093       if (IS_GENPTR (ctype))
10094         {
10095           if (IS_PTR (type))
10096             p_type = DCL_TYPE (type);
10097           else
10098             {
10099               if (SPEC_SCLS(etype)==S_REGISTER) {
10100                 // let's assume it is a generic pointer
10101                 p_type=GPOINTER;
10102               } else {
10103                 /* we have to go by the storage class */
10104                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10105               }
10106             }
10107
10108           /* the first two bytes are known */
10109           size = GPTRSIZE - 1;
10110           offset = 0;
10111           while (size--)
10112             {
10113               aopPut (result,
10114                       aopGet (right, offset, FALSE, FALSE),
10115                       offset,
10116                       isOperandVolatile (result, FALSE));
10117               offset++;
10118             }
10119           /* the last byte depending on type */
10120             {
10121                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10122                 char gpValStr[10];
10123
10124                 if (gpVal == -1)
10125                 {
10126                     // pointerTypeToGPByte will have bitched.
10127                     exit(1);
10128                 }
10129
10130                 sprintf(gpValStr, "#0x%x", gpVal);
10131                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10132             }
10133           goto release;
10134         }
10135
10136       /* just copy the pointers */
10137       size = AOP_SIZE (result);
10138       offset = 0;
10139       while (size--)
10140         {
10141           aopPut (result,
10142                   aopGet (right, offset, FALSE, FALSE),
10143                   offset,
10144                   isOperandVolatile (result, FALSE));
10145           offset++;
10146         }
10147       goto release;
10148     }
10149
10150   /* so we now know that the size of destination is greater
10151      than the size of the source */
10152   /* we move to result for the size of source */
10153   size = AOP_SIZE (right);
10154   offset = 0;
10155   while (size--)
10156     {
10157       aopPut (result,
10158               aopGet (right, offset, FALSE, FALSE),
10159               offset,
10160               isOperandVolatile (result, FALSE));
10161       offset++;
10162     }
10163
10164   /* now depending on the sign of the source && destination */
10165   size = AOP_SIZE (result) - AOP_SIZE (right);
10166   /* if unsigned or not an integral type */
10167   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10168     {
10169       while (size--)
10170         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10171     }
10172   else
10173     {
10174       /* we need to extend the sign :{ */
10175       char *l = aopGet (right, AOP_SIZE (right) - 1,
10176                         FALSE, FALSE);
10177       MOVA (l);
10178       emitcode ("rlc", "a");
10179       emitcode ("subb", "a,acc");
10180       while (size--)
10181         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10182     }
10183
10184   /* we are done hurray !!!! */
10185
10186 release:
10187   freeAsmop (right, NULL, ic, TRUE);
10188   freeAsmop (result, NULL, ic, TRUE);
10189
10190 }
10191
10192 /*-----------------------------------------------------------------*/
10193 /* genDjnz - generate decrement & jump if not zero instrucion      */
10194 /*-----------------------------------------------------------------*/
10195 static int
10196 genDjnz (iCode * ic, iCode * ifx)
10197 {
10198   symbol *lbl, *lbl1;
10199   if (!ifx)
10200     return 0;
10201
10202   D(emitcode (";     genDjnz",""));
10203
10204   /* if the if condition has a false label
10205      then we cannot save */
10206   if (IC_FALSE (ifx))
10207     return 0;
10208
10209   /* if the minus is not of the form
10210      a = a - 1 */
10211   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10212       !IS_OP_LITERAL (IC_RIGHT (ic)))
10213     return 0;
10214
10215   if (operandLitValue (IC_RIGHT (ic)) != 1)
10216     return 0;
10217
10218   /* if the size of this greater than one then no
10219      saving */
10220   if (getSize (operandType (IC_RESULT (ic))) > 1)
10221     return 0;
10222
10223   /* otherwise we can save BIG */
10224   lbl = newiTempLabel (NULL);
10225   lbl1 = newiTempLabel (NULL);
10226
10227   aopOp (IC_RESULT (ic), ic, FALSE);
10228
10229   if (AOP_NEEDSACC(IC_RESULT(ic)))
10230   {
10231       /* If the result is accessed indirectly via
10232        * the accumulator, we must explicitly write
10233        * it back after the decrement.
10234        */
10235       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10236
10237       if (strcmp(rByte, "a"))
10238       {
10239            /* Something is hopelessly wrong */
10240            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10241                    __FILE__, __LINE__);
10242            /* We can just give up; the generated code will be inefficient,
10243             * but what the hey.
10244             */
10245            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10246            return 0;
10247       }
10248       emitcode ("dec", "%s", rByte);
10249       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10250       emitcode ("jnz", "%05d$", lbl->key + 100);
10251   }
10252   else if (IS_AOP_PREG (IC_RESULT (ic)))
10253     {
10254       emitcode ("dec", "%s",
10255                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10256       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10257       emitcode ("jnz", "%05d$", lbl->key + 100);
10258     }
10259   else
10260     {
10261       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10262                 lbl->key + 100);
10263     }
10264   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10265   emitcode ("", "%05d$:", lbl->key + 100);
10266   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10267   emitcode ("", "%05d$:", lbl1->key + 100);
10268
10269   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10270   ifx->generated = 1;
10271   return 1;
10272 }
10273
10274 /*-----------------------------------------------------------------*/
10275 /* genReceive - generate code for a receive iCode                  */
10276 /*-----------------------------------------------------------------*/
10277 static void
10278 genReceive (iCode * ic)
10279 {
10280     int size = getSize (operandType (IC_RESULT (ic)));
10281     int offset = 0;
10282   D(emitcode (";     genReceive",""));
10283
10284   if (ic->argreg == 1) { /* first parameter */
10285       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10286           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10287            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10288
10289           regs *tempRegs[4];
10290           int receivingA = 0;
10291           int roffset = 0;
10292
10293           for (offset = 0; offset<size; offset++)
10294             if (!strcmp (fReturn[offset], "a"))
10295               receivingA = 1;
10296
10297           if (!receivingA)
10298             {
10299               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10300                 {
10301                   for (offset = size-1; offset>0; offset--)
10302                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10303                   emitcode("mov","a,%s", fReturn[0]);
10304                   _G.accInUse++;
10305                   aopOp (IC_RESULT (ic), ic, FALSE);
10306                   _G.accInUse--;
10307                   aopPut (IC_RESULT (ic), "a", offset,
10308                           isOperandVolatile (IC_RESULT (ic), FALSE));
10309                   for (offset = 1; offset<size; offset++)
10310                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10311                             isOperandVolatile (IC_RESULT (ic), FALSE));
10312                   goto release;
10313                 }
10314             }
10315           else
10316             {
10317               if (getTempRegs(tempRegs, size, ic))
10318                 {
10319                   for (offset = 0; offset<size; offset++)
10320                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10321                   aopOp (IC_RESULT (ic), ic, FALSE);
10322                   for (offset = 0; offset<size; offset++)
10323                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10324                             isOperandVolatile (IC_RESULT (ic), FALSE));
10325                   goto release;
10326                 }
10327             }
10328
10329           offset = fReturnSizeMCS51 - size;
10330           while (size--) {
10331               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10332                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10333               offset++;
10334           }
10335           aopOp (IC_RESULT (ic), ic, FALSE);
10336           size = AOP_SIZE (IC_RESULT (ic));
10337           offset = 0;
10338           while (size--) {
10339               emitcode ("pop", "acc");
10340               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10341           }
10342
10343       } else {
10344           _G.accInUse++;
10345           aopOp (IC_RESULT (ic), ic, FALSE);
10346           _G.accInUse--;
10347           assignResultValue (IC_RESULT (ic));
10348       }
10349   } else { /* second receive onwards */
10350       int rb1off ;
10351       aopOp (IC_RESULT (ic), ic, FALSE);
10352       rb1off = ic->argreg;
10353       while (size--) {
10354           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10355       }
10356   }
10357
10358 release:
10359   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10360 }
10361
10362 /*-----------------------------------------------------------------*/
10363 /* genDummyRead - generate code for dummy read of volatiles        */
10364 /*-----------------------------------------------------------------*/
10365 static void
10366 genDummyRead (iCode * ic)
10367 {
10368   operand *op;
10369   int size, offset;
10370
10371   D(emitcode(";     genDummyRead",""));
10372
10373   op = IC_RIGHT (ic);
10374   if (op && IS_SYMOP (op))
10375     {
10376       aopOp (op, ic, FALSE);
10377
10378       /* if the result is a bit */
10379       if (AOP_TYPE (op) == AOP_CRY)
10380         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10381       else
10382         {
10383           /* bit variables done */
10384           /* general case */
10385           size = AOP_SIZE (op);
10386           offset = 0;
10387           while (size--)
10388           {
10389             MOVA (aopGet (op, offset, FALSE, FALSE));
10390             offset++;
10391           }
10392         }
10393
10394       freeAsmop (op, NULL, ic, TRUE);
10395     }
10396
10397   op = IC_LEFT (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
10422 /*-----------------------------------------------------------------*/
10423 /* genCritical - generate code for start of a critical sequence    */
10424 /*-----------------------------------------------------------------*/
10425 static void
10426 genCritical (iCode *ic)
10427 {
10428   symbol *tlbl = newiTempLabel (NULL);
10429
10430   D(emitcode(";     genCritical",""));
10431
10432   if (IC_RESULT (ic))
10433     {
10434       aopOp (IC_RESULT (ic), ic, TRUE);
10435       aopPut (IC_RESULT (ic), one, 0, 0);
10436       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10437       aopPut (IC_RESULT (ic), zero, 0, 0);
10438       emitcode ("", "%05d$:", (tlbl->key + 100));
10439       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10440     }
10441   else
10442     {
10443       emitcode ("setb", "c");
10444       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10445       emitcode ("clr", "c");
10446       emitcode ("", "%05d$:", (tlbl->key + 100));
10447       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10448     }
10449 }
10450
10451 /*-----------------------------------------------------------------*/
10452 /* genEndCritical - generate code for end of a critical sequence   */
10453 /*-----------------------------------------------------------------*/
10454 static void
10455 genEndCritical (iCode *ic)
10456 {
10457   D(emitcode(";     genEndCritical",""));
10458
10459   if (IC_RIGHT (ic))
10460     {
10461       aopOp (IC_RIGHT (ic), ic, FALSE);
10462       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10463         {
10464           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10465           emitcode ("mov", "ea,c");
10466         }
10467       else
10468         {
10469           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10470             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
10471           emitcode ("rrc", "a");
10472           emitcode ("mov", "ea,c");
10473         }
10474       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10475     }
10476   else
10477     {
10478       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10479       emitcode ("mov", "ea,c");
10480     }
10481 }
10482
10483 /*-----------------------------------------------------------------*/
10484 /* gen51Code - generate code for 8051 based controllers            */
10485 /*-----------------------------------------------------------------*/
10486 void
10487 gen51Code (iCode * lic)
10488 {
10489   iCode *ic;
10490   int cln = 0;
10491   /* int cseq = 0; */
10492
10493   _G.currentFunc = NULL;
10494   lineHead = lineCurr = NULL;
10495
10496   /* print the allocation information */
10497   if (allocInfo && currFunc)
10498     printAllocInfo (currFunc, codeOutFile);
10499   /* if debug information required */
10500   if (options.debug && currFunc)
10501     {
10502       debugFile->writeFunction (currFunc, lic);
10503     }
10504   /* stack pointer name */
10505   if (options.useXstack)
10506     spname = "_spx";
10507   else
10508     spname = "sp";
10509
10510
10511   for (ic = lic; ic; ic = ic->next)
10512     {
10513       _G.current_iCode = ic;
10514
10515       if (ic->lineno && cln != ic->lineno)
10516         {
10517           if (options.debug)
10518             {
10519               debugFile->writeCLine (ic);
10520             }
10521           if (!options.noCcodeInAsm) {
10522             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10523                       printCLine(ic->filename, ic->lineno));
10524           }
10525           cln = ic->lineno;
10526         }
10527       #if 0
10528       if (ic->seqPoint && ic->seqPoint != cseq)
10529         {
10530           emitcode ("", "; sequence point %d", ic->seqPoint);
10531           cseq = ic->seqPoint;
10532         }
10533       #endif
10534       if (options.iCodeInAsm) {
10535         char regsInUse[80];
10536         int i;
10537
10538         for (i=0; i<8; i++) {
10539           sprintf (&regsInUse[i],
10540                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10541         }
10542         regsInUse[i]=0;
10543         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10544       }
10545       /* if the result is marked as
10546          spilt and rematerializable or code for
10547          this has already been generated then
10548          do nothing */
10549       if (resultRemat (ic) || ic->generated)
10550         continue;
10551
10552       /* depending on the operation */
10553       switch (ic->op)
10554         {
10555         case '!':
10556           genNot (ic);
10557           break;
10558
10559         case '~':
10560           genCpl (ic);
10561           break;
10562
10563         case UNARYMINUS:
10564           genUminus (ic);
10565           break;
10566
10567         case IPUSH:
10568           genIpush (ic);
10569           break;
10570
10571         case IPOP:
10572           /* IPOP happens only when trying to restore a
10573              spilt live range, if there is an ifx statement
10574              following this pop then the if statement might
10575              be using some of the registers being popped which
10576              would destory the contents of the register so
10577              we need to check for this condition and handle it */
10578           if (ic->next &&
10579               ic->next->op == IFX &&
10580               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10581             genIfx (ic->next, ic);
10582           else
10583             genIpop (ic);
10584           break;
10585
10586         case CALL:
10587           genCall (ic);
10588           break;
10589
10590         case PCALL:
10591           genPcall (ic);
10592           break;
10593
10594         case FUNCTION:
10595           genFunction (ic);
10596           break;
10597
10598         case ENDFUNCTION:
10599           genEndFunction (ic);
10600           break;
10601
10602         case RETURN:
10603           genRet (ic);
10604           break;
10605
10606         case LABEL:
10607           genLabel (ic);
10608           break;
10609
10610         case GOTO:
10611           genGoto (ic);
10612           break;
10613
10614         case '+':
10615           genPlus (ic);
10616           break;
10617
10618         case '-':
10619           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10620             genMinus (ic);
10621           break;
10622
10623         case '*':
10624           genMult (ic);
10625           break;
10626
10627         case '/':
10628           genDiv (ic);
10629           break;
10630
10631         case '%':
10632           genMod (ic);
10633           break;
10634
10635         case '>':
10636           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10637           break;
10638
10639         case '<':
10640           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10641           break;
10642
10643         case LE_OP:
10644         case GE_OP:
10645         case NE_OP:
10646
10647           /* note these two are xlated by algebraic equivalence
10648              during parsing SDCC.y */
10649           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10650                   "got '>=' or '<=' shouldn't have come here");
10651           break;
10652
10653         case EQ_OP:
10654           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10655           break;
10656
10657         case AND_OP:
10658           genAndOp (ic);
10659           break;
10660
10661         case OR_OP:
10662           genOrOp (ic);
10663           break;
10664
10665         case '^':
10666           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10667           break;
10668
10669         case '|':
10670           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10671           break;
10672
10673         case BITWISEAND:
10674           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10675           break;
10676
10677         case INLINEASM:
10678           genInline (ic);
10679           break;
10680
10681         case RRC:
10682           genRRC (ic);
10683           break;
10684
10685         case RLC:
10686           genRLC (ic);
10687           break;
10688
10689         case GETHBIT:
10690           genGetHbit (ic);
10691           break;
10692
10693         case LEFT_OP:
10694           genLeftShift (ic);
10695           break;
10696
10697         case RIGHT_OP:
10698           genRightShift (ic);
10699           break;
10700
10701         case GET_VALUE_AT_ADDRESS:
10702           genPointerGet (ic,
10703                          hasInc (IC_LEFT (ic), ic,
10704                                  getSize (operandType (IC_RESULT (ic)))),
10705                          ifxForOp (IC_RESULT (ic), ic) );
10706           break;
10707
10708         case '=':
10709           if (POINTER_SET (ic))
10710             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10711           else
10712             genAssign (ic);
10713           break;
10714
10715         case IFX:
10716           genIfx (ic, NULL);
10717           break;
10718
10719         case ADDRESS_OF:
10720           genAddrOf (ic);
10721           break;
10722
10723         case JUMPTABLE:
10724           genJumpTab (ic);
10725           break;
10726
10727         case CAST:
10728           genCast (ic);
10729           break;
10730
10731         case RECEIVE:
10732           genReceive (ic);
10733           break;
10734
10735         case SEND:
10736           addSet (&_G.sendSet, ic);
10737           break;
10738
10739         case DUMMY_READ_VOLATILE:
10740           genDummyRead (ic);
10741           break;
10742
10743         case CRITICAL:
10744           genCritical (ic);
10745           break;
10746
10747         case ENDCRITICAL:
10748           genEndCritical (ic);
10749           break;
10750
10751         case SWAP:
10752           genSwap (ic);
10753           break;
10754
10755         default:
10756           ic = ic;
10757         }
10758     }
10759
10760   _G.current_iCode = NULL;
10761
10762   /* now we are ready to call the
10763      peep hole optimizer */
10764   if (!options.nopeep)
10765     peepHole (&lineHead);
10766
10767   /* now do the actual printing */
10768   printLine (lineHead, codeOutFile);
10769   return;
10770 }