891625a6c560fcf9b230de132b36a0d9d9f39fec
[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 char *aopLiteralLong (value * val, int offset, int size);
48 extern int allocInfo;
49
50 /* this is the down and dirty file with all kinds of
51    kludgy & hacky stuff. This is what it is all about
52    CODE GENERATION for a specific MCU . some of the
53    routines may be reusable, will have to see */
54
55 static char *zero = "#0x00";
56 static char *one = "#0x01";
57 static char *spname;
58
59 char *fReturn8051[] =
60 {"dpl", "dph", "b", "a"};
61 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
62 char **fReturn = fReturn8051;
63 static char *accUse[] =
64 {"a", "b"};
65
66 static unsigned short rbank = -1;
67
68 #define AOP(op) op->aop
69 #define AOP_TYPE(op) AOP(op)->type
70 #define AOP_SIZE(op) AOP(op)->size
71 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
72                        AOP_TYPE(x) == AOP_R0))
73
74 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
75                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
76
77 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
78                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
79                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
80
81
82 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
83
84 #define R0INB   _G.bu.bs.r0InB
85 #define R1INB   _G.bu.bs.r1InB
86 #define OPINB   _G.bu.bs.OpInB
87 #define BINUSE  _G.bu.BInUse
88
89 static struct
90   {
91     short r0Pushed;
92     short r1Pushed;
93     union
94       {
95         struct
96           {
97             short r0InB : 2;//2 so we can see it overflow
98             short r1InB : 2;//2 so we can see it overflow
99             short OpInB : 2;//2 so we can see it overflow
100           } bs;
101         short BInUse;
102       } bu;
103     short accInUse;
104     short inLine;
105     short debugLine;
106     short nRegsSaved;
107     set *sendSet;
108     iCode *current_iCode;
109     symbol *currentFunc;
110   }
111 _G;
112
113 static char *rb1regs[] = {
114     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
115 };
116
117 extern int mcs51_ptrRegReq;
118 extern int mcs51_nRegs;
119 extern FILE *codeOutFile;
120 static void saveRBank (int, iCode *, bool);
121
122 #define RESULTONSTACK(x) \
123                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
124                          IC_RESULT(x)->aop->type == AOP_STK )
125
126 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
127 #define CLRC     emitcode("clr","c")
128 #define SETC     emitcode("setb","c")
129
130 static lineNode *lineHead = NULL;
131 static lineNode *lineCurr = NULL;
132
133 static unsigned char SLMask[] =
134 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
135  0xE0, 0xC0, 0x80, 0x00};
136 static unsigned char SRMask[] =
137 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
138  0x07, 0x03, 0x01, 0x00};
139
140 #define LSB     0
141 #define MSB16   1
142 #define MSB24   2
143 #define MSB32   3
144
145 /*-----------------------------------------------------------------*/
146 /* emitcode - writes the code into a file : for now it is simple    */
147 /*-----------------------------------------------------------------*/
148 static void
149 emitcode (char *inst, const char *fmt,...)
150 {
151   va_list ap;
152   char lb[INITIAL_INLINEASM];
153   char *lbp = lb;
154
155   va_start (ap, fmt);
156
157   if (inst && *inst)
158     {
159       if (fmt && *fmt)
160           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
161       else
162           SNPRINTF (lb, sizeof(lb), "%s", inst);
163       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
164     }
165   else
166       tvsprintf (lb, sizeof(lb), fmt, ap);
167
168   while (isspace (*lbp))
169       lbp++;
170
171   if (lbp && *lbp)
172       lineCurr = (lineCurr ?
173                   connectLine (lineCurr, newLineNode (lb)) :
174                   (lineHead = newLineNode (lb)));
175   lineCurr->isInline = _G.inLine;
176   lineCurr->isDebug = _G.debugLine;
177   lineCurr->ic = _G.current_iCode;
178   lineCurr->isComment = (*lbp==';');
179   va_end (ap);
180 }
181
182 /*-----------------------------------------------------------------*/
183 /* mcs51_emitDebuggerSymbol - associate the current code location  */
184 /*   with a debugger symbol                                        */
185 /*-----------------------------------------------------------------*/
186 void
187 mcs51_emitDebuggerSymbol (char * debugSym)
188 {
189   _G.debugLine = 1;
190   emitcode ("", "%s ==.", debugSym);
191   _G.debugLine = 0;
192 }
193
194 /*-----------------------------------------------------------------*/
195 /* mova - moves specified value into accumulator                   */
196 /*-----------------------------------------------------------------*/
197 static void
198 mova (const char *x)
199 {
200   /* do some early peephole optimization */
201   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
202     return;
203
204   emitcode("mov","a,%s", x);
205 }
206
207 /*-----------------------------------------------------------------*/
208 /* pushB - saves register B if necessary                           */
209 /*-----------------------------------------------------------------*/
210 static bool
211 pushB (void)
212 {
213   bool pushedB = FALSE;
214
215   if (BINUSE)
216     {
217       emitcode ("push", "b");
218 //    printf("B was in use !\n");
219       pushedB = TRUE;
220     }
221   else
222     {
223       OPINB++;
224     }
225   return pushedB;
226 }
227
228 /*-----------------------------------------------------------------*/
229 /* popB - restores value of register B if necessary                */
230 /*-----------------------------------------------------------------*/
231 static void
232 popB (bool pushedB)
233 {
234   if (pushedB)
235     {
236       emitcode ("pop", "b");
237     }
238   else
239     {
240       OPINB--;
241     }
242 }
243
244 /*-----------------------------------------------------------------*/
245 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
246 /*-----------------------------------------------------------------*/
247 static regs *
248 getFreePtr (iCode * ic, asmop ** aopp, bool result)
249 {
250   bool r0iu, r1iu;
251   bool r0ou, r1ou;
252
253   /* the logic: if r0 & r1 used in the instruction
254      then we are in trouble otherwise */
255
256   /* first check if r0 & r1 are used by this
257      instruction, in which case we are in trouble */
258   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
259   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
260   if (r0iu && r1iu) {
261       goto endOfWorld;
262     }
263
264   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
265   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
266
267   /* if no usage of r0 then return it */
268   if (!r0iu && !r0ou)
269     {
270       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
271       (*aopp)->type = AOP_R0;
272
273       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
274     }
275
276   /* if no usage of r1 then return it */
277   if (!r1iu && !r1ou)
278     {
279       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
280       (*aopp)->type = AOP_R1;
281
282       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
283     }
284
285   /* now we know they both have usage */
286   /* if r0 not used in this instruction */
287   if (!r0iu)
288     {
289       /* push it if not already pushed */
290       if (ic->op == IPUSH)
291         {
292           emitcode ("mov", "b,%s",
293                     mcs51_regWithIdx (R0_IDX)->dname);
294           R0INB++;
295         }
296       else if (!_G.r0Pushed)
297         {
298           emitcode ("push", "%s",
299                     mcs51_regWithIdx (R0_IDX)->dname);
300           _G.r0Pushed++;
301         }
302
303       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
304       (*aopp)->type = AOP_R0;
305
306       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
307     }
308
309   /* if r1 not used then */
310
311   if (!r1iu)
312     {
313       /* push it if not already pushed */
314       if (ic->op == IPUSH)
315         {
316           emitcode ("mov", "b,%s",
317                     mcs51_regWithIdx (R1_IDX)->dname);
318           R1INB++;
319         }
320       else if (!_G.r1Pushed)
321         {
322           emitcode ("push", "%s",
323                     mcs51_regWithIdx (R1_IDX)->dname);
324           _G.r1Pushed++;
325         }
326
327       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
328       (*aopp)->type = AOP_R1;
329       return mcs51_regWithIdx (R1_IDX);
330     }
331 endOfWorld:
332   /* I said end of world, but not quite end of world yet */
333   if (result) {
334     /* we can push it on the stack */
335     (*aopp)->type = AOP_STK;
336     return NULL;
337   } else {
338     /* in the case that result AND left AND right needs a pointer reg
339        we can safely use the result's */
340     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
341       (*aopp)->type = AOP_R0;
342       return mcs51_regWithIdx (R0_IDX);
343     }
344     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
345       (*aopp)->type = AOP_R1;
346       return mcs51_regWithIdx (R1_IDX);
347     }
348   }
349
350   /* now this is REALLY the end of the world */
351   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
352           "getFreePtr should never reach here");
353   exit (1);
354 }
355
356
357 /*-----------------------------------------------------------------*/
358 /* getTempRegs - initialize an array of pointers to GPR registers */
359 /*               that are not in use. Returns 1 if the requested   */
360 /*               number of registers were available, 0 otherwise.  */
361 /*-----------------------------------------------------------------*/
362 int
363 getTempRegs(regs **tempRegs, int size, iCode *ic)
364 {
365   bitVect * freeRegs;
366   int i;
367   int offset;
368
369   if (!ic)
370     ic = _G.current_iCode;
371   if (!ic)
372     return 0;
373   if (!_G.currentFunc)
374     return 0;
375
376   freeRegs = newBitVect(8);
377   bitVectSetBit (freeRegs, R2_IDX);
378   bitVectSetBit (freeRegs, R3_IDX);
379   bitVectSetBit (freeRegs, R4_IDX);
380   bitVectSetBit (freeRegs, R5_IDX);
381   bitVectSetBit (freeRegs, R6_IDX);
382   bitVectSetBit (freeRegs, R7_IDX);
383
384   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
385     {
386       bitVect * newfreeRegs;
387       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
388       freeBitVect(freeRegs);
389       freeRegs = newfreeRegs;
390     }
391   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
392
393   offset = 0;
394   for (i=0; i<freeRegs->size; i++)
395     {
396       if (bitVectBitValue(freeRegs,i))
397         tempRegs[offset++] = mcs51_regWithIdx(i);
398       if (offset>=size)
399         {
400           freeBitVect(freeRegs);
401           return 1;
402         }
403     }
404
405   freeBitVect(freeRegs);
406   return 1;
407 }
408
409
410 /*-----------------------------------------------------------------*/
411 /* newAsmop - creates a new asmOp                                  */
412 /*-----------------------------------------------------------------*/
413 static asmop *
414 newAsmop (short type)
415 {
416   asmop *aop;
417
418   aop = Safe_calloc (1, sizeof (asmop));
419   aop->type = type;
420   return aop;
421 }
422
423 /*-----------------------------------------------------------------*/
424 /* pointerCode - returns the code for a pointer type               */
425 /*-----------------------------------------------------------------*/
426 static int
427 pointerCode (sym_link * etype)
428 {
429
430   return PTR_TYPE (SPEC_OCLS (etype));
431
432 }
433
434 /*-----------------------------------------------------------------*/
435 /* leftRightUseAcc - returns size of accumulator use by operands   */
436 /*-----------------------------------------------------------------*/
437 static int
438 leftRightUseAcc(iCode *ic)
439 {
440   operand *op;
441   int size;
442   int accuseSize = 0;
443   int accuse = 0;
444
445   if (!ic)
446     {
447       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
448               "null iCode pointer");
449       return 0;
450     }
451
452   if (ic->op == IFX)
453     {
454       op = IC_COND (ic);
455       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
456         {
457           accuse = 1;
458           size = getSize (OP_SYMBOL (op)->type);
459           if (size>accuseSize)
460             accuseSize = size;
461         }
462     }
463   else if (ic->op == JUMPTABLE)
464     {
465       op = IC_JTCOND (ic);
466       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
467         {
468           accuse = 1;
469           size = getSize (OP_SYMBOL (op)->type);
470           if (size>accuseSize)
471             accuseSize = size;
472         }
473     }
474   else
475     {
476       op = IC_LEFT (ic);
477       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
478         {
479           accuse = 1;
480           size = getSize (OP_SYMBOL (op)->type);
481           if (size>accuseSize)
482             accuseSize = size;
483         }
484       op = IC_RIGHT (ic);
485       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
486         {
487           accuse = 1;
488           size = getSize (OP_SYMBOL (op)->type);
489           if (size>accuseSize)
490             accuseSize = size;
491         }
492     }
493
494   if (accuseSize)
495     return accuseSize;
496   else
497     return accuse;
498 }
499
500 /*-----------------------------------------------------------------*/
501 /* aopForSym - for a true symbol                                   */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 aopForSym (iCode * ic, symbol * sym, bool result)
505 {
506   asmop *aop;
507   memmap *space;
508
509   wassertl (ic != NULL, "Got a null iCode");
510   wassertl (sym != NULL, "Got a null symbol");
511
512   space = SPEC_OCLS (sym->etype);
513
514   /* if already has one */
515   if (sym->aop)
516     return sym->aop;
517
518   /* assign depending on the storage class */
519   /* if it is on the stack or indirectly addressable */
520   /* space we need to assign either r0 or r1 to it   */
521   if (sym->onStack || sym->iaccess)
522     {
523       sym->aop = aop = newAsmop (0);
524       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
525       aop->size = getSize (sym->type);
526
527       /* now assign the address of the variable to
528          the pointer register */
529       if (aop->type != AOP_STK)
530         {
531
532           if (sym->onStack)
533             {
534               char offset = ((sym->stack < 0) ?
535                          ((char) (sym->stack - _G.nRegsSaved)) :
536                          ((char) sym->stack)) & 0xff;
537
538               if ((offset >= -3) && (offset <= 3))
539                 {
540                   emitcode ("mov", "%s,%s",
541                             aop->aopu.aop_ptr->name, SYM_BP (sym));
542                   while (offset < 0)
543                     {
544                       emitcode ("dec", aop->aopu.aop_ptr->name);
545                       offset++;
546                     }
547                   while (offset > 0)
548                     {
549                       emitcode ("inc", aop->aopu.aop_ptr->name);
550                       offset--;
551                     }
552                 }
553               else
554                 {
555                   if (_G.accInUse || leftRightUseAcc (ic))
556                     emitcode ("push", "acc");
557                   emitcode ("mov", "a,%s", SYM_BP (sym));
558                   emitcode ("add", "a,#0x%02x", offset);
559                   emitcode ("mov", "%s,a",
560                             aop->aopu.aop_ptr->name);
561                   if (_G.accInUse || leftRightUseAcc (ic))
562                     emitcode ("pop", "acc");
563                 }
564             }
565           else
566             emitcode ("mov", "%s,#%s",
567                       aop->aopu.aop_ptr->name,
568                       sym->rname);
569           aop->paged = space->paged;
570         }
571       else
572         aop->aopu.aop_stk = sym->stack;
573       return aop;
574     }
575
576   /* if in bit space */
577   if (IN_BITSPACE (space))
578     {
579       sym->aop = aop = newAsmop (AOP_CRY);
580       aop->aopu.aop_dir = sym->rname;
581       aop->size = getSize (sym->type);
582       return aop;
583     }
584   /* if it is in direct space */
585   if (IN_DIRSPACE (space))
586     {
587       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
588       //printTypeChainRaw(sym->type, NULL);
589       //printf("space = %s\n", space ? space->sname : "NULL");
590       sym->aop = aop = newAsmop (AOP_DIR);
591       aop->aopu.aop_dir = sym->rname;
592       aop->size = getSize (sym->type);
593       return aop;
594     }
595
596   /* special case for a function */
597   if (IS_FUNC (sym->type))
598     {
599       sym->aop = aop = newAsmop (AOP_IMMD);
600       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
601       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
602       aop->size = getSize (sym->type);
603       return aop;
604     }
605
606   /* only remaining is far space */
607   /* in which case DPTR gets the address */
608   sym->aop = aop = newAsmop (AOP_DPTR);
609   emitcode ("mov", "dptr,#%s", sym->rname);
610   aop->size = getSize (sym->type);
611
612   /* if it is in code space */
613   if (IN_CODESPACE (space))
614     aop->code = 1;
615
616   return aop;
617 }
618
619 /*-----------------------------------------------------------------*/
620 /* aopForRemat - rematerialzes an object                           */
621 /*-----------------------------------------------------------------*/
622 static asmop *
623 aopForRemat (symbol * sym)
624 {
625   iCode *ic = sym->rematiCode;
626   asmop *aop = newAsmop (AOP_IMMD);
627   int ptr_type = 0;
628   int val = 0;
629
630   for (;;)
631     {
632       if (ic->op == '+')
633         val += (int) operandLitValue (IC_RIGHT (ic));
634       else if (ic->op == '-')
635         val -= (int) operandLitValue (IC_RIGHT (ic));
636       else if (IS_CAST_ICODE(ic)) {
637               sym_link *from_type = operandType(IC_RIGHT(ic));
638               aop->aopu.aop_immd.from_cast_remat = 1;
639               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
640               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
641               continue ;
642       } else break;
643
644       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
645     }
646
647   if (val)
648     sprintf (buffer, "(%s %c 0x%04x)",
649              OP_SYMBOL (IC_LEFT (ic))->rname,
650              val >= 0 ? '+' : '-',
651              abs (val) & 0xffff);
652   else
653     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
654
655   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
656   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
657   /* set immd2 field if required */
658   if (aop->aopu.aop_immd.from_cast_remat) {
659           sprintf(buffer,"#0x%02x",ptr_type);
660           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
661           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
662   }
663
664   return aop;
665 }
666
667 /*-----------------------------------------------------------------*/
668 /* regsInCommon - two operands have some registers in common       */
669 /*-----------------------------------------------------------------*/
670 static bool
671 regsInCommon (operand * op1, operand * op2)
672 {
673   symbol *sym1, *sym2;
674   int i;
675
676   /* if they have registers in common */
677   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
678     return FALSE;
679
680   sym1 = OP_SYMBOL (op1);
681   sym2 = OP_SYMBOL (op2);
682
683   if (sym1->nRegs == 0 || sym2->nRegs == 0)
684     return FALSE;
685
686   for (i = 0; i < sym1->nRegs; i++)
687     {
688       int j;
689       if (!sym1->regs[i])
690         continue;
691
692       for (j = 0; j < sym2->nRegs; j++)
693         {
694           if (!sym2->regs[j])
695             continue;
696
697           if (sym2->regs[j] == sym1->regs[i])
698             return TRUE;
699         }
700     }
701
702   return FALSE;
703 }
704
705 /*-----------------------------------------------------------------*/
706 /* operandsEqu - equivalent                                        */
707 /*-----------------------------------------------------------------*/
708 static bool
709 operandsEqu (operand * op1, operand * op2)
710 {
711   symbol *sym1, *sym2;
712
713   /* if they're not symbols */
714   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
715     return FALSE;
716
717   sym1 = OP_SYMBOL (op1);
718   sym2 = OP_SYMBOL (op2);
719
720   /* if both are itemps & one is spilt
721      and the other is not then false */
722   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
723       sym1->isspilt != sym2->isspilt)
724     return FALSE;
725
726   /* if they are the same */
727   if (sym1 == sym2)
728     return TRUE;
729
730   /* if they have the same rname */
731   if (sym1->rname[0] && sym2->rname[0] &&
732       strcmp (sym1->rname, sym2->rname) == 0 &&
733       !(IS_PARM (op2) && IS_ITEMP (op1)))
734     return TRUE;
735
736   /* if left is a tmp & right is not */
737   if (IS_ITEMP (op1) &&
738       !IS_ITEMP (op2) &&
739       sym1->isspilt &&
740       (sym1->usl.spillLoc == sym2))
741     return TRUE;
742
743   if (IS_ITEMP (op2) &&
744       !IS_ITEMP (op1) &&
745       sym2->isspilt &&
746       sym1->level > 0 &&
747       (sym2->usl.spillLoc == sym1))
748     return TRUE;
749
750   return FALSE;
751 }
752
753 /*-----------------------------------------------------------------*/
754 /* sameRegs - two asmops have the same registers                   */
755 /*-----------------------------------------------------------------*/
756 static bool
757 sameRegs (asmop * aop1, asmop * aop2)
758 {
759   int i;
760
761   if (aop1 == aop2)
762     return TRUE;
763
764   if (aop1->type != AOP_REG ||
765       aop2->type != AOP_REG)
766     return FALSE;
767
768   if (aop1->size != aop2->size)
769     return FALSE;
770
771   for (i = 0; i < aop1->size; i++)
772     if (aop1->aopu.aop_reg[i] !=
773         aop2->aopu.aop_reg[i])
774       return FALSE;
775
776   return TRUE;
777 }
778
779 /*-----------------------------------------------------------------*/
780 /* aopOp - allocates an asmop for an operand  :                    */
781 /*-----------------------------------------------------------------*/
782 static void
783 aopOp (operand * op, iCode * ic, bool result)
784 {
785   asmop *aop;
786   symbol *sym;
787   int i;
788
789   if (!op)
790     return;
791
792   /* if this a literal */
793   if (IS_OP_LITERAL (op))
794     {
795       op->aop = aop = newAsmop (AOP_LIT);
796       aop->aopu.aop_lit = op->operand.valOperand;
797       aop->size = getSize (operandType (op));
798       return;
799     }
800
801   /* if already has a asmop then continue */
802   if (op->aop )
803     return;
804
805   /* if the underlying symbol has a aop */
806   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
807     {
808       op->aop = OP_SYMBOL (op)->aop;
809       return;
810     }
811
812   /* if this is a true symbol */
813   if (IS_TRUE_SYMOP (op))
814     {
815       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
816       return;
817     }
818
819   /* this is a temporary : this has
820      only five choices :
821      a) register
822      b) spillocation
823      c) rematerialize
824      d) conditional
825      e) can be a return use only */
826
827   sym = OP_SYMBOL (op);
828
829   /* if the type is a conditional */
830   if (sym->regType == REG_CND)
831     {
832       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
833       aop->size = 0;
834       return;
835     }
836
837   /* if it is spilt then two situations
838      a) is rematerialize
839      b) has a spill location */
840   if (sym->isspilt || sym->nRegs == 0)
841     {
842
843       /* rematerialize it NOW */
844       if (sym->remat)
845         {
846           sym->aop = op->aop = aop =
847             aopForRemat (sym);
848           aop->size = getSize (sym->type);
849           return;
850         }
851
852       if (sym->accuse)
853         {
854           int i;
855           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
856           aop->size = getSize (sym->type);
857           for (i = 0; i < 2; i++)
858             aop->aopu.aop_str[i] = accUse[i];
859           return;
860         }
861
862       if (sym->ruonly)
863         {
864           unsigned i;
865
866           aop = op->aop = sym->aop = newAsmop (AOP_STR);
867           aop->size = getSize (sym->type);
868           for (i = 0; i < fReturnSizeMCS51; i++)
869             aop->aopu.aop_str[i] = fReturn[i];
870           return;
871         }
872
873       if (sym->usl.spillLoc)
874         {
875           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
876             {
877               /* force a new aop if sizes differ */
878               sym->usl.spillLoc->aop = NULL;
879             }
880           sym->aop = op->aop = aop =
881                      aopForSym (ic, sym->usl.spillLoc, result);
882           aop->size = getSize (sym->type);
883           return;
884         }
885
886       /* else must be a dummy iTemp */
887       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
888       aop->size = getSize (sym->type);
889       return;
890     }
891
892   /* must be in a register */
893   sym->aop = op->aop = aop = newAsmop (AOP_REG);
894   aop->size = sym->nRegs;
895   for (i = 0; i < sym->nRegs; i++)
896     aop->aopu.aop_reg[i] = sym->regs[i];
897 }
898
899 /*-----------------------------------------------------------------*/
900 /* freeAsmop - free up the asmop given to an operand               */
901 /*----------------------------------------------------------------*/
902 static void
903 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
904 {
905   asmop *aop;
906
907   if (!op)
908     aop = aaop;
909   else
910     aop = op->aop;
911
912   if (!aop)
913     return;
914
915   if (aop->freed)
916     goto dealloc;
917
918   aop->freed = 1;
919
920   /* depending on the asmop type only three cases need work AOP_RO
921      , AOP_R1 && AOP_STK */
922   switch (aop->type)
923     {
924     case AOP_R0:
925       if (R0INB)
926         {
927           emitcode ("mov", "r0,b");
928           R0INB--;
929         }
930       else if (_G.r0Pushed)
931         {
932           if (pop)
933             {
934               emitcode ("pop", "ar0");
935               _G.r0Pushed--;
936             }
937         }
938       bitVectUnSetBit (ic->rUsed, R0_IDX);
939       break;
940
941     case AOP_R1:
942       if (R1INB)
943         {
944           emitcode ("mov", "r1,b");
945           R1INB--;
946         }
947       if (_G.r1Pushed)
948         {
949           if (pop)
950             {
951               emitcode ("pop", "ar1");
952               _G.r1Pushed--;
953             }
954         }
955       bitVectUnSetBit (ic->rUsed, R1_IDX);
956       break;
957
958     case AOP_STK:
959       {
960         int sz = aop->size;
961         int stk = aop->aopu.aop_stk + aop->size - 1;
962         bitVectUnSetBit (ic->rUsed, R0_IDX);
963         bitVectUnSetBit (ic->rUsed, R1_IDX);
964
965         getFreePtr (ic, &aop, FALSE);
966
967         if (stk)
968           {
969             emitcode ("mov", "a,_bp");
970             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
971             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
972           }
973         else
974           {
975             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
976           }
977
978         while (sz--)
979           {
980             emitcode ("pop", "acc");
981             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
982             if (!sz)
983               break;
984             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
985           }
986         op->aop = aop;
987         freeAsmop (op, NULL, ic, TRUE);
988         if (_G.r1Pushed)
989           {
990             emitcode ("pop", "ar1");
991             _G.r1Pushed--;
992           }
993
994         if (_G.r0Pushed)
995           {
996             emitcode ("pop", "ar0");
997             _G.r0Pushed--;
998           }
999       }
1000     }
1001
1002 dealloc:
1003   /* all other cases just dealloc */
1004   if (op)
1005     {
1006       op->aop = NULL;
1007       if (IS_SYMOP (op))
1008         {
1009           OP_SYMBOL (op)->aop = NULL;
1010           /* if the symbol has a spill */
1011           if (SPIL_LOC (op))
1012             SPIL_LOC (op)->aop = NULL;
1013         }
1014     }
1015 }
1016
1017 /*------------------------------------------------------------------*/
1018 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1019 /*                      pop r0 or r1 off stack if pushed            */
1020 /*------------------------------------------------------------------*/
1021 static void
1022 freeForBranchAsmop (operand * op)
1023 {
1024   asmop *aop;
1025
1026   if (!op)
1027     return;
1028
1029   aop = op->aop;
1030
1031   if (!aop)
1032     return;
1033
1034   if (aop->freed)
1035     return;
1036
1037   switch (aop->type)
1038     {
1039     case AOP_R0:
1040       if (R0INB)
1041         {
1042           emitcode ("mov", "r0,b");
1043         }
1044       else if (_G.r0Pushed)
1045         {
1046           emitcode ("pop", "ar0");
1047         }
1048       break;
1049
1050     case AOP_R1:
1051       if (R1INB)
1052         {
1053           emitcode ("mov", "r1,b");
1054         }
1055       else if (_G.r1Pushed)
1056         {
1057           emitcode ("pop", "ar1");
1058         }
1059       break;
1060
1061     case AOP_STK:
1062       {
1063         int sz = aop->size;
1064         int stk = aop->aopu.aop_stk + aop->size - 1;
1065
1066         emitcode ("mov", "b,r0");
1067         if (stk)
1068           {
1069             emitcode ("mov", "a,_bp");
1070             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1071             emitcode ("mov", "r0,a");
1072           }
1073         else
1074           {
1075             emitcode ("mov", "r0,_bp");
1076           }
1077
1078         while (sz--)
1079           {
1080             emitcode ("pop", "acc");
1081             emitcode ("mov", "@r0,a");
1082             if (!sz)
1083               break;
1084             emitcode ("dec", "r0");
1085           }
1086         emitcode ("mov", "r0,b");
1087       }
1088     }
1089
1090 }
1091
1092 /*-----------------------------------------------------------------*/
1093 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1094 /*                 clobber the accumulator                         */
1095 /*-----------------------------------------------------------------*/
1096 static bool
1097 aopGetUsesAcc (operand * oper, int offset)
1098 {
1099   asmop * aop = AOP (oper);
1100
1101   if (offset > (aop->size - 1))
1102     return FALSE;
1103
1104   switch (aop->type)
1105     {
1106
1107     case AOP_R0:
1108     case AOP_R1:
1109       if (aop->paged)
1110         return TRUE;
1111       return FALSE;
1112     case AOP_DPTR:
1113       return TRUE;
1114     case AOP_IMMD:
1115       return FALSE;
1116     case AOP_DIR:
1117       return FALSE;
1118     case AOP_REG:
1119       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1120       return FALSE;
1121     case AOP_CRY:
1122       return TRUE;
1123     case AOP_ACC:
1124       if (offset)
1125         return FALSE;
1126       return TRUE;
1127     case AOP_LIT:
1128       return FALSE;
1129     case AOP_STR:
1130       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1131         return TRUE;
1132       return FALSE;
1133     case AOP_DUMMY:
1134       return FALSE;
1135     default:
1136       /* Error case --- will have been caught already */
1137       wassert(0);
1138       return FALSE;
1139     }
1140 }
1141
1142 /*-----------------------------------------------------------------*/
1143 /* aopGet - for fetching value of the aop                          */
1144 /*-----------------------------------------------------------------*/
1145 static char *
1146 aopGet (operand * oper, int offset, bool bit16, bool dname)
1147 {
1148   char *s = buffer;
1149   char *rs;
1150   asmop * aop = AOP (oper);
1151
1152   /* offset is greater than
1153      size then zero */
1154   if (offset > (aop->size - 1) &&
1155       aop->type != AOP_LIT)
1156     return zero;
1157
1158   /* depending on type */
1159   switch (aop->type)
1160     {
1161     case AOP_DUMMY:
1162       return zero;
1163
1164     case AOP_R0:
1165     case AOP_R1:
1166       /* if we need to increment it */
1167       while (offset > aop->coff)
1168         {
1169           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1170           aop->coff++;
1171         }
1172
1173       while (offset < aop->coff)
1174         {
1175           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1176           aop->coff--;
1177         }
1178
1179       aop->coff = offset;
1180       if (aop->paged)
1181         {
1182           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1183           return (dname ? "acc" : "a");
1184         }
1185       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1186       rs = Safe_calloc (1, strlen (s) + 1);
1187       strcpy (rs, s);
1188       return rs;
1189
1190     case AOP_DPTR:
1191       if (aop->code && aop->coff==0 && offset>=1) {
1192         emitcode ("mov", "a,#0x%02x", offset);
1193         emitcode ("movc", "a,@a+dptr");
1194         return (dname ? "acc" : "a");
1195       }
1196
1197       while (offset > aop->coff)
1198         {
1199           emitcode ("inc", "dptr");
1200           aop->coff++;
1201         }
1202
1203       while (offset < aop->coff)
1204         {
1205           emitcode ("lcall", "__decdptr");
1206           aop->coff--;
1207         }
1208
1209       aop->coff = offset;
1210       if (aop->code)
1211         {
1212           emitcode ("clr", "a");
1213           emitcode ("movc", "a,@a+dptr");
1214         }
1215       else
1216         {
1217           emitcode ("movx", "a,@dptr");
1218         }
1219       return (dname ? "acc" : "a");
1220
1221
1222     case AOP_IMMD:
1223       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1224               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1225       } else if (bit16)
1226         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1227       else if (offset)
1228         sprintf (s, "#(%s >> %d)",
1229                  aop->aopu.aop_immd.aop_immd1,
1230                  offset * 8);
1231       else
1232         sprintf (s, "#%s",
1233                  aop->aopu.aop_immd.aop_immd1);
1234       rs = Safe_calloc (1, strlen (s) + 1);
1235       strcpy (rs, s);
1236       return rs;
1237
1238     case AOP_DIR:
1239       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1240         sprintf (s, "(%s >> %d)",
1241                  aop->aopu.aop_dir, offset * 8);
1242       else if (offset)
1243         sprintf (s, "(%s + %d)",
1244                  aop->aopu.aop_dir,
1245                  offset);
1246       else
1247         sprintf (s, "%s", aop->aopu.aop_dir);
1248       rs = Safe_calloc (1, strlen (s) + 1);
1249       strcpy (rs, s);
1250       return rs;
1251
1252     case AOP_REG:
1253       if (dname)
1254         return aop->aopu.aop_reg[offset]->dname;
1255       else
1256         return aop->aopu.aop_reg[offset]->name;
1257
1258     case AOP_CRY:
1259       emitcode ("clr", "a");
1260       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1261       emitcode ("rlc", "a");
1262       return (dname ? "acc" : "a");
1263
1264     case AOP_ACC:
1265       if (!offset && dname)
1266         return "acc";
1267       return aop->aopu.aop_str[offset];
1268
1269     case AOP_LIT:
1270       return aopLiteral (aop->aopu.aop_lit, offset);
1271
1272     case AOP_STR:
1273       aop->coff = offset;
1274       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1275           dname)
1276         return "acc";
1277
1278       return aop->aopu.aop_str[offset];
1279
1280     }
1281
1282   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1283           "aopget got unsupported aop->type");
1284   exit (1);
1285 }
1286 /*-----------------------------------------------------------------*/
1287 /* aopPut - puts a string for a aop and indicates if acc is in use */
1288 /*-----------------------------------------------------------------*/
1289 static bool
1290 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1291 {
1292   char *d = buffer;
1293   bool accuse = FALSE;
1294   asmop * aop = AOP (result);
1295
1296   if (aop->size && offset > (aop->size - 1))
1297     {
1298       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1299               "aopPut got offset > aop->size");
1300       exit (1);
1301     }
1302
1303   /* will assign value to value */
1304   /* depending on where it is ofcourse */
1305   switch (aop->type)
1306     {
1307     case AOP_DUMMY:
1308       MOVA (s);         /* read s in case it was volatile */
1309       accuse = TRUE;
1310       break;
1311
1312     case AOP_DIR:
1313       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1314         sprintf (d, "(%s >> %d)",
1315                  aop->aopu.aop_dir, offset * 8);
1316       else if (offset)
1317         sprintf (d, "(%s + %d)",
1318                  aop->aopu.aop_dir, offset);
1319       else
1320         sprintf (d, "%s", aop->aopu.aop_dir);
1321
1322       if (strcmp (d, s) ||
1323           bvolatile)
1324           emitcode ("mov", "%s,%s", d, s);
1325       if (!strcmp (d, "acc"))
1326           accuse = TRUE;
1327
1328       break;
1329
1330     case AOP_REG:
1331       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1332           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1333         {
1334           if (*s == '@' ||
1335               strcmp (s, "r0") == 0 ||
1336               strcmp (s, "r1") == 0 ||
1337               strcmp (s, "r2") == 0 ||
1338               strcmp (s, "r3") == 0 ||
1339               strcmp (s, "r4") == 0 ||
1340               strcmp (s, "r5") == 0 ||
1341               strcmp (s, "r6") == 0 ||
1342               strcmp (s, "r7") == 0)
1343             emitcode ("mov", "%s,%s",
1344                       aop->aopu.aop_reg[offset]->dname, s);
1345           else
1346             emitcode ("mov", "%s,%s",
1347                       aop->aopu.aop_reg[offset]->name, s);
1348         }
1349       break;
1350
1351     case AOP_DPTR:
1352       if (aop->code)
1353         {
1354           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1355                   "aopPut writing to code space");
1356           exit (1);
1357         }
1358
1359       while (offset > aop->coff)
1360         {
1361           aop->coff++;
1362           emitcode ("inc", "dptr");
1363         }
1364
1365       while (offset < aop->coff)
1366         {
1367           aop->coff--;
1368           emitcode ("lcall", "__decdptr");
1369         }
1370
1371       aop->coff = offset;
1372
1373       /* if not in accumulator */
1374       MOVA (s);
1375
1376       emitcode ("movx", "@dptr,a");
1377       break;
1378
1379     case AOP_R0:
1380     case AOP_R1:
1381       while (offset > aop->coff)
1382         {
1383           aop->coff++;
1384           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1385         }
1386       while (offset < aop->coff)
1387         {
1388           aop->coff--;
1389           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1390         }
1391       aop->coff = offset;
1392
1393       if (aop->paged)
1394         {
1395           MOVA (s);
1396           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1397
1398         }
1399       else if (*s == '@')
1400         {
1401           MOVA (s);
1402           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1403         }
1404       else if (strcmp (s, "r0") == 0 ||
1405                strcmp (s, "r1") == 0 ||
1406                strcmp (s, "r2") == 0 ||
1407                strcmp (s, "r3") == 0 ||
1408                strcmp (s, "r4") == 0 ||
1409                strcmp (s, "r5") == 0 ||
1410                strcmp (s, "r6") == 0 ||
1411                strcmp (s, "r7") == 0)
1412         {
1413           char buffer[10];
1414           sprintf (buffer, "a%s", s);
1415           emitcode ("mov", "@%s,%s",
1416                     aop->aopu.aop_ptr->name, buffer);
1417         }
1418       else
1419         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1420
1421       break;
1422
1423     case AOP_STK:
1424       if (strcmp (s, "a") == 0)
1425         emitcode ("push", "acc");
1426       else
1427         if (*s=='@') {
1428           MOVA(s);
1429           emitcode ("push", "acc");
1430         } else {
1431           emitcode ("push", s);
1432         }
1433
1434       break;
1435
1436     case AOP_CRY:
1437       /* if not bit variable */
1438       if (!aop->aopu.aop_dir)
1439         {
1440           /* inefficient: move carry into A and use jz/jnz */
1441           emitcode ("clr", "a");
1442           emitcode ("rlc", "a");
1443           accuse = TRUE;
1444         }
1445       else
1446         {
1447           if (s == zero)
1448             emitcode ("clr", "%s", aop->aopu.aop_dir);
1449           else if (s == one)
1450             emitcode ("setb", "%s", aop->aopu.aop_dir);
1451           else if (!strcmp (s, "c"))
1452             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1453           else
1454             {
1455               MOVA (s);
1456               /* set C, if a >= 1 */
1457               emitcode ("add", "a,#0xff");
1458               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1459             }
1460         }
1461       break;
1462
1463     case AOP_STR:
1464       aop->coff = offset;
1465       if (strcmp (aop->aopu.aop_str[offset], s) ||
1466           bvolatile)
1467         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1468       break;
1469
1470     case AOP_ACC:
1471       accuse = TRUE;
1472       aop->coff = offset;
1473       if (!offset && (strcmp (s, "acc") == 0) &&
1474           !bvolatile)
1475         break;
1476
1477       if (strcmp (aop->aopu.aop_str[offset], s) &&
1478           !bvolatile)
1479         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1480       break;
1481
1482     default:
1483       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1484               "aopPut got unsupported aop->type");
1485       exit (1);
1486     }
1487
1488     return accuse;
1489 }
1490
1491
1492 #if 0
1493 /*-----------------------------------------------------------------*/
1494 /* pointToEnd :- points to the last byte of the operand            */
1495 /*-----------------------------------------------------------------*/
1496 static void
1497 pointToEnd (asmop * aop)
1498 {
1499   int count;
1500   if (!aop)
1501     return;
1502
1503   aop->coff = count = (aop->size - 1);
1504   switch (aop->type)
1505     {
1506     case AOP_R0:
1507     case AOP_R1:
1508       while (count--)
1509         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1510       break;
1511     case AOP_DPTR:
1512       while (count--)
1513         emitcode ("inc", "dptr");
1514       break;
1515     }
1516
1517 }
1518 #endif
1519
1520 /*-----------------------------------------------------------------*/
1521 /* reAdjustPreg - points a register back to where it should        */
1522 /*-----------------------------------------------------------------*/
1523 static void
1524 reAdjustPreg (asmop * aop)
1525 {
1526   if ((aop->coff==0) || aop->size <= 1)
1527     return;
1528
1529   switch (aop->type)
1530     {
1531     case AOP_R0:
1532     case AOP_R1:
1533       while (aop->coff--)
1534         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1535       break;
1536     case AOP_DPTR:
1537       while (aop->coff--)
1538         {
1539           emitcode ("lcall", "__decdptr");
1540         }
1541       break;
1542     }
1543   aop->coff = 0;
1544 }
1545
1546 /*-----------------------------------------------------------------*/
1547 /* opIsGptr: returns non-zero if the passed operand is       */
1548 /* a generic pointer type.             */
1549 /*-----------------------------------------------------------------*/
1550 static int
1551 opIsGptr (operand * op)
1552 {
1553   sym_link *type = operandType (op);
1554
1555   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1556     {
1557       return 1;
1558     }
1559   return 0;
1560 }
1561
1562 /*-----------------------------------------------------------------*/
1563 /* getDataSize - get the operand data size                         */
1564 /*-----------------------------------------------------------------*/
1565 static int
1566 getDataSize (operand * op)
1567 {
1568   int size;
1569   size = AOP_SIZE (op);
1570   if (size == GPTRSIZE)
1571     {
1572       sym_link *type = operandType (op);
1573       if (IS_GENPTR (type))
1574         {
1575           /* generic pointer; arithmetic operations
1576            * should ignore the high byte (pointer type).
1577            */
1578           size--;
1579         }
1580     }
1581   return size;
1582 }
1583
1584 /*-----------------------------------------------------------------*/
1585 /* outAcc - output Acc                                             */
1586 /*-----------------------------------------------------------------*/
1587 static void
1588 outAcc (operand * result)
1589 {
1590   int size, offset;
1591   size = getDataSize (result);
1592   if (size)
1593     {
1594       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1595       size--;
1596       offset = 1;
1597       /* unsigned or positive */
1598       while (size--)
1599         {
1600           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1601         }
1602     }
1603 }
1604
1605 /*-----------------------------------------------------------------*/
1606 /* outBitC - output a bit C                                        */
1607 /*-----------------------------------------------------------------*/
1608 static void
1609 outBitC (operand * result)
1610 {
1611   /* if the result is bit */
1612   if (AOP_TYPE (result) == AOP_CRY)
1613     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1614   else
1615     {
1616       emitcode ("clr", "a");
1617       emitcode ("rlc", "a");
1618       outAcc (result);
1619     }
1620 }
1621
1622 /*-----------------------------------------------------------------*/
1623 /* toBoolean - emit code for orl a,operator(sizeop)                */
1624 /*-----------------------------------------------------------------*/
1625 static void
1626 toBoolean (operand * oper)
1627 {
1628   int size = AOP_SIZE (oper) - 1;
1629   int offset = 1;
1630   bool AccUsed = FALSE;
1631   bool pushedB;
1632
1633   while (!AccUsed && size--)
1634     {
1635       AccUsed |= aopGetUsesAcc(oper, offset++);
1636     }
1637
1638   size = AOP_SIZE (oper) - 1;
1639   offset = 1;
1640   MOVA (aopGet (oper, 0, FALSE, FALSE));
1641   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1642     {
1643       pushedB = pushB ();
1644       emitcode("mov", "b,a");
1645       while (--size)
1646         {
1647           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1648           emitcode ("orl", "b,a");
1649         }
1650       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1651       emitcode ("orl", "a,b");
1652       popB (pushedB);
1653     }
1654   else
1655     {
1656       while (size--)
1657         {
1658           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1659         }
1660     }
1661 }
1662
1663
1664 /*-----------------------------------------------------------------*/
1665 /* genNot - generate code for ! operation                          */
1666 /*-----------------------------------------------------------------*/
1667 static void
1668 genNot (iCode * ic)
1669 {
1670   symbol *tlbl;
1671
1672   D(emitcode (";     genNot",""));
1673
1674   /* assign asmOps to operand & result */
1675   aopOp (IC_LEFT (ic), ic, FALSE);
1676   aopOp (IC_RESULT (ic), ic, TRUE);
1677
1678   /* if in bit space then a special case */
1679   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1680     {
1681       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1682       emitcode ("cpl", "c");
1683       outBitC (IC_RESULT (ic));
1684       goto release;
1685     }
1686
1687   toBoolean (IC_LEFT (ic));
1688
1689   tlbl = newiTempLabel (NULL);
1690   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1691   emitcode ("", "%05d$:", tlbl->key + 100);
1692   outBitC (IC_RESULT (ic));
1693
1694 release:
1695   /* release the aops */
1696   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1697   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1698 }
1699
1700
1701 /*-----------------------------------------------------------------*/
1702 /* genCpl - generate code for complement                           */
1703 /*-----------------------------------------------------------------*/
1704 static void
1705 genCpl (iCode * ic)
1706 {
1707   int offset = 0;
1708   int size;
1709   symbol *tlbl;
1710   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1711
1712   D(emitcode (";", "genCpl"));
1713
1714   /* assign asmOps to operand & result */
1715   aopOp (IC_LEFT (ic), ic, FALSE);
1716   aopOp (IC_RESULT (ic), ic, TRUE);
1717
1718   /* special case if in bit space */
1719   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1720     {
1721       char *l;
1722
1723       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1724           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1725         {
1726           /* promotion rules are responsible for this strange result:
1727              bit -> int -> ~int -> bit
1728              uchar -> int -> ~int -> bit
1729           */
1730           werror(W_COMPLEMENT);
1731           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1732           goto release;
1733         }
1734
1735       tlbl=newiTempLabel(NULL);
1736       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1737       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1738           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1739           IS_AOP_PREG (IC_LEFT (ic)))
1740         {
1741           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1742         }
1743       else
1744         {
1745           MOVA (l);
1746           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1747         }
1748       emitcode ("", "%05d$:", tlbl->key + 100);
1749       outBitC (IC_RESULT(ic));
1750       goto release;
1751     }
1752
1753   size = AOP_SIZE (IC_RESULT (ic));
1754   while (size--)
1755     {
1756       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1757       MOVA (l);
1758       emitcode ("cpl", "a");
1759       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1760     }
1761
1762
1763 release:
1764   /* release the aops */
1765   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1766   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1767 }
1768
1769 /*-----------------------------------------------------------------*/
1770 /* genUminusFloat - unary minus for floating points                */
1771 /*-----------------------------------------------------------------*/
1772 static void
1773 genUminusFloat (operand * op, operand * result)
1774 {
1775   int size, offset = 0;
1776   char *l;
1777
1778   D(emitcode (";     genUminusFloat",""));
1779
1780   /* for this we just copy and then flip the bit */
1781
1782   size = AOP_SIZE (op) - 1;
1783
1784   while (size--)
1785     {
1786       aopPut (result,
1787               aopGet (op, offset, FALSE, FALSE),
1788               offset,
1789               isOperandVolatile (result, FALSE));
1790       offset++;
1791     }
1792
1793   l = aopGet (op, offset, FALSE, FALSE);
1794
1795   MOVA (l);
1796
1797   emitcode ("cpl", "acc.7");
1798   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1799 }
1800
1801 /*-----------------------------------------------------------------*/
1802 /* genUminus - unary minus code generation                         */
1803 /*-----------------------------------------------------------------*/
1804 static void
1805 genUminus (iCode * ic)
1806 {
1807   int offset, size;
1808   sym_link *optype, *rtype;
1809
1810
1811   D(emitcode (";     genUminus",""));
1812
1813   /* assign asmops */
1814   aopOp (IC_LEFT (ic), ic, FALSE);
1815   aopOp (IC_RESULT (ic), ic, TRUE);
1816
1817   /* if both in bit space then special
1818      case */
1819   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1820       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1821     {
1822
1823       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1824       emitcode ("cpl", "c");
1825       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1826       goto release;
1827     }
1828
1829   optype = operandType (IC_LEFT (ic));
1830   rtype = operandType (IC_RESULT (ic));
1831
1832   /* if float then do float stuff */
1833   if (IS_FLOAT (optype))
1834     {
1835       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1836       goto release;
1837     }
1838
1839   /* otherwise subtract from zero */
1840   size = AOP_SIZE (IC_LEFT (ic));
1841   offset = 0;
1842   //CLRC ;
1843   while (size--)
1844     {
1845       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1846       if (!strcmp (l, "a"))
1847         {
1848           if (offset == 0)
1849             SETC;
1850           emitcode ("cpl", "a");
1851           emitcode ("addc", "a,#0");
1852         }
1853       else
1854         {
1855           if (offset == 0)
1856             CLRC;
1857           emitcode ("clr", "a");
1858           emitcode ("subb", "a,%s", l);
1859         }
1860       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1861     }
1862
1863   /* if any remaining bytes in the result */
1864   /* we just need to propagate the sign   */
1865   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1866     {
1867       emitcode ("rlc", "a");
1868       emitcode ("subb", "a,acc");
1869       while (size--)
1870         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1871     }
1872
1873 release:
1874   /* release the aops */
1875   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1876   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1877 }
1878
1879 /*-----------------------------------------------------------------*/
1880 /* saveRegisters - will look for a call and save the registers     */
1881 /*-----------------------------------------------------------------*/
1882 static void
1883 saveRegisters (iCode * lic)
1884 {
1885   int i;
1886   iCode *ic;
1887   bitVect *rsave;
1888
1889   /* look for call */
1890   for (ic = lic; ic; ic = ic->next)
1891     if (ic->op == CALL || ic->op == PCALL)
1892       break;
1893
1894   if (!ic)
1895     {
1896       fprintf (stderr, "found parameter push with no function call\n");
1897       return;
1898     }
1899
1900   /* if the registers have been saved already or don't need to be then
1901      do nothing */
1902   if (ic->regsSaved)
1903     return;
1904   if (IS_SYMOP(IC_LEFT(ic)) &&
1905       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1906        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1907     return;
1908
1909   /* save the registers in use at this time but skip the
1910      ones for the result */
1911   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1912                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1913
1914   ic->regsSaved = 1;
1915   if (options.useXstack)
1916     {
1917       int count = bitVectnBitsOn (rsave);
1918
1919       if (count == 1)
1920         {
1921           i = bitVectFirstBit (rsave);
1922           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1923           emitcode ("mov", "r0,%s", spname);
1924           emitcode ("inc", "%s", spname);// allocate before use
1925           emitcode ("movx", "@r0,a");
1926           if (bitVectBitValue (rsave, R0_IDX))
1927             emitcode ("mov", "r0,a");
1928         }
1929       else if (count != 0)
1930         {
1931           if (bitVectBitValue (rsave, R0_IDX))
1932             {
1933               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1934             }
1935           emitcode ("mov", "r0,%s", spname);
1936           MOVA ("r0");
1937           emitcode ("add", "a,#%d", count);
1938           emitcode ("mov", "%s,a", spname);
1939           for (i = 0; i < mcs51_nRegs; i++)
1940             {
1941               if (bitVectBitValue (rsave, i))
1942                 {
1943                   if (i == R0_IDX)
1944                     {
1945                       emitcode ("pop", "acc");
1946                       emitcode ("push", "acc");
1947                     }
1948                   else
1949                     {
1950                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1951                     }
1952                   emitcode ("movx", "@r0,a");
1953                   if (--count)
1954                     {
1955                       emitcode ("inc", "r0");
1956                     }
1957                 }
1958             }
1959           if (bitVectBitValue (rsave, R0_IDX))
1960             {
1961               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1962             }
1963         }
1964     }
1965   else
1966     for (i = 0; i < mcs51_nRegs; i++)
1967       {
1968         if (bitVectBitValue (rsave, i))
1969           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1970       }
1971 }
1972
1973 /*-----------------------------------------------------------------*/
1974 /* unsaveRegisters - pop the pushed registers                      */
1975 /*-----------------------------------------------------------------*/
1976 static void
1977 unsaveRegisters (iCode * ic)
1978 {
1979   int i;
1980   bitVect *rsave;
1981
1982   /* restore the registers in use at this time but skip the
1983      ones for the result */
1984   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1985                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1986
1987   if (options.useXstack)
1988     {
1989       int count = bitVectnBitsOn (rsave);
1990
1991       if (count == 1)
1992         {
1993           emitcode ("mov", "r0,%s", spname);
1994           emitcode ("dec", "r0");
1995           emitcode ("movx", "a,@r0");
1996           i = bitVectFirstBit (rsave);
1997           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1998           emitcode ("dec", "%s", spname);
1999         }
2000       else if (count != 0)
2001         {
2002           emitcode ("mov", "r0,%s", spname);
2003           for (i = mcs51_nRegs; i >= 0; i--)
2004             {
2005               if (bitVectBitValue (rsave, i))
2006                 {
2007                   emitcode ("dec", "r0");
2008                   emitcode ("movx", "a,@r0");
2009                   if (i != R0_IDX)
2010                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
2011                   else
2012                     emitcode ("push", "acc");
2013                 }
2014             }
2015           emitcode ("mov", "%s,r0", spname);
2016           if (bitVectBitValue (rsave, R0_IDX))
2017             {
2018               emitcode ("pop", "ar0");
2019             }
2020         }
2021     }
2022   else
2023     for (i = mcs51_nRegs; i >= 0; i--)
2024       {
2025         if (bitVectBitValue (rsave, i))
2026           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2027       }
2028 }
2029
2030
2031 /*-----------------------------------------------------------------*/
2032 /* pushSide -                */
2033 /*-----------------------------------------------------------------*/
2034 static void
2035 pushSide (operand * oper, int size)
2036 {
2037   int offset = 0;
2038   while (size--)
2039     {
2040       char *l = aopGet (oper, offset++, FALSE, TRUE);
2041       if (AOP_TYPE (oper) != AOP_REG &&
2042           AOP_TYPE (oper) != AOP_DIR &&
2043           strcmp (l, "a"))
2044         {
2045           MOVA (l);
2046           emitcode ("push", "acc");
2047         }
2048       else
2049         {
2050           emitcode ("push", "%s", l);
2051         }
2052     }
2053 }
2054
2055 /*-----------------------------------------------------------------*/
2056 /* assignResultValue - also indicates if acc is in use afterwards  */
2057 /*-----------------------------------------------------------------*/
2058 static bool
2059 assignResultValue (operand * oper)
2060 {
2061   int offset = 0;
2062   int size = AOP_SIZE (oper);
2063   bool accuse = FALSE;
2064
2065   while (size--)
2066     {
2067       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2068       offset++;
2069     }
2070   return accuse;
2071 }
2072
2073
2074 /*-----------------------------------------------------------------*/
2075 /* genXpush - pushes onto the external stack                       */
2076 /*-----------------------------------------------------------------*/
2077 static void
2078 genXpush (iCode * ic)
2079 {
2080   asmop *aop = newAsmop (0);
2081   regs *r;
2082   int size, offset = 0;
2083
2084   D(emitcode (";     genXpush",""));
2085
2086   aopOp (IC_LEFT (ic), ic, FALSE);
2087   r = getFreePtr (ic, &aop, FALSE);
2088
2089   size = AOP_SIZE (IC_LEFT (ic));
2090
2091   if (size == 1)
2092     {
2093       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2094       emitcode ("mov", "%s,%s", r->name, spname);
2095       emitcode ("inc", "%s", spname); // allocate space first
2096       emitcode ("movx", "@%s,a", r->name);
2097     }
2098   else
2099     {
2100       // allocate space first
2101       emitcode ("mov", "%s,%s", r->name, spname);
2102       MOVA (r->name);
2103       emitcode ("add", "a,#%d", size);
2104       emitcode ("mov", "%s,a", spname);
2105
2106       while (size--)
2107         {
2108           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2109           emitcode ("movx", "@%s,a", r->name);
2110           emitcode ("inc", "%s", r->name);
2111         }
2112     }
2113
2114   freeAsmop (NULL, aop, ic, TRUE);
2115   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2116 }
2117
2118 /*-----------------------------------------------------------------*/
2119 /* genIpush - generate code for pushing this gets a little complex */
2120 /*-----------------------------------------------------------------*/
2121 static void
2122 genIpush (iCode * ic)
2123 {
2124   int size, offset = 0;
2125   char *l;
2126
2127   D(emitcode (";     genIpush",""));
2128
2129   /* if this is not a parm push : ie. it is spill push
2130      and spill push is always done on the local stack */
2131   if (!ic->parmPush)
2132     {
2133
2134       /* and the item is spilt then do nothing */
2135       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2136         return;
2137
2138       aopOp (IC_LEFT (ic), ic, FALSE);
2139       size = AOP_SIZE (IC_LEFT (ic));
2140       /* push it on the stack */
2141       while (size--)
2142         {
2143           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2144           if (*l == '#')
2145             {
2146               MOVA (l);
2147               l = "acc";
2148             }
2149           emitcode ("push", "%s", l);
2150         }
2151       return;
2152     }
2153
2154   /* this is a paramter push: in this case we call
2155      the routine to find the call and save those
2156      registers that need to be saved */
2157   saveRegisters (ic);
2158
2159   /* if use external stack then call the external
2160      stack pushing routine */
2161   if (options.useXstack)
2162     {
2163       genXpush (ic);
2164       return;
2165     }
2166
2167   /* then do the push */
2168   aopOp (IC_LEFT (ic), ic, FALSE);
2169
2170   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2171   size = AOP_SIZE (IC_LEFT (ic));
2172
2173   while (size--)
2174     {
2175       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2176       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2177           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2178           strcmp (l, "a"))
2179         {
2180           MOVA (l);
2181           emitcode ("push", "acc");
2182         }
2183       else
2184           emitcode ("push", "%s", l);
2185     }
2186
2187   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2188 }
2189
2190 /*-----------------------------------------------------------------*/
2191 /* genIpop - recover the registers: can happen only for spilling   */
2192 /*-----------------------------------------------------------------*/
2193 static void
2194 genIpop (iCode * ic)
2195 {
2196   int size, offset;
2197
2198   D(emitcode (";     genIpop",""));
2199
2200   /* if the temp was not pushed then */
2201   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2202     return;
2203
2204   aopOp (IC_LEFT (ic), ic, FALSE);
2205   size = AOP_SIZE (IC_LEFT (ic));
2206   offset = (size - 1);
2207   while (size--)
2208     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2209                                    FALSE, TRUE));
2210
2211   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2212 }
2213
2214 /*-----------------------------------------------------------------*/
2215 /* saveRBank - saves an entire register bank on the stack          */
2216 /*-----------------------------------------------------------------*/
2217 static void
2218 saveRBank (int bank, iCode * ic, bool pushPsw)
2219 {
2220   int i;
2221   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2222   asmop *aop = NULL;
2223   regs *r = NULL;
2224
2225   if (options.useXstack)
2226     {
2227       if (!ic)
2228       {
2229           /* Assume r0 is available for use. */
2230           r = mcs51_regWithIdx (R0_IDX);;
2231       }
2232       else
2233       {
2234           aop = newAsmop (0);
2235           r = getFreePtr (ic, &aop, FALSE);
2236       }
2237       // allocate space first
2238       emitcode ("mov", "%s,%s", r->name, spname);
2239       MOVA (r->name);
2240       emitcode ("add", "a,#%d", count);
2241       emitcode ("mov", "%s,a", spname);
2242     }
2243
2244   for (i = 0; i < mcs51_nRegs; i++)
2245     {
2246       if (options.useXstack)
2247         {
2248           emitcode ("mov", "a,(%s+%d)",
2249                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2250           emitcode ("movx", "@%s,a", r->name);
2251           if (--count)
2252             emitcode ("inc", "%s", r->name);
2253         }
2254       else
2255         emitcode ("push", "(%s+%d)",
2256                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2257     }
2258
2259   if (pushPsw)
2260     {
2261       if (options.useXstack)
2262         {
2263           emitcode ("mov", "a,psw");
2264           emitcode ("movx", "@%s,a", r->name);
2265
2266         }
2267       else
2268         {
2269           emitcode ("push", "psw");
2270         }
2271
2272       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2273     }
2274
2275   if (aop)
2276     {
2277       freeAsmop (NULL, aop, ic, TRUE);
2278     }
2279
2280   if (ic)
2281   {
2282     ic->bankSaved = 1;
2283   }
2284 }
2285
2286 /*-----------------------------------------------------------------*/
2287 /* unsaveRBank - restores the register bank from stack             */
2288 /*-----------------------------------------------------------------*/
2289 static void
2290 unsaveRBank (int bank, iCode * ic, bool popPsw)
2291 {
2292   int i;
2293   asmop *aop = NULL;
2294   regs *r = NULL;
2295
2296   if (options.useXstack)
2297     {
2298       if (!ic)
2299         {
2300           /* Assume r0 is available for use. */
2301           r = mcs51_regWithIdx (R0_IDX);;
2302         }
2303       else
2304         {
2305           aop = newAsmop (0);
2306           r = getFreePtr (ic, &aop, FALSE);
2307         }
2308       emitcode ("mov", "%s,%s", r->name, spname);
2309     }
2310
2311   if (popPsw)
2312     {
2313       if (options.useXstack)
2314         {
2315           emitcode ("dec", "%s", r->name);
2316           emitcode ("movx", "a,@%s", r->name);
2317           emitcode ("mov", "psw,a");
2318         }
2319       else
2320         {
2321           emitcode ("pop", "psw");
2322         }
2323     }
2324
2325   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2326     {
2327       if (options.useXstack)
2328         {
2329           emitcode ("dec", "%s", r->name);
2330           emitcode ("movx", "a,@%s", r->name);
2331           emitcode ("mov", "(%s+%d),a",
2332                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2333         }
2334       else
2335         {
2336           emitcode ("pop", "(%s+%d)",
2337                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2338         }
2339     }
2340
2341   if (options.useXstack)
2342     {
2343       emitcode ("mov", "%s,%s", spname, r->name);
2344     }
2345
2346   if (aop)
2347     {
2348       freeAsmop (NULL, aop, ic, TRUE);
2349     }
2350 }
2351
2352 /*-----------------------------------------------------------------*/
2353 /* genSend - gen code for SEND                                     */
2354 /*-----------------------------------------------------------------*/
2355 static void genSend(set *sendSet)
2356 {
2357     iCode *sic;
2358     int rb1_count = 0 ;
2359
2360     for (sic = setFirstItem (sendSet); sic;
2361          sic = setNextItem (sendSet)) {
2362           int size, offset = 0;
2363           aopOp (IC_LEFT (sic), sic, FALSE);
2364           size = AOP_SIZE (IC_LEFT (sic));
2365
2366           if (sic->argreg == 1) {
2367               while (size--) {
2368                   char *l = aopGet (IC_LEFT (sic), offset,
2369                                     FALSE, FALSE);
2370                   if (strcmp (l, fReturn[offset]))
2371                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2372                   offset++;
2373               }
2374               rb1_count = 0;
2375           } else {
2376               while (size--) {
2377                   emitcode ("mov","b1_%d,%s",rb1_count++,
2378                             aopGet (IC_LEFT (sic), offset++,FALSE, FALSE));
2379               }
2380           }
2381           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2382     }
2383 }
2384
2385 /*-----------------------------------------------------------------*/
2386 /* genCall - generates a call statement                            */
2387 /*-----------------------------------------------------------------*/
2388 static void
2389 genCall (iCode * ic)
2390 {
2391   sym_link *dtype;
2392 //  bool restoreBank = FALSE;
2393   bool swapBanks = FALSE;
2394   bool accuse = FALSE;
2395   bool accPushed = FALSE;
2396
2397   D(emitcode(";     genCall",""));
2398
2399   dtype = operandType (IC_LEFT (ic));
2400   /* if send set is not empty then assign */
2401   if (_G.sendSet)
2402     {
2403         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2404             genSend(reverseSet(_G.sendSet));
2405         } else {
2406             genSend(_G.sendSet);
2407         }
2408
2409       _G.sendSet = NULL;
2410     }
2411
2412   /* if we are calling a not _naked function that is not using
2413      the same register bank then we need to save the
2414      destination registers on the stack */
2415   dtype = operandType (IC_LEFT (ic));
2416   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2417       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2418        !IFFUNC_ISISR (dtype))
2419   {
2420       swapBanks = TRUE;
2421   }
2422
2423   /* if caller saves & we have not saved then */
2424   if (!ic->regsSaved)
2425       saveRegisters (ic);
2426
2427   if (swapBanks)
2428   {
2429         emitcode ("mov", "psw,#0x%02x",
2430            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2431   }
2432
2433   /* make the call */
2434   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2435     {
2436       if (IFFUNC_CALLEESAVES(dtype))
2437         {
2438           werror (E_BANKED_WITH_CALLEESAVES);
2439         }
2440       else
2441         {
2442           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2443                      OP_SYMBOL (IC_LEFT (ic))->rname :
2444                      OP_SYMBOL (IC_LEFT (ic))->name);
2445
2446           emitcode ("mov", "r0,#%s", l);
2447           emitcode ("mov", "r1,#(%s >> 8)", l);
2448           emitcode ("mov", "r2,#(%s >> 16)", l);
2449           emitcode ("lcall", "__sdcc_banked_call");
2450         }
2451     }
2452   else
2453     {
2454       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2455                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2456                                 OP_SYMBOL (IC_LEFT (ic))->name));
2457     }
2458
2459   if (swapBanks)
2460   {
2461        emitcode ("mov", "psw,#0x%02x",
2462           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2463   }
2464
2465   /* if we need assign a result value */
2466   if ((IS_ITEMP (IC_RESULT (ic)) &&
2467        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2468         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2469         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2470       IS_TRUE_SYMOP (IC_RESULT (ic)))
2471     {
2472
2473       _G.accInUse++;
2474       aopOp (IC_RESULT (ic), ic, FALSE);
2475       _G.accInUse--;
2476
2477       accuse = assignResultValue (IC_RESULT (ic));
2478
2479       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2480     }
2481
2482   /* adjust the stack for parameters if required */
2483   if (ic->parmBytes)
2484     {
2485       int i;
2486       if (ic->parmBytes > 3)
2487         {
2488           if (accuse)
2489             {
2490               emitcode ("push", "acc");
2491               accPushed = TRUE;
2492             }
2493
2494           emitcode ("mov", "a,%s", spname);
2495           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2496           emitcode ("mov", "%s,a", spname);
2497
2498           /* unsaveRegisters from xstack needs acc, but */
2499           /* unsaveRegisters from stack needs this popped */
2500           if (accPushed && !options.useXstack)
2501             {
2502               emitcode ("pop", "acc");
2503               accPushed = FALSE;
2504             }
2505         }
2506       else
2507         for (i = 0; i < ic->parmBytes; i++)
2508           emitcode ("dec", "%s", spname);
2509     }
2510
2511   /* if we hade saved some registers then unsave them */
2512   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2513     {
2514       if (accuse && !accPushed && options.useXstack)
2515         {
2516           /* xstack needs acc, but doesn't touch normal stack */
2517           emitcode ("push", "acc");
2518           accPushed = TRUE;
2519         }
2520       unsaveRegisters (ic);
2521     }
2522
2523 //  /* if register bank was saved then pop them */
2524 //  if (restoreBank)
2525 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2526
2527   if (accPushed)
2528     emitcode ("pop", "acc");
2529 }
2530
2531 /*-----------------------------------------------------------------*/
2532 /* -10l - generates a call by pointer statement                */
2533 /*-----------------------------------------------------------------*/
2534 static void
2535 genPcall (iCode * ic)
2536 {
2537   sym_link *dtype;
2538   sym_link *etype;
2539   symbol *rlbl = newiTempLabel (NULL);
2540 //  bool restoreBank=FALSE;
2541   bool swapBanks = FALSE;
2542
2543   D(emitcode(";     genPCall",""));
2544
2545   /* if caller saves & we have not saved then */
2546   if (!ic->regsSaved)
2547     saveRegisters (ic);
2548
2549   /* if we are calling a not _naked function that is not using
2550      the same register bank then we need to save the
2551      destination registers on the stack */
2552   dtype = operandType (IC_LEFT (ic))->next;
2553   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2554       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2555       !IFFUNC_ISISR (dtype))
2556   {
2557 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2558 //    restoreBank=TRUE;
2559       swapBanks = TRUE;
2560       // need caution message to user here
2561   }
2562
2563   etype = getSpec(dtype);
2564   if (IS_LITERAL(etype))
2565     {
2566       /* if send set is not empty then assign */
2567       if (_G.sendSet)
2568         {
2569           genSend(reverseSet(_G.sendSet));
2570           _G.sendSet = NULL;
2571         }
2572
2573       if (swapBanks)
2574         {
2575           emitcode ("mov", "psw,#0x%02x",
2576            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2577         }
2578
2579       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2580         {
2581           if (IFFUNC_CALLEESAVES(dtype))
2582             {
2583               werror (E_BANKED_WITH_CALLEESAVES);
2584             }
2585           else
2586             {
2587               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2588
2589               emitcode ("mov", "r0,#%s", l);
2590               emitcode ("mov", "r1,#(%s >> 8)", l);
2591               emitcode ("mov", "r2,#(%s >> 16)", l);
2592               emitcode ("lcall", "__sdcc_banked_call");
2593             }
2594         }
2595       else
2596         {
2597           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2598         }
2599     }
2600   else
2601     {
2602       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2603         {
2604           if (IFFUNC_CALLEESAVES(dtype))
2605             {
2606               werror (E_BANKED_WITH_CALLEESAVES);
2607             }
2608           else
2609             {
2610               aopOp (IC_LEFT (ic), ic, FALSE);
2611
2612               if (!swapBanks)
2613                 {
2614                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2615                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2616                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2617                 }
2618               else
2619                 {
2620                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2621                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2622                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2623                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2624                 }
2625
2626               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2627
2628               /* if send set is not empty then assign */
2629               if (_G.sendSet)
2630                 {
2631                   genSend(reverseSet(_G.sendSet));
2632                   _G.sendSet = NULL;
2633                 }
2634
2635               if (swapBanks)
2636                 {
2637                   emitcode ("mov", "psw,#0x%02x",
2638                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2639                 }
2640
2641               /* make the call */
2642               emitcode ("lcall", "__sdcc_banked_call");
2643             }
2644         }
2645       else
2646         {
2647           /* push the return address on to the stack */
2648           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2649           emitcode ("push", "acc");
2650           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2651           emitcode ("push", "acc");
2652
2653           /* now push the calling address */
2654           aopOp (IC_LEFT (ic), ic, FALSE);
2655
2656           pushSide (IC_LEFT (ic), FPTRSIZE);
2657
2658           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2659
2660           /* if send set is not empty the assign */
2661           if (_G.sendSet)
2662             {
2663               genSend(reverseSet(_G.sendSet));
2664               _G.sendSet = NULL;
2665             }
2666
2667           if (swapBanks)
2668             {
2669               emitcode ("mov", "psw,#0x%02x",
2670                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2671             }
2672
2673           /* make the call */
2674           emitcode ("ret", "");
2675           emitcode ("", "%05d$:", (rlbl->key + 100));
2676         }
2677     }
2678   if (swapBanks)
2679   {
2680        emitcode ("mov", "psw,#0x%02x",
2681           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2682   }
2683
2684   /* if we need assign a result value */
2685   if ((IS_ITEMP (IC_RESULT (ic)) &&
2686        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2687         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2688       IS_TRUE_SYMOP (IC_RESULT (ic)))
2689     {
2690
2691       _G.accInUse++;
2692       aopOp (IC_RESULT (ic), ic, FALSE);
2693       _G.accInUse--;
2694
2695       assignResultValue (IC_RESULT (ic));
2696
2697       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2698     }
2699
2700   /* adjust the stack for parameters if
2701      required */
2702   if (ic->parmBytes)
2703     {
2704       int i;
2705       if (ic->parmBytes > 3)
2706         {
2707           emitcode ("mov", "a,%s", spname);
2708           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2709           emitcode ("mov", "%s,a", spname);
2710         }
2711       else
2712         for (i = 0; i < ic->parmBytes; i++)
2713           emitcode ("dec", "%s", spname);
2714
2715     }
2716
2717 //  /* if register bank was saved then unsave them */
2718 //  if (restoreBank)
2719 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2720
2721   /* if we hade saved some registers then
2722      unsave them */
2723   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2724     unsaveRegisters (ic);
2725 }
2726
2727 /*-----------------------------------------------------------------*/
2728 /* resultRemat - result  is rematerializable                       */
2729 /*-----------------------------------------------------------------*/
2730 static int
2731 resultRemat (iCode * ic)
2732 {
2733   if (SKIP_IC (ic) || ic->op == IFX)
2734     return 0;
2735
2736   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2737     {
2738       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2739       if (sym->remat && !POINTER_SET (ic))
2740         return 1;
2741     }
2742
2743   return 0;
2744 }
2745
2746 #if defined(__BORLANDC__) || defined(_MSC_VER)
2747 #define STRCASECMP stricmp
2748 #else
2749 #define STRCASECMP strcasecmp
2750 #endif
2751
2752 /*-----------------------------------------------------------------*/
2753 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2754 /*-----------------------------------------------------------------*/
2755 static int
2756 regsCmp(void *p1, void *p2)
2757 {
2758   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2759 }
2760
2761 static bool
2762 inExcludeList (char *s)
2763 {
2764   const char *p = setFirstItem(options.excludeRegsSet);
2765
2766   if (p == NULL || STRCASECMP(p, "none") == 0)
2767     return FALSE;
2768
2769
2770   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2771 }
2772
2773 /*-----------------------------------------------------------------*/
2774 /* genFunction - generated code for function entry                 */
2775 /*-----------------------------------------------------------------*/
2776 static void
2777 genFunction (iCode * ic)
2778 {
2779   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2780   sym_link *ftype;
2781   bool     switchedPSW = FALSE;
2782   int      calleesaves_saved_register = -1;
2783   int      stackAdjust = sym->stack;
2784   int      accIsFree = sym->recvSize < 4;
2785   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2786   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2787
2788   _G.nRegsSaved = 0;
2789   /* create the function header */
2790   emitcode (";", "-----------------------------------------");
2791   emitcode (";", " function %s", sym->name);
2792   emitcode (";", "-----------------------------------------");
2793
2794   emitcode ("", "%s:", sym->rname);
2795   ftype = operandType (IC_LEFT (ic));
2796   _G.currentFunc = sym;
2797
2798   if (IFFUNC_ISNAKED(ftype))
2799   {
2800       emitcode(";", "naked function: no prologue.");
2801       return;
2802   }
2803
2804   /* here we need to generate the equates for the
2805      register bank if required */
2806   if (FUNC_REGBANK (ftype) != rbank)
2807     {
2808       int i;
2809
2810       rbank = FUNC_REGBANK (ftype);
2811       for (i = 0; i < mcs51_nRegs; i++)
2812         {
2813           if (strcmp (regs8051[i].base, "0") == 0)
2814             emitcode ("", "%s = 0x%02x",
2815                       regs8051[i].dname,
2816                       8 * rbank + regs8051[i].offset);
2817           else
2818             emitcode ("", "%s = %s + 0x%02x",
2819                       regs8051[i].dname,
2820                       regs8051[i].base,
2821                       8 * rbank + regs8051[i].offset);
2822         }
2823     }
2824
2825   /* if this is an interrupt service routine then
2826      save acc, b, dpl, dph  */
2827   if (IFFUNC_ISISR (sym->type))
2828     {
2829
2830       if (!inExcludeList ("acc"))
2831         emitcode ("push", "acc");
2832       if (!inExcludeList ("b"))
2833         emitcode ("push", "b");
2834       if (!inExcludeList ("dpl"))
2835         emitcode ("push", "dpl");
2836       if (!inExcludeList ("dph"))
2837         emitcode ("push", "dph");
2838       /* if this isr has no bank i.e. is going to
2839          run with bank 0 , then we need to save more
2840          registers :-) */
2841       if (!FUNC_REGBANK (sym->type))
2842         {
2843
2844           /* if this function does not call any other
2845              function then we can be economical and
2846              save only those registers that are used */
2847           if (!IFFUNC_HASFCALL(sym->type))
2848             {
2849               int i;
2850
2851               /* if any registers used */
2852               if (sym->regsUsed)
2853                 {
2854                   /* save the registers used */
2855                   for (i = 0; i < sym->regsUsed->size; i++)
2856                     {
2857                       if (bitVectBitValue (sym->regsUsed, i))
2858                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2859                     }
2860                 }
2861             }
2862           else
2863             {
2864
2865               /* this function has a function call. We cannot
2866                  determines register usage so we will have to push the
2867                  entire bank */
2868                 saveRBank (0, ic, FALSE);
2869                 if (options.parms_in_bank1) {
2870                     int i;
2871                     for (i=0; i < 8 ; i++ ) {
2872                         emitcode ("push","%s",rb1regs[i]);
2873                     }
2874                 }
2875             }
2876         }
2877         else
2878         {
2879             /* This ISR uses a non-zero bank.
2880              *
2881              * We assume that the bank is available for our
2882              * exclusive use.
2883              *
2884              * However, if this ISR calls a function which uses some
2885              * other bank, we must save that bank entirely.
2886              */
2887             unsigned long banksToSave = 0;
2888
2889             if (IFFUNC_HASFCALL(sym->type))
2890             {
2891
2892 #define MAX_REGISTER_BANKS 4
2893
2894                 iCode *i;
2895                 int ix;
2896
2897                 for (i = ic; i; i = i->next)
2898                 {
2899                     if (i->op == ENDFUNCTION)
2900                     {
2901                         /* we got to the end OK. */
2902                         break;
2903                     }
2904
2905                     if (i->op == CALL)
2906                     {
2907                         sym_link *dtype;
2908
2909                         dtype = operandType (IC_LEFT(i));
2910                         if (dtype
2911                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2912                         {
2913                              /* Mark this bank for saving. */
2914                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2915                              {
2916                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2917                              }
2918                              else
2919                              {
2920                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2921                              }
2922
2923                              /* And note that we don't need to do it in
2924                               * genCall.
2925                               */
2926                              i->bankSaved = 1;
2927                         }
2928                     }
2929                     if (i->op == PCALL)
2930                     {
2931                         /* This is a mess; we have no idea what
2932                          * register bank the called function might
2933                          * use.
2934                          *
2935                          * The only thing I can think of to do is
2936                          * throw a warning and hope.
2937                          */
2938                         werror(W_FUNCPTR_IN_USING_ISR);
2939                     }
2940                 }
2941
2942                 if (banksToSave && options.useXstack)
2943                 {
2944                     /* Since we aren't passing it an ic,
2945                      * saveRBank will assume r0 is available to abuse.
2946                      *
2947                      * So switch to our (trashable) bank now, so
2948                      * the caller's R0 isn't trashed.
2949                      */
2950                     emitcode ("push", "psw");
2951                     emitcode ("mov", "psw,#0x%02x",
2952                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2953                     switchedPSW = TRUE;
2954                 }
2955
2956                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2957                 {
2958                      if (banksToSave & (1 << ix))
2959                      {
2960                          saveRBank(ix, NULL, FALSE);
2961                      }
2962                 }
2963             }
2964             // TODO: this needs a closer look
2965             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2966         }
2967
2968       /* Set the register bank to the desired value if nothing else */
2969       /* has done so yet. */
2970       if (!switchedPSW)
2971         {
2972           emitcode ("push", "psw");
2973           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2974         }
2975     }
2976   else
2977     {
2978       /* This is a non-ISR function. The caller has already switched register */
2979       /* banks, if necessary, so just handle the callee-saves option. */
2980
2981       /* if callee-save to be used for this function
2982          then save the registers being used in this function */
2983       if (IFFUNC_CALLEESAVES(sym->type))
2984         {
2985           int i;
2986
2987           /* if any registers used */
2988           if (sym->regsUsed)
2989             {
2990               /* save the registers used */
2991               for (i = 0; i < sym->regsUsed->size; i++)
2992                 {
2993                   if (bitVectBitValue (sym->regsUsed, i))
2994                     {
2995                       /* remember one saved register for later usage */
2996                       if (calleesaves_saved_register < 0)
2997                         calleesaves_saved_register = i;
2998                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2999                       _G.nRegsSaved++;
3000                     }
3001                 }
3002             }
3003         }
3004     }
3005
3006
3007   if (fReentrant)
3008     {
3009       if (options.useXstack)
3010         {
3011           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3012             {
3013               emitcode ("mov", "r0,%s", spname);
3014               emitcode ("inc", "%s", spname);
3015               emitcode ("xch", "a,_bpx");
3016               emitcode ("movx", "@r0,a");
3017               emitcode ("inc", "r0");
3018               emitcode ("mov", "a,r0");
3019               emitcode ("xch", "a,_bpx");
3020             }
3021           if (sym->stack)
3022             {
3023               emitcode ("push", "_bp");     /* save the callers stack  */
3024               emitcode ("mov", "_bp,sp");
3025             }
3026         }
3027       else
3028         {
3029           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3030             {
3031               /* set up the stack */
3032               emitcode ("push", "_bp");     /* save the callers stack  */
3033               emitcode ("mov", "_bp,sp");
3034             }
3035         }
3036     }
3037
3038   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3039   /* before setting up the stack frame completely. */
3040   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3041     {
3042       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3043
3044       if (rsym->isitmp)
3045         {
3046           if (rsym && rsym->regType == REG_CND)
3047             rsym = NULL;
3048           if (rsym && (rsym->accuse || rsym->ruonly))
3049             rsym = NULL;
3050           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3051             rsym = rsym->usl.spillLoc;
3052         }
3053
3054       /* If the RECEIVE operand immediately spills to the first entry on the */
3055       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3056       /* rather than the usual @r0/r1 machinations. */
3057       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3058         {
3059           int ofs;
3060
3061           _G.current_iCode = ric;
3062           D(emitcode (";     genReceive",""));
3063           for (ofs=0; ofs < sym->recvSize; ofs++)
3064             {
3065               if (!strcmp (fReturn[ofs], "a"))
3066                 emitcode ("push", "acc");
3067               else
3068                 emitcode ("push", fReturn[ofs]);
3069             }
3070           stackAdjust -= sym->recvSize;
3071           if (stackAdjust<0)
3072             {
3073               assert (stackAdjust>=0);
3074               stackAdjust = 0;
3075             }
3076           _G.current_iCode = ic;
3077           ric->generated = 1;
3078           accIsFree = 1;
3079         }
3080       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3081       /* to free up the accumulator. */
3082       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3083         {
3084           int ofs;
3085
3086           _G.current_iCode = ric;
3087           D(emitcode (";     genReceive",""));
3088           for (ofs=0; ofs < sym->recvSize; ofs++)
3089             {
3090               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3091             }
3092           _G.current_iCode = ic;
3093           ric->generated = 1;
3094           accIsFree = 1;
3095         }
3096     }
3097
3098   /* adjust the stack for the function */
3099   if (stackAdjust)
3100     {
3101       int i = stackAdjust;
3102       if (i > 256)
3103         werror (W_STACK_OVERFLOW, sym->name);
3104
3105       if (i > 3 && accIsFree)
3106         {
3107           emitcode ("mov", "a,sp");
3108           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3109           emitcode ("mov", "sp,a");
3110         }
3111       else if (i > 5)
3112         {
3113           /* The accumulator is not free, so we will need another register */
3114           /* to clobber. No need to worry about a possible conflict with */
3115           /* the above early RECEIVE optimizations since they would have */
3116           /* freed the accumulator if they were generated. */
3117
3118           if (IFFUNC_CALLEESAVES(sym->type))
3119             {
3120               /* if it's a callee-saves function we need a saved register */
3121               if (calleesaves_saved_register >= 0)
3122                 {
3123                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3124                   emitcode ("mov", "a,sp");
3125                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3126                   emitcode ("mov", "sp,a");
3127                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3128                 }
3129               else
3130                 /* do it the hard way */
3131                 while (i--)
3132                   emitcode ("inc", "sp");
3133             }
3134           else
3135             {
3136               /* not callee-saves, we can clobber r0 */
3137               emitcode ("mov", "r0,a");
3138               emitcode ("mov", "a,sp");
3139               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3140               emitcode ("mov", "sp,a");
3141               emitcode ("mov", "a,r0");
3142             }
3143         }
3144       else
3145         while (i--)
3146           emitcode ("inc", "sp");
3147     }
3148
3149   if (sym->xstack)
3150     {
3151       char i = ((char) sym->xstack & 0xff);
3152
3153       if (i > 3 && accIsFree)
3154         {
3155           emitcode ("mov", "a,_spx");
3156           emitcode ("add", "a,#0x%02x", i);
3157           emitcode ("mov", "_spx,a");
3158         }
3159       else if (i > 5)
3160         {
3161           emitcode ("push", "acc");
3162           emitcode ("mov", "a,_spx");
3163           emitcode ("add", "a,#0x%02x", i);
3164           emitcode ("mov", "_spx,a");
3165           emitcode ("pop", "acc");
3166         }
3167       else
3168         {
3169           while (i--)
3170             emitcode ("inc", "_spx");
3171         }
3172     }
3173
3174   /* if critical function then turn interrupts off */
3175   if (IFFUNC_ISCRITICAL (ftype))
3176     {
3177       symbol *tlbl = newiTempLabel (NULL);
3178       emitcode ("setb", "c");
3179       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3180       emitcode ("clr", "c");
3181       emitcode ("", "%05d$:", (tlbl->key + 100));
3182       emitcode ("push", "psw"); /* save old ea via c in psw */
3183     }
3184 }
3185
3186 /*-----------------------------------------------------------------*/
3187 /* genEndFunction - generates epilogue for functions               */
3188 /*-----------------------------------------------------------------*/
3189 static void
3190 genEndFunction (iCode * ic)
3191 {
3192   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3193   lineNode *lnp = lineCurr;
3194   bitVect  *regsUsed;
3195   bitVect  *regsUsedPrologue;
3196   bitVect  *regsUnneeded;
3197   int      idx;
3198
3199   _G.currentFunc = NULL;
3200   if (IFFUNC_ISNAKED(sym->type))
3201   {
3202       emitcode(";", "naked function: no epilogue.");
3203       if (options.debug && currFunc)
3204         debugFile->writeEndFunction (currFunc, ic, 0);
3205       return;
3206   }
3207
3208   if (IFFUNC_ISCRITICAL (sym->type))
3209     {
3210       emitcode ("pop", "psw"); /* restore ea via c in psw */
3211       emitcode ("mov", "ea,c");
3212     }
3213
3214   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3215     {
3216       if (options.useXstack)
3217         {
3218           if (sym->stack)
3219             {
3220               emitcode ("mov", "sp,_bp");
3221               emitcode ("pop", "_bp");
3222             }
3223           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3224             {
3225               emitcode ("xch", "a,_bpx");
3226               emitcode ("mov", "r0,a");
3227               emitcode ("dec", "r0");
3228               emitcode ("movx", "a,@r0");
3229               emitcode ("xch", "a,_bpx");
3230               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3231             }
3232         }
3233       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3234         {
3235           emitcode ("mov", "sp,_bp");
3236           emitcode ("pop", "_bp");
3237         }
3238     }
3239
3240   /* restore the register bank  */
3241   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3242   {
3243     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3244      || !options.useXstack)
3245     {
3246         /* Special case of ISR using non-zero bank with useXstack
3247          * is handled below.
3248          */
3249         emitcode ("pop", "psw");
3250     }
3251   }
3252
3253   if (IFFUNC_ISISR (sym->type))
3254     {
3255
3256       /* now we need to restore the registers */
3257       /* if this isr has no bank i.e. is going to
3258          run with bank 0 , then we need to save more
3259          registers :-) */
3260       if (!FUNC_REGBANK (sym->type))
3261         {
3262           /* if this function does not call any other
3263              function then we can be economical and
3264              save only those registers that are used */
3265           if (!IFFUNC_HASFCALL(sym->type))
3266             {
3267               int i;
3268
3269               /* if any registers used */
3270               if (sym->regsUsed)
3271                 {
3272                   /* save the registers used */
3273                   for (i = sym->regsUsed->size; i >= 0; i--)
3274                     {
3275                       if (bitVectBitValue (sym->regsUsed, i))
3276                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3277                     }
3278                 }
3279             }
3280           else
3281             {
3282               if (options.parms_in_bank1) {
3283                   int i;
3284                   for (i = 7 ; i >= 0 ; i-- ) {
3285                       emitcode ("pop","%s",rb1regs[i]);
3286                   }
3287               }
3288               /* this function has  a function call cannot
3289                  determines register usage so we will have to pop the
3290                  entire bank */
3291               unsaveRBank (0, ic, FALSE);
3292             }
3293         }
3294         else
3295         {
3296             /* This ISR uses a non-zero bank.
3297              *
3298              * Restore any register banks saved by genFunction
3299              * in reverse order.
3300              */
3301             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3302             int ix;
3303
3304             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3305             {
3306                 if (savedBanks & (1 << ix))
3307                 {
3308                     unsaveRBank(ix, NULL, FALSE);
3309                 }
3310             }
3311
3312             if (options.useXstack)
3313             {
3314                 /* Restore bank AFTER calling unsaveRBank,
3315                  * since it can trash r0.
3316                  */
3317                 emitcode ("pop", "psw");
3318             }
3319         }
3320
3321       if (!inExcludeList ("dph"))
3322         emitcode ("pop", "dph");
3323       if (!inExcludeList ("dpl"))
3324         emitcode ("pop", "dpl");
3325       if (!inExcludeList ("b"))
3326         emitcode ("pop", "b");
3327       if (!inExcludeList ("acc"))
3328         emitcode ("pop", "acc");
3329
3330       /* if debug then send end of function */
3331       if (options.debug && currFunc)
3332         {
3333           debugFile->writeEndFunction (currFunc, ic, 1);
3334         }
3335
3336       emitcode ("reti", "");
3337     }
3338   else
3339     {
3340       if (IFFUNC_CALLEESAVES(sym->type))
3341         {
3342           int i;
3343
3344           /* if any registers used */
3345           if (sym->regsUsed)
3346             {
3347               /* save the registers used */
3348               for (i = sym->regsUsed->size; i >= 0; i--)
3349                 {
3350                   if (bitVectBitValue (sym->regsUsed, i) ||
3351                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3352                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3353                 }
3354             }
3355           else if (mcs51_ptrRegReq)
3356             {
3357               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3358               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3359             }
3360
3361         }
3362
3363       /* if debug then send end of function */
3364       if (options.debug && currFunc)
3365         {
3366           debugFile->writeEndFunction (currFunc, ic, 1);
3367         }
3368
3369       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3370         {
3371           emitcode ("ljmp", "__sdcc_banked_ret");
3372         }
3373       else
3374         {
3375           emitcode ("ret", "");
3376         }
3377     }
3378
3379   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3380     return;
3381
3382   /* If this was an interrupt handler using bank 0 that called another */
3383   /* function, then all registers must be saved; nothing to optimized. */
3384   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3385       && !FUNC_REGBANK(sym->type))
3386     return;
3387
3388   /* There are no push/pops to optimize if not callee-saves or ISR */
3389   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3390     return;
3391
3392   /* If there were stack parameters, we cannot optimize without also    */
3393   /* fixing all of the stack offsets; this is too dificult to consider. */
3394   if (FUNC_HASSTACKPARM(sym->type))
3395     return;
3396
3397   /* Compute the registers actually used */
3398   regsUsed = newBitVect (mcs51_nRegs);
3399   regsUsedPrologue = newBitVect (mcs51_nRegs);
3400   while (lnp)
3401     {
3402       if (lnp->ic && lnp->ic->op == FUNCTION)
3403         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3404       else
3405         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3406
3407       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3408           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3409         break;
3410       if (!lnp->prev)
3411         break;
3412       lnp = lnp->prev;
3413     }
3414
3415   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3416       && !bitVectBitValue (regsUsed, CND_IDX))
3417     {
3418       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3419       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3420           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3421         bitVectUnSetBit (regsUsed, CND_IDX);
3422     }
3423   else
3424     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3425
3426   /* If this was an interrupt handler that called another function */
3427   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3428   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3429     {
3430       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3431       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3432       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3433       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3434       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3435     }
3436
3437   /* Remove the unneeded push/pops */
3438   regsUnneeded = newBitVect (mcs51_nRegs);
3439   while (lnp)
3440     {
3441       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3442         {
3443           if (!strncmp(lnp->line, "push", 4))
3444             {
3445               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3446               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3447                 {
3448                   connectLine (lnp->prev, lnp->next);
3449                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3450                 }
3451             }
3452           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3453             {
3454               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3455               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3456                 {
3457                   connectLine (lnp->prev, lnp->next);
3458                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3459                 }
3460             }
3461         }
3462       lnp = lnp->next;
3463     }
3464
3465   for (idx = 0; idx < regsUnneeded->size; idx++)
3466     if (bitVectBitValue (regsUnneeded, idx))
3467       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3468
3469   freeBitVect (regsUnneeded);
3470   freeBitVect (regsUsed);
3471   freeBitVect (regsUsedPrologue);
3472 }
3473
3474 /*-----------------------------------------------------------------*/
3475 /* genRet - generate code for return statement                     */
3476 /*-----------------------------------------------------------------*/
3477 static void
3478 genRet (iCode * ic)
3479 {
3480   int size, offset = 0, pushed = 0;
3481
3482   D(emitcode (";     genRet",""));
3483
3484   /* if we have no return value then
3485      just generate the "ret" */
3486   if (!IC_LEFT (ic))
3487     goto jumpret;
3488
3489   /* we have something to return then
3490      move the return value into place */
3491   aopOp (IC_LEFT (ic), ic, FALSE);
3492   size = AOP_SIZE (IC_LEFT (ic));
3493
3494   while (size--)
3495     {
3496       char *l;
3497       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3498         {
3499           /* #NOCHANGE */
3500           l = aopGet (IC_LEFT (ic), offset++,
3501                       FALSE, TRUE);
3502           emitcode ("push", "%s", l);
3503           pushed++;
3504         }
3505       else
3506         {
3507           l = aopGet (IC_LEFT (ic), offset,
3508                       FALSE, FALSE);
3509           if (strcmp (fReturn[offset], l))
3510             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3511         }
3512     }
3513
3514   if (pushed)
3515     {
3516       while (pushed)
3517         {
3518           pushed--;
3519           if (strcmp (fReturn[pushed], "a"))
3520             emitcode ("pop", fReturn[pushed]);
3521           else
3522             emitcode ("pop", "acc");
3523         }
3524     }
3525   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3526
3527 jumpret:
3528   /* generate a jump to the return label
3529      if the next is not the return statement */
3530   if (!(ic->next && ic->next->op == LABEL &&
3531         IC_LABEL (ic->next) == returnLabel))
3532
3533     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3534
3535 }
3536
3537 /*-----------------------------------------------------------------*/
3538 /* genLabel - generates a label                                    */
3539 /*-----------------------------------------------------------------*/
3540 static void
3541 genLabel (iCode * ic)
3542 {
3543   /* special case never generate */
3544   if (IC_LABEL (ic) == entryLabel)
3545     return;
3546
3547   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3548 }
3549
3550 /*-----------------------------------------------------------------*/
3551 /* genGoto - generates a ljmp                                      */
3552 /*-----------------------------------------------------------------*/
3553 static void
3554 genGoto (iCode * ic)
3555 {
3556   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3557 }
3558
3559 /*-----------------------------------------------------------------*/
3560 /* findLabelBackwards: walks back through the iCode chain looking  */
3561 /* for the given label. Returns number of iCode instructions     */
3562 /* between that label and given ic.          */
3563 /* Returns zero if label not found.          */
3564 /*-----------------------------------------------------------------*/
3565 static int
3566 findLabelBackwards (iCode * ic, int key)
3567 {
3568   int count = 0;
3569
3570   while (ic->prev)
3571     {
3572       ic = ic->prev;
3573       count++;
3574
3575       /* If we have any pushes or pops, we cannot predict the distance.
3576          I don't like this at all, this should be dealt with in the
3577          back-end */
3578       if (ic->op == IPUSH || ic->op == IPOP) {
3579         return 0;
3580       }
3581
3582       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3583         {
3584           return count;
3585         }
3586     }
3587
3588   return 0;
3589 }
3590
3591 /*-----------------------------------------------------------------*/
3592 /* genPlusIncr :- does addition with increment if possible         */
3593 /*-----------------------------------------------------------------*/
3594 static bool
3595 genPlusIncr (iCode * ic)
3596 {
3597   unsigned int icount;
3598   unsigned int size = getDataSize (IC_RESULT (ic));
3599
3600   /* will try to generate an increment */
3601   /* if the right side is not a literal
3602      we cannot */
3603   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3604     return FALSE;
3605
3606   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3607
3608   D(emitcode (";     genPlusIncr",""));
3609
3610   /* if increment >=16 bits in register or direct space */
3611   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3612       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3613       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3614       (size > 1) &&
3615       (icount == 1))
3616     {
3617       symbol *tlbl;
3618       int emitTlbl;
3619       int labelRange;
3620
3621       /* If the next instruction is a goto and the goto target
3622        * is < 10 instructions previous to this, we can generate
3623        * jumps straight to that target.
3624        */
3625       if (ic->next && ic->next->op == GOTO
3626           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3627           && labelRange <= 10)
3628         {
3629           emitcode (";", "tail increment optimized");
3630           tlbl = IC_LABEL (ic->next);
3631           emitTlbl = 0;
3632         }
3633       else
3634         {
3635           tlbl = newiTempLabel (NULL);
3636           emitTlbl = 1;
3637         }
3638       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3639       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3640           IS_AOP_PREG (IC_RESULT (ic)))
3641         emitcode ("cjne", "%s,#0x00,%05d$",
3642                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3643                   tlbl->key + 100);
3644       else
3645         {
3646           emitcode ("clr", "a");
3647           emitcode ("cjne", "a,%s,%05d$",
3648                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3649                     tlbl->key + 100);
3650         }
3651
3652       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3653       if (size > 2)
3654         {
3655           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3656               IS_AOP_PREG (IC_RESULT (ic)))
3657             emitcode ("cjne", "%s,#0x00,%05d$",
3658                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3659                       tlbl->key + 100);
3660           else
3661             emitcode ("cjne", "a,%s,%05d$",
3662                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3663                       tlbl->key + 100);
3664
3665           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3666         }
3667       if (size > 3)
3668         {
3669           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3670               IS_AOP_PREG (IC_RESULT (ic)))
3671             emitcode ("cjne", "%s,#0x00,%05d$",
3672                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3673                       tlbl->key + 100);
3674           else
3675             {
3676               emitcode ("cjne", "a,%s,%05d$",
3677                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3678                         tlbl->key + 100);
3679             }
3680           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3681         }
3682
3683       if (emitTlbl)
3684         {
3685           emitcode ("", "%05d$:", tlbl->key + 100);
3686         }
3687       return TRUE;
3688     }
3689
3690   /* if result is dptr */
3691   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
3692       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
3693       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
3694       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
3695     {
3696       if (aopGetUsesAcc (IC_LEFT (ic), 0))
3697         return FALSE;
3698
3699       if (icount > 9)
3700         return FALSE;
3701
3702       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
3703         return FALSE;
3704
3705       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
3706       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
3707       while (icount--)
3708         emitcode ("inc", "dptr");
3709
3710       return TRUE;
3711     }
3712
3713   /* if the literal value of the right hand side
3714      is greater than 4 then it is not worth it */
3715   if (icount > 4)
3716     return FALSE;
3717
3718   /* if the sizes are greater than 1 then we cannot */
3719   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3720       AOP_SIZE (IC_LEFT (ic)) > 1)
3721     return FALSE;
3722
3723   /* we can if the aops of the left & result match or
3724      if they are in registers and the registers are the
3725      same */
3726   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3727     {
3728
3729       if (icount > 3)
3730         {
3731           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3732           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3733           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3734         }
3735       else
3736         {
3737
3738           while (icount--)
3739             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3740         }
3741
3742       return TRUE;
3743     }
3744
3745   return FALSE;
3746 }
3747
3748 /*-----------------------------------------------------------------*/
3749 /* outBitAcc - output a bit in acc                                 */
3750 /*-----------------------------------------------------------------*/
3751 static void
3752 outBitAcc (operand * result)
3753 {
3754   symbol *tlbl = newiTempLabel (NULL);
3755   /* if the result is a bit */
3756   if (AOP_TYPE (result) == AOP_CRY)
3757     {
3758       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
3759     }
3760   else
3761     {
3762       emitcode ("jz", "%05d$", tlbl->key + 100);
3763       emitcode ("mov", "a,%s", one);
3764       emitcode ("", "%05d$:", tlbl->key + 100);
3765       outAcc (result);
3766     }
3767 }
3768
3769 /*-----------------------------------------------------------------*/
3770 /* genPlusBits - generates code for addition of two bits           */
3771 /*-----------------------------------------------------------------*/
3772 static void
3773 genPlusBits (iCode * ic)
3774 {
3775   D(emitcode (";     genPlusBits",""));
3776
3777   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3778     {
3779       symbol *lbl = newiTempLabel (NULL);
3780       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3781       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3782       emitcode ("cpl", "c");
3783       emitcode ("", "%05d$:", (lbl->key + 100));
3784       outBitC (IC_RESULT (ic));
3785     }
3786   else
3787     {
3788       emitcode ("clr", "a");
3789       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3790       emitcode ("rlc", "a");
3791       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3792       emitcode ("addc", "a,#0x00");
3793       outAcc (IC_RESULT (ic));
3794     }
3795 }
3796
3797 #if 0
3798 /* This is the original version of this code.
3799
3800  * This is being kept around for reference,
3801  * because I am not entirely sure I got it right...
3802  */
3803 static void
3804 adjustArithmeticResult (iCode * ic)
3805 {
3806   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3807       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3808       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3809     aopPut (IC_RESULT (ic),
3810             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
3811             2,
3812             isOperandVolatile (IC_RESULT (ic), FALSE));
3813
3814   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3815       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3816       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3817     aopPut (IC_RESULT (ic),
3818             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
3819             2,
3820             isOperandVolatile (IC_RESULT (ic), FALSE));
3821
3822   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3823       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3824       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3825       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3826       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3827     {
3828       char buffer[5];
3829       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3830       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3831     }
3832 }
3833 #else
3834 /* This is the pure and virtuous version of this code.
3835  * I'm pretty certain it's right, but not enough to toss the old
3836  * code just yet...
3837  */
3838 static void
3839 adjustArithmeticResult (iCode * ic)
3840 {
3841   if (opIsGptr (IC_RESULT (ic)) &&
3842       opIsGptr (IC_LEFT (ic)) &&
3843       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3844     {
3845       aopPut (IC_RESULT (ic),
3846               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
3847               GPTRSIZE - 1,
3848               isOperandVolatile (IC_RESULT (ic), FALSE));
3849     }
3850
3851   if (opIsGptr (IC_RESULT (ic)) &&
3852       opIsGptr (IC_RIGHT (ic)) &&
3853       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3854     {
3855       aopPut (IC_RESULT (ic),
3856               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
3857               GPTRSIZE - 1,
3858               isOperandVolatile (IC_RESULT (ic), FALSE));
3859     }
3860
3861   if (opIsGptr (IC_RESULT (ic)) &&
3862       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3863       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3864       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3865       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3866     {
3867       char buffer[5];
3868       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3869       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3870     }
3871 }
3872 #endif
3873
3874 /*-----------------------------------------------------------------*/
3875 /* genPlus - generates code for addition                           */
3876 /*-----------------------------------------------------------------*/
3877 static void
3878 genPlus (iCode * ic)
3879 {
3880   int size, offset = 0;
3881   int skip_bytes = 0;
3882   char *add = "add";
3883   operand *leftOp, *rightOp;
3884   operand * op;
3885
3886   /* special cases :- */
3887
3888   D(emitcode (";     genPlus",""));
3889
3890   aopOp (IC_LEFT (ic), ic, FALSE);
3891   aopOp (IC_RIGHT (ic), ic, FALSE);
3892   aopOp (IC_RESULT (ic), ic, TRUE);
3893
3894   /* if literal, literal on the right or
3895      if left requires ACC or right is already
3896      in ACC */
3897   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3898       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3899       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3900     {
3901       operand *t = IC_RIGHT (ic);
3902       IC_RIGHT (ic) = IC_LEFT (ic);
3903       IC_LEFT (ic) = t;
3904     }
3905
3906   /* if both left & right are in bit
3907      space */
3908   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3909       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3910     {
3911       genPlusBits (ic);
3912       goto release;
3913     }
3914
3915   /* if left in bit space & right literal */
3916   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3917       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3918     {
3919       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3920       /* if result in bit space */
3921       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3922         {
3923           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3924             emitcode ("cpl", "c");
3925           outBitC (IC_RESULT (ic));
3926         }
3927       else
3928         {
3929           size = getDataSize (IC_RESULT (ic));
3930           while (size--)
3931             {
3932               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
3933               emitcode ("addc", "a,#00");
3934               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3935             }
3936         }
3937       goto release;
3938     }
3939
3940   /* if I can do an increment instead
3941      of add then GOOD for ME */
3942   if (genPlusIncr (ic) == TRUE)
3943     goto release;
3944
3945   size = getDataSize (IC_RESULT (ic));
3946   leftOp = IC_LEFT(ic);
3947   rightOp = IC_RIGHT(ic);
3948   op=IC_LEFT(ic);
3949
3950   /* if this is an add for an array access
3951      at a 256 byte boundary */
3952   if ( 2 == size
3953        && AOP_TYPE (op) == AOP_IMMD
3954        && IS_SYMOP (op)
3955        && IS_SPEC (OP_SYM_ETYPE (op))
3956        && SPEC_ABSA (OP_SYM_ETYPE (op))
3957        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3958      )
3959     {
3960       D(emitcode (";     genPlus aligned array",""));
3961       aopPut (IC_RESULT (ic),
3962               aopGet (rightOp, 0, FALSE, FALSE),
3963               0,
3964               isOperandVolatile (IC_RESULT (ic), FALSE));
3965
3966       if( 1 == getDataSize (IC_RIGHT (ic)) )
3967         {
3968           aopPut (IC_RESULT (ic),
3969                   aopGet (leftOp, 1, FALSE, FALSE),
3970                   1,
3971                   isOperandVolatile (IC_RESULT (ic), FALSE));
3972         }
3973       else
3974         {
3975           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
3976           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3977           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3978         }
3979       goto release;
3980     }
3981
3982   /* if the lower bytes of a literal are zero skip the addition */
3983   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3984     {
3985        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3986               (skip_bytes+1 < size))
3987          {
3988            skip_bytes++;
3989          }
3990        if (skip_bytes)
3991          D(emitcode (";     genPlus shortcut",""));
3992     }
3993
3994   while (size--)
3995     {
3996       if( offset >= skip_bytes )
3997         {
3998           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3999             {
4000               bool pushedB;
4001               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4002               pushedB = pushB ();
4003               emitcode("xch", "a,b");
4004               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4005               emitcode (add, "a,b");
4006               popB (pushedB);
4007             }
4008           else if (aopGetUsesAcc (leftOp, offset))
4009             {
4010               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4011               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4012             }
4013           else
4014             {
4015               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4016               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4017             }
4018           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4019           add = "addc";  /* further adds must propagate carry */
4020         }
4021       else
4022         {
4023           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4024               isOperandVolatile (IC_RESULT (ic), FALSE))
4025             {
4026               /* just move */
4027               aopPut (IC_RESULT (ic),
4028                       aopGet (leftOp, offset, FALSE, FALSE),
4029                       offset,
4030                       isOperandVolatile (IC_RESULT (ic), FALSE));
4031             }
4032         }
4033       offset++;
4034     }
4035
4036   adjustArithmeticResult (ic);
4037
4038 release:
4039   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4040   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4041   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4042 }
4043
4044 /*-----------------------------------------------------------------*/
4045 /* genMinusDec :- does subtraction with deccrement if possible     */
4046 /*-----------------------------------------------------------------*/
4047 static bool
4048 genMinusDec (iCode * ic)
4049 {
4050   unsigned int icount;
4051   unsigned int size = getDataSize (IC_RESULT (ic));
4052
4053   /* will try to generate an increment */
4054   /* if the right side is not a literal
4055      we cannot */
4056   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4057     return FALSE;
4058
4059   /* if the literal value of the right hand side
4060      is greater than 4 then it is not worth it */
4061   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4062     return FALSE;
4063
4064   D(emitcode (";     genMinusDec",""));
4065
4066   /* if decrement >=16 bits in register or direct space */
4067   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4068       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4069       (size > 1) &&
4070       (icount == 1))
4071     {
4072       symbol *tlbl;
4073       int emitTlbl;
4074       int labelRange;
4075
4076       /* If the next instruction is a goto and the goto target
4077        * is <= 10 instructions previous to this, we can generate
4078        * jumps straight to that target.
4079        */
4080       if (ic->next && ic->next->op == GOTO
4081           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4082           && labelRange <= 10)
4083         {
4084           emitcode (";", "tail decrement optimized");
4085           tlbl = IC_LABEL (ic->next);
4086           emitTlbl = 0;
4087         }
4088       else
4089         {
4090           tlbl = newiTempLabel (NULL);
4091           emitTlbl = 1;
4092         }
4093
4094       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4095       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4096           IS_AOP_PREG (IC_RESULT (ic)))
4097         emitcode ("cjne", "%s,#0xff,%05d$"
4098                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4099                   ,tlbl->key + 100);
4100       else
4101         {
4102           emitcode ("mov", "a,#0xff");
4103           emitcode ("cjne", "a,%s,%05d$"
4104                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4105                     ,tlbl->key + 100);
4106         }
4107       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4108       if (size > 2)
4109         {
4110           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4111               IS_AOP_PREG (IC_RESULT (ic)))
4112             emitcode ("cjne", "%s,#0xff,%05d$"
4113                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4114                       ,tlbl->key + 100);
4115           else
4116             {
4117               emitcode ("cjne", "a,%s,%05d$"
4118                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4119                         ,tlbl->key + 100);
4120             }
4121           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4122         }
4123       if (size > 3)
4124         {
4125           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4126               IS_AOP_PREG (IC_RESULT (ic)))
4127             emitcode ("cjne", "%s,#0xff,%05d$"
4128                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4129                       ,tlbl->key + 100);
4130           else
4131             {
4132               emitcode ("cjne", "a,%s,%05d$"
4133                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4134                         ,tlbl->key + 100);
4135             }
4136           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4137         }
4138       if (emitTlbl)
4139         {
4140           emitcode ("", "%05d$:", tlbl->key + 100);
4141         }
4142       return TRUE;
4143     }
4144
4145   /* if the sizes are greater than 1 then we cannot */
4146   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4147       AOP_SIZE (IC_LEFT (ic)) > 1)
4148     return FALSE;
4149
4150   /* we can if the aops of the left & result match or
4151      if they are in registers and the registers are the
4152      same */
4153   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4154     {
4155
4156       while (icount--)
4157         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4158
4159       return TRUE;
4160     }
4161
4162   return FALSE;
4163 }
4164
4165 /*-----------------------------------------------------------------*/
4166 /* addSign - complete with sign                                    */
4167 /*-----------------------------------------------------------------*/
4168 static void
4169 addSign (operand * result, int offset, int sign)
4170 {
4171   int size = (getDataSize (result) - offset);
4172   if (size > 0)
4173     {
4174       if (sign)
4175         {
4176           emitcode ("rlc", "a");
4177           emitcode ("subb", "a,acc");
4178           while (size--)
4179             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4180         }
4181       else
4182         while (size--)
4183           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4184     }
4185 }
4186
4187 /*-----------------------------------------------------------------*/
4188 /* genMinusBits - generates code for subtraction  of two bits      */
4189 /*-----------------------------------------------------------------*/
4190 static void
4191 genMinusBits (iCode * ic)
4192 {
4193   symbol *lbl = newiTempLabel (NULL);
4194
4195   D(emitcode (";     genMinusBits",""));
4196
4197   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4198     {
4199       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4200       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4201       emitcode ("cpl", "c");
4202       emitcode ("", "%05d$:", (lbl->key + 100));
4203       outBitC (IC_RESULT (ic));
4204     }
4205   else
4206     {
4207       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4208       emitcode ("subb", "a,acc");
4209       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4210       emitcode ("inc", "a");
4211       emitcode ("", "%05d$:", (lbl->key + 100));
4212       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4213       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4214     }
4215 }
4216
4217 /*-----------------------------------------------------------------*/
4218 /* genMinus - generates code for subtraction                       */
4219 /*-----------------------------------------------------------------*/
4220 static void
4221 genMinus (iCode * ic)
4222 {
4223   int size, offset = 0;
4224
4225   D(emitcode (";     genMinus",""));
4226
4227   aopOp (IC_LEFT (ic), ic, FALSE);
4228   aopOp (IC_RIGHT (ic), ic, FALSE);
4229   aopOp (IC_RESULT (ic), ic, TRUE);
4230
4231   /* special cases :- */
4232   /* if both left & right are in bit space */
4233   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4234       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4235     {
4236       genMinusBits (ic);
4237       goto release;
4238     }
4239
4240   /* if I can do an decrement instead
4241      of subtract then GOOD for ME */
4242   if (genMinusDec (ic) == TRUE)
4243     goto release;
4244
4245   size = getDataSize (IC_RESULT (ic));
4246
4247   /* if literal, add a,#-lit, else normal subb */
4248   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4249     {
4250       unsigned long lit = 0L;
4251       bool useCarry = FALSE;
4252
4253       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4254       lit = -(long) lit;
4255
4256       while (size--)
4257         {
4258           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL)) {
4259             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4260             if (!offset && !size && lit== (unsigned long) -1) {
4261               emitcode ("dec", "a");
4262             } else if (!useCarry) {
4263           /* first add without previous c */
4264               emitcode ("add", "a,#0x%02x",
4265                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4266               useCarry = TRUE;
4267           } else {
4268             emitcode ("addc", "a,#0x%02x",
4269                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4270           }
4271             aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4272             } else {
4273               /* no need to add zeroes */
4274               offset++;
4275             }
4276         }
4277     }
4278   else
4279     {
4280       operand *leftOp, *rightOp;
4281
4282       leftOp = IC_LEFT(ic);
4283       rightOp = IC_RIGHT(ic);
4284
4285       while (size--)
4286         {
4287           if (aopGetUsesAcc(rightOp, offset)) {
4288             if (aopGetUsesAcc(leftOp, offset)) {
4289               bool pushedB;
4290
4291               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4292               pushedB = pushB ();
4293               emitcode ("mov", "b,a");
4294               if (offset == 0)
4295                 CLRC;
4296               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4297               emitcode ("subb", "a,b");
4298               popB (pushedB);
4299             } else {
4300               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4301               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4302               if (offset == 0) {
4303                 emitcode( "setb", "c");
4304               }
4305               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4306               emitcode("cpl", "a");
4307             }
4308           } else {
4309             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4310             if (offset == 0)
4311               CLRC;
4312             emitcode ("subb", "a,%s",
4313                       aopGet(rightOp, offset, FALSE, TRUE));
4314           }
4315
4316           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4317         }
4318     }
4319
4320
4321   adjustArithmeticResult (ic);
4322
4323 release:
4324   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4325   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4326   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4327 }
4328
4329
4330 /*-----------------------------------------------------------------*/
4331 /* genMultbits :- multiplication of bits                           */
4332 /*-----------------------------------------------------------------*/
4333 static void
4334 genMultbits (operand * left,
4335              operand * right,
4336              operand * result)
4337 {
4338   D(emitcode (";     genMultbits",""));
4339
4340   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4341   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4342   outBitC (result);
4343 }
4344
4345 /*-----------------------------------------------------------------*/
4346 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4347 /*-----------------------------------------------------------------*/
4348 static void
4349 genMultOneByte (operand * left,
4350                 operand * right,
4351                 operand * result)
4352 {
4353   symbol *lbl;
4354   int size = AOP_SIZE (result);
4355   bool runtimeSign, compiletimeSign;
4356   bool lUnsigned, rUnsigned, pushedB;
4357
4358   D(emitcode (";     genMultOneByte",""));
4359
4360   if (size < 1 || size > 2)
4361     {
4362       /* this should never happen */
4363       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4364                AOP_SIZE(result), __FILE__, lineno);
4365       exit (1);
4366     }
4367
4368   /* (if two literals: the value is computed before) */
4369   /* if one literal, literal on the right */
4370   if (AOP_TYPE (left) == AOP_LIT)
4371     {
4372       operand *t = right;
4373       right = left;
4374       left = t;
4375       /* emitcode (";", "swapped left and right"); */
4376     }
4377   /* if no literal, unsigned on the right: shorter code */
4378   if (   AOP_TYPE (right) != AOP_LIT
4379       && SPEC_USIGN (getSpec (operandType (left))))
4380     {
4381       operand *t = right;
4382       right = left;
4383       left = t;
4384     }
4385
4386   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4387   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4388
4389   pushedB = pushB ();
4390
4391   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4392                    no need to take care about the signedness! */
4393       || (lUnsigned && rUnsigned))
4394     {
4395       /* just an unsigned 8 * 8 = 8 multiply
4396          or 8u * 8u = 16u */
4397       /* emitcode (";","unsigned"); */
4398       /* TODO: check for accumulator clash between left & right aops? */
4399
4400       if (AOP_TYPE (right) == AOP_LIT)
4401         {
4402           /* moving to accumulator first helps peepholes */
4403           MOVA (aopGet (left, 0, FALSE, FALSE));
4404           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4405         }
4406       else
4407         {
4408           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4409           MOVA (aopGet (left, 0, FALSE, FALSE));
4410         }
4411
4412       emitcode ("mul", "ab");
4413       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4414       if (size == 2)
4415         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4416
4417       popB (pushedB);
4418       return;
4419     }
4420
4421   /* we have to do a signed multiply */
4422   /* emitcode (";", "signed"); */
4423
4424   /* now sign adjust for both left & right */
4425
4426   /* let's see what's needed: */
4427   /* apply negative sign during runtime */
4428   runtimeSign = FALSE;
4429   /* negative sign from literals */
4430   compiletimeSign = FALSE;
4431
4432   if (!lUnsigned)
4433     {
4434       if (AOP_TYPE(left) == AOP_LIT)
4435         {
4436           /* signed literal */
4437           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4438           if (val < 0)
4439             compiletimeSign = TRUE;
4440         }
4441       else
4442         /* signed but not literal */
4443         runtimeSign = TRUE;
4444     }
4445
4446   if (!rUnsigned)
4447     {
4448       if (AOP_TYPE(right) == AOP_LIT)
4449         {
4450           /* signed literal */
4451           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4452           if (val < 0)
4453             compiletimeSign ^= TRUE;
4454         }
4455       else
4456         /* signed but not literal */
4457         runtimeSign = TRUE;
4458     }
4459
4460   /* initialize F0, which stores the runtime sign */
4461   if (runtimeSign)
4462     {
4463       if (compiletimeSign)
4464         emitcode ("setb", "F0"); /* set sign flag */
4465       else
4466         emitcode ("clr", "F0"); /* reset sign flag */
4467     }
4468
4469   /* save the signs of the operands */
4470   if (AOP_TYPE(right) == AOP_LIT)
4471     {
4472       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4473
4474       if (!rUnsigned && val < 0)
4475         emitcode ("mov", "b,#0x%02x", -val);
4476       else
4477         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4478     }
4479   else /* ! literal */
4480     {
4481       if (rUnsigned)  /* emitcode (";", "signed"); */
4482
4483         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4484       else
4485         {
4486           MOVA (aopGet (right, 0, FALSE, FALSE));
4487           lbl = newiTempLabel (NULL);
4488           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4489           emitcode ("cpl", "F0"); /* complement sign flag */
4490           emitcode ("cpl", "a");  /* 2's complement */
4491           emitcode ("inc", "a");
4492           emitcode ("", "%05d$:", (lbl->key + 100));
4493           emitcode ("mov", "b,a");
4494         }
4495     }
4496
4497   if (AOP_TYPE(left) == AOP_LIT)
4498     {
4499       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4500
4501       if (!lUnsigned && val < 0)
4502         emitcode ("mov", "a,#0x%02x", -val);
4503       else
4504         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4505     }
4506   else /* ! literal */
4507     {
4508       MOVA (aopGet (left, 0, FALSE, FALSE));
4509
4510       if (!lUnsigned)
4511         {
4512           lbl = newiTempLabel (NULL);
4513           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4514           emitcode ("cpl", "F0"); /* complement sign flag */
4515           emitcode ("cpl", "a"); /* 2's complement */
4516           emitcode ("inc", "a");
4517           emitcode ("", "%05d$:", (lbl->key + 100));
4518         }
4519     }
4520
4521   /* now the multiplication */
4522   emitcode ("mul", "ab");
4523   if (runtimeSign || compiletimeSign)
4524     {
4525       lbl = newiTempLabel (NULL);
4526       if (runtimeSign)
4527         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4528       emitcode ("cpl", "a"); /* lsb 2's complement */
4529       if (size != 2)
4530         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4531       else
4532         {
4533           emitcode ("add", "a,#1"); /* this sets carry flag */
4534           emitcode ("xch", "a,b");
4535           emitcode ("cpl", "a"); /* msb 2's complement */
4536           emitcode ("addc", "a,#0");
4537           emitcode ("xch", "a,b");
4538         }
4539       emitcode ("", "%05d$:", (lbl->key + 100));
4540     }
4541   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4542   if (size == 2)
4543     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4544
4545   popB (pushedB);
4546 }
4547
4548 /*-----------------------------------------------------------------*/
4549 /* genMult - generates code for multiplication                     */
4550 /*-----------------------------------------------------------------*/
4551 static void
4552 genMult (iCode * ic)
4553 {
4554   operand *left = IC_LEFT (ic);
4555   operand *right = IC_RIGHT (ic);
4556   operand *result = IC_RESULT (ic);
4557
4558   D(emitcode (";     genMult",""));
4559
4560   /* assign the amsops */
4561   aopOp (left, ic, FALSE);
4562   aopOp (right, ic, FALSE);
4563   aopOp (result, ic, TRUE);
4564
4565   /* special cases first */
4566   /* both are bits */
4567   if (AOP_TYPE (left) == AOP_CRY &&
4568       AOP_TYPE (right) == AOP_CRY)
4569     {
4570       genMultbits (left, right, result);
4571       goto release;
4572     }
4573
4574   /* if both are of size == 1 */
4575 #if 0 // one of them can be a sloc shared with the result
4576     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4577 #else
4578   if (getSize(operandType(left)) == 1 &&
4579       getSize(operandType(right)) == 1)
4580 #endif
4581     {
4582       genMultOneByte (left, right, result);
4583       goto release;
4584     }
4585
4586   /* should have been converted to function call */
4587     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4588              getSize(OP_SYMBOL(right)->type));
4589   assert (0);
4590
4591 release:
4592   freeAsmop (result, NULL, ic, TRUE);
4593   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4594   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4595 }
4596
4597 /*-----------------------------------------------------------------*/
4598 /* genDivbits :- division of bits                                  */
4599 /*-----------------------------------------------------------------*/
4600 static void
4601 genDivbits (operand * left,
4602             operand * right,
4603             operand * result)
4604 {
4605   char *l;
4606   bool pushedB;
4607
4608   D(emitcode (";     genDivbits",""));
4609
4610   pushedB = pushB ();
4611
4612   /* the result must be bit */
4613   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4614   l = aopGet (left, 0, FALSE, FALSE);
4615
4616   MOVA (l);
4617
4618   emitcode ("div", "ab");
4619   emitcode ("rrc", "a");
4620
4621   popB (pushedB);
4622
4623   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4624 }
4625
4626 /*-----------------------------------------------------------------*/
4627 /* genDivOneByte : 8 bit division                                  */
4628 /*-----------------------------------------------------------------*/
4629 static void
4630 genDivOneByte (operand * left,
4631                operand * right,
4632                operand * result)
4633 {
4634   bool lUnsigned, rUnsigned, pushedB;
4635   bool runtimeSign, compiletimeSign;
4636   symbol *lbl;
4637   int size, offset;
4638
4639   D(emitcode (";     genDivOneByte",""));
4640
4641   /* Why is it necessary that genDivOneByte() can return an int result?
4642      Have a look at:
4643
4644         volatile unsigned char uc;
4645         volatile signed char sc1, sc2;
4646         volatile int i;
4647
4648         uc  = 255;
4649         sc1 = -1;
4650         i = uc / sc1;
4651
4652      Or:
4653
4654         sc1 = -128;
4655         sc2 = -1;
4656         i = sc1 / sc2;
4657
4658      In all cases a one byte result would overflow, the following cast to int
4659      would return the wrong result.
4660
4661      Two possible solution:
4662         a) cast operands to int, if ((unsigned) / (signed)) or
4663            ((signed) / (signed))
4664         b) return an 16 bit signed int; this is what we're doing here!
4665   */
4666
4667   size = AOP_SIZE (result) - 1;
4668   offset = 1;
4669   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4670   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4671
4672   pushedB = pushB ();
4673
4674   /* signed or unsigned */
4675   if (lUnsigned && rUnsigned)
4676     {
4677       /* unsigned is easy */
4678       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4679       MOVA (aopGet (left, 0, FALSE, FALSE));
4680       emitcode ("div", "ab");
4681       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4682       while (size--)
4683         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4684
4685       popB (pushedB);
4686       return;
4687     }
4688
4689   /* signed is a little bit more difficult */
4690
4691   /* now sign adjust for both left & right */
4692
4693   /* let's see what's needed: */
4694   /* apply negative sign during runtime */
4695   runtimeSign = FALSE;
4696   /* negative sign from literals */
4697   compiletimeSign = FALSE;
4698
4699   if (!lUnsigned)
4700     {
4701       if (AOP_TYPE(left) == AOP_LIT)
4702         {
4703           /* signed literal */
4704           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4705           if (val < 0)
4706             compiletimeSign = TRUE;
4707         }
4708       else
4709         /* signed but not literal */
4710         runtimeSign = TRUE;
4711     }
4712
4713   if (!rUnsigned)
4714     {
4715       if (AOP_TYPE(right) == AOP_LIT)
4716         {
4717           /* signed literal */
4718           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4719           if (val < 0)
4720             compiletimeSign ^= TRUE;
4721         }
4722       else
4723         /* signed but not literal */
4724         runtimeSign = TRUE;
4725     }
4726
4727   /* initialize F0, which stores the runtime sign */
4728   if (runtimeSign)
4729     {
4730       if (compiletimeSign)
4731         emitcode ("setb", "F0"); /* set sign flag */
4732       else
4733         emitcode ("clr", "F0"); /* reset sign flag */
4734     }
4735
4736   /* save the signs of the operands */
4737   if (AOP_TYPE(right) == AOP_LIT)
4738     {
4739       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4740
4741       if (!rUnsigned && val < 0)
4742         emitcode ("mov", "b,#0x%02x", -val);
4743       else
4744         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4745     }
4746   else /* ! literal */
4747     {
4748       if (rUnsigned)
4749         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4750       else
4751         {
4752           MOVA (aopGet (right, 0, FALSE, FALSE));
4753           lbl = newiTempLabel (NULL);
4754           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4755           emitcode ("cpl", "F0"); /* complement sign flag */
4756           emitcode ("cpl", "a");  /* 2's complement */
4757           emitcode ("inc", "a");
4758           emitcode ("", "%05d$:", (lbl->key + 100));
4759           emitcode ("mov", "b,a");
4760         }
4761     }
4762
4763   if (AOP_TYPE(left) == AOP_LIT)
4764     {
4765       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4766
4767       if (!lUnsigned && val < 0)
4768         emitcode ("mov", "a,#0x%02x", -val);
4769       else
4770         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4771     }
4772   else /* ! literal */
4773     {
4774       MOVA (aopGet (left, 0, FALSE, FALSE));
4775
4776       if (!lUnsigned)
4777         {
4778           lbl = newiTempLabel (NULL);
4779           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4780           emitcode ("cpl", "F0"); /* complement sign flag */
4781           emitcode ("cpl", "a");  /* 2's complement */
4782           emitcode ("inc", "a");
4783           emitcode ("", "%05d$:", (lbl->key + 100));
4784         }
4785     }
4786
4787   /* now the division */
4788   emitcode ("div", "ab");
4789
4790   if (runtimeSign || compiletimeSign)
4791     {
4792       lbl = newiTempLabel (NULL);
4793       if (runtimeSign)
4794         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4795       emitcode ("cpl", "a"); /* lsb 2's complement */
4796       emitcode ("inc", "a");
4797       emitcode ("", "%05d$:", (lbl->key + 100));
4798
4799       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4800       if (size > 0)
4801         {
4802           /* msb is 0x00 or 0xff depending on the sign */
4803           if (runtimeSign)
4804             {
4805               emitcode ("mov", "c,F0");
4806               emitcode ("subb", "a,acc");
4807               while (size--)
4808                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4809             }
4810           else /* compiletimeSign */
4811             while (size--)
4812               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4813         }
4814     }
4815   else
4816     {
4817       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4818       while (size--)
4819         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4820     }
4821
4822   popB (pushedB);
4823 }
4824
4825 /*-----------------------------------------------------------------*/
4826 /* genDiv - generates code for division                            */
4827 /*-----------------------------------------------------------------*/
4828 static void
4829 genDiv (iCode * ic)
4830 {
4831   operand *left = IC_LEFT (ic);
4832   operand *right = IC_RIGHT (ic);
4833   operand *result = IC_RESULT (ic);
4834
4835   D(emitcode (";     genDiv",""));
4836
4837   /* assign the amsops */
4838   aopOp (left, ic, FALSE);
4839   aopOp (right, ic, FALSE);
4840   aopOp (result, ic, TRUE);
4841
4842   /* special cases first */
4843   /* both are bits */
4844   if (AOP_TYPE (left) == AOP_CRY &&
4845       AOP_TYPE (right) == AOP_CRY)
4846     {
4847       genDivbits (left, right, result);
4848       goto release;
4849     }
4850
4851   /* if both are of size == 1 */
4852   if (AOP_SIZE (left) == 1 &&
4853       AOP_SIZE (right) == 1)
4854     {
4855       genDivOneByte (left, right, result);
4856       goto release;
4857     }
4858
4859   /* should have been converted to function call */
4860   assert (0);
4861 release:
4862   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4863   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4864   freeAsmop (result, NULL, ic, TRUE);
4865 }
4866
4867 /*-----------------------------------------------------------------*/
4868 /* genModbits :- modulus of bits                                   */
4869 /*-----------------------------------------------------------------*/
4870 static void
4871 genModbits (operand * left,
4872             operand * right,
4873             operand * result)
4874 {
4875   char *l;
4876   bool pushedB;
4877
4878   D(emitcode (";     genModbits",""));
4879
4880   pushedB = pushB ();
4881
4882   /* the result must be bit */
4883   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4884   l = aopGet (left, 0, FALSE, FALSE);
4885
4886   MOVA (l);
4887
4888   emitcode ("div", "ab");
4889   emitcode ("mov", "a,b");
4890   emitcode ("rrc", "a");
4891
4892   popB (pushedB);
4893
4894   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4895 }
4896
4897 /*-----------------------------------------------------------------*/
4898 /* genModOneByte : 8 bit modulus                                   */
4899 /*-----------------------------------------------------------------*/
4900 static void
4901 genModOneByte (operand * left,
4902                operand * right,
4903                operand * result)
4904 {
4905   bool lUnsigned, rUnsigned, pushedB;
4906   bool runtimeSign, compiletimeSign;
4907   symbol *lbl;
4908   int size, offset;
4909
4910   D(emitcode (";     genModOneByte",""));
4911
4912   size = AOP_SIZE (result) - 1;
4913   offset = 1;
4914   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4915   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4916
4917   /* if right is a literal, check it for 2^n */
4918   if (AOP_TYPE(right) == AOP_LIT)
4919     {
4920       unsigned char val = abs((int) operandLitValue(right));
4921       symbol *lbl2 = NULL;
4922
4923       switch (val)
4924         {
4925           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4926           case 2:
4927           case 4:
4928           case 8:
4929           case 16:
4930           case 32:
4931           case 64:
4932           case 128:
4933             if (lUnsigned)
4934               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4935                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4936               /* because iCode should have been changed to genAnd  */
4937               /* see file "SDCCopt.c", function "convertToFcall()" */
4938
4939             MOVA (aopGet (left, 0, FALSE, FALSE));
4940             emitcode ("mov", "c,acc.7");
4941             emitcode ("anl", "a,#0x%02x", val - 1);
4942             lbl = newiTempLabel (NULL);
4943             emitcode ("jz", "%05d$", (lbl->key + 100));
4944             emitcode ("jnc", "%05d$", (lbl->key + 100));
4945             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4946             if (size)
4947               {
4948                 int size2 = size;
4949                 int offs2 = offset;
4950
4951                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4952                 while (size2--)
4953                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
4954                 lbl2 = newiTempLabel (NULL);
4955                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4956               }
4957             emitcode ("", "%05d$:", (lbl->key + 100));
4958             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4959             while (size--)
4960               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4961             if (lbl2)
4962               {
4963                 emitcode ("", "%05d$:", (lbl2->key + 100));
4964               }
4965             return;
4966
4967           default:
4968             break;
4969         }
4970     }
4971
4972   pushedB = pushB ();
4973
4974   /* signed or unsigned */
4975   if (lUnsigned && rUnsigned)
4976     {
4977       /* unsigned is easy */
4978       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4979       MOVA (aopGet (left, 0, FALSE, FALSE));
4980       emitcode ("div", "ab");
4981       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4982       while (size--)
4983         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4984
4985       popB (pushedB);
4986       return;
4987     }
4988
4989   /* signed is a little bit more difficult */
4990
4991   /* now sign adjust for both left & right */
4992
4993   /* modulus: sign of the right operand has no influence on the result! */
4994   if (AOP_TYPE(right) == AOP_LIT)
4995     {
4996       signed char val = (char) operandLitValue(right);
4997
4998       if (!rUnsigned && val < 0)
4999         emitcode ("mov", "b,#0x%02x", -val);
5000       else
5001         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5002     }
5003   else /* not literal */
5004     {
5005       if (rUnsigned)
5006         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5007       else
5008         {
5009           MOVA (aopGet (right, 0, FALSE, FALSE));
5010           lbl = newiTempLabel (NULL);
5011           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5012           emitcode ("cpl", "a"); /* 2's complement */
5013           emitcode ("inc", "a");
5014           emitcode ("", "%05d$:", (lbl->key + 100));
5015           emitcode ("mov", "b,a");
5016         }
5017     }
5018
5019   /* let's see what's needed: */
5020   /* apply negative sign during runtime */
5021   runtimeSign = FALSE;
5022   /* negative sign from literals */
5023   compiletimeSign = FALSE;
5024
5025   /* sign adjust left side */
5026   if (AOP_TYPE(left) == AOP_LIT)
5027     {
5028       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5029
5030       if (!lUnsigned && val < 0)
5031         {
5032           compiletimeSign = TRUE; /* set sign flag */
5033           emitcode ("mov", "a,#0x%02x", -val);
5034         }
5035       else
5036         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5037     }
5038   else /* ! literal */
5039     {
5040       MOVA (aopGet (left, 0, FALSE, FALSE));
5041
5042       if (!lUnsigned)
5043         {
5044           runtimeSign = TRUE;
5045           emitcode ("clr", "F0"); /* clear sign flag */
5046
5047           lbl = newiTempLabel (NULL);
5048           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5049           emitcode ("setb", "F0"); /* set sign flag */
5050           emitcode ("cpl", "a");   /* 2's complement */
5051           emitcode ("inc", "a");
5052           emitcode ("", "%05d$:", (lbl->key + 100));
5053         }
5054     }
5055
5056   /* now the modulus */
5057   emitcode ("div", "ab");
5058
5059   if (runtimeSign || compiletimeSign)
5060     {
5061       emitcode ("mov", "a,b");
5062       lbl = newiTempLabel (NULL);
5063       if (runtimeSign)
5064         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5065       emitcode ("cpl", "a"); /* 2's complement */
5066       emitcode ("inc", "a");
5067       emitcode ("", "%05d$:", (lbl->key + 100));
5068
5069       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5070       if (size > 0)
5071         {
5072           /* msb is 0x00 or 0xff depending on the sign */
5073           if (runtimeSign)
5074             {
5075               emitcode ("mov", "c,F0");
5076               emitcode ("subb", "a,acc");
5077               while (size--)
5078                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5079             }
5080           else /* compiletimeSign */
5081             while (size--)
5082               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5083         }
5084     }
5085   else
5086     {
5087       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5088       while (size--)
5089         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5090     }
5091
5092   popB (pushedB);
5093 }
5094
5095 /*-----------------------------------------------------------------*/
5096 /* genMod - generates code for division                            */
5097 /*-----------------------------------------------------------------*/
5098 static void
5099 genMod (iCode * ic)
5100 {
5101   operand *left = IC_LEFT (ic);
5102   operand *right = IC_RIGHT (ic);
5103   operand *result = IC_RESULT (ic);
5104
5105   D(emitcode (";     genMod",""));
5106
5107   /* assign the asmops */
5108   aopOp (left, ic, FALSE);
5109   aopOp (right, ic, FALSE);
5110   aopOp (result, ic, TRUE);
5111
5112   /* special cases first */
5113   /* both are bits */
5114   if (AOP_TYPE (left) == AOP_CRY &&
5115       AOP_TYPE (right) == AOP_CRY)
5116     {
5117       genModbits (left, right, result);
5118       goto release;
5119     }
5120
5121   /* if both are of size == 1 */
5122   if (AOP_SIZE (left) == 1 &&
5123       AOP_SIZE (right) == 1)
5124     {
5125       genModOneByte (left, right, result);
5126       goto release;
5127     }
5128
5129   /* should have been converted to function call */
5130   assert (0);
5131
5132 release:
5133   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5134   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5135   freeAsmop (result, NULL, ic, TRUE);
5136 }
5137
5138 /*-----------------------------------------------------------------*/
5139 /* genIfxJump :- will create a jump depending on the ifx           */
5140 /*-----------------------------------------------------------------*/
5141 static void
5142 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5143 {
5144   symbol *jlbl;
5145   symbol *tlbl = newiTempLabel (NULL);
5146   char *inst;
5147
5148   D(emitcode (";     genIfxJump",""));
5149
5150   /* if true label then we jump if condition
5151      supplied is true */
5152   if (IC_TRUE (ic))
5153     {
5154       jlbl = IC_TRUE (ic);
5155       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5156                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5157     }
5158   else
5159     {
5160       /* false label is present */
5161       jlbl = IC_FALSE (ic);
5162       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5163                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5164     }
5165   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5166     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5167   else
5168     emitcode (inst, "%05d$", tlbl->key + 100);
5169   freeForBranchAsmop (result);
5170   freeForBranchAsmop (right);
5171   freeForBranchAsmop (left);
5172   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5173   emitcode ("", "%05d$:", tlbl->key + 100);
5174
5175   /* mark the icode as generated */
5176   ic->generated = 1;
5177 }
5178
5179 /*-----------------------------------------------------------------*/
5180 /* genCmp :- greater or less than comparison                       */
5181 /*-----------------------------------------------------------------*/
5182 static void
5183 genCmp (operand * left, operand * right,
5184         operand * result, iCode * ifx, int sign, iCode *ic)
5185 {
5186   int size, offset = 0;
5187   unsigned long lit = 0L;
5188   bool rightInB;
5189
5190   D(emitcode (";     genCmp",""));
5191
5192   /* if left & right are bit variables */
5193   if (AOP_TYPE (left) == AOP_CRY &&
5194       AOP_TYPE (right) == AOP_CRY)
5195     {
5196       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5197       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5198     }
5199   else
5200     {
5201       /* subtract right from left if at the
5202          end the carry flag is set then we know that
5203          left is greater than right */
5204       size = max (AOP_SIZE (left), AOP_SIZE (right));
5205
5206       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5207       if ((size == 1) && !sign &&
5208           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5209         {
5210           symbol *lbl = newiTempLabel (NULL);
5211           emitcode ("cjne", "%s,%s,%05d$",
5212                     aopGet (left, offset, FALSE, FALSE),
5213                     aopGet (right, offset, FALSE, FALSE),
5214                     lbl->key + 100);
5215           emitcode ("", "%05d$:", lbl->key + 100);
5216         }
5217       else
5218         {
5219           if (AOP_TYPE (right) == AOP_LIT)
5220             {
5221               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5222               /* optimize if(x < 0) or if(x >= 0) */
5223               if (lit == 0L)
5224                 {
5225                   if (!sign)
5226                     {
5227                       CLRC;
5228                     }
5229                   else
5230                     {
5231                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5232                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5233                         {
5234                           genIfxJump (ifx, "acc.7", left, right, result);
5235                           freeAsmop (right, NULL, ic, TRUE);
5236                           freeAsmop (left, NULL, ic, TRUE);
5237
5238                           return;
5239                         }
5240                       else
5241                         emitcode ("rlc", "a");
5242                     }
5243                   goto release;
5244                 }
5245             }
5246           CLRC;
5247           while (size--)
5248             {
5249               bool pushedB = FALSE;
5250               rightInB = aopGetUsesAcc(right, offset);
5251               if (rightInB)
5252                 {
5253                   pushedB = pushB ();
5254                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5255                 }
5256               MOVA (aopGet (left, offset, FALSE, FALSE));
5257               if (sign && size == 0)
5258                 {
5259                   emitcode ("xrl", "a,#0x80");
5260                   if (AOP_TYPE (right) == AOP_LIT)
5261                     {
5262                       unsigned long lit = (unsigned long)
5263                       floatFromVal (AOP (right)->aopu.aop_lit);
5264                       emitcode ("subb", "a,#0x%02x",
5265                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5266                     }
5267                   else
5268                     {
5269                       if (!rightInB)
5270                         {
5271                           pushedB = pushB ();
5272                           rightInB++;
5273                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5274                         }
5275                       emitcode ("xrl", "b,#0x80");
5276                       emitcode ("subb", "a,b");
5277                     }
5278                 }
5279               else
5280                 {
5281                   if (rightInB)
5282                     emitcode ("subb", "a,b");
5283                   else
5284                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5285                 }
5286               if (rightInB)
5287                 popB (pushedB);
5288               offset++;
5289             }
5290         }
5291     }
5292
5293 release:
5294   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5295   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5296   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5297     {
5298       outBitC (result);
5299     }
5300   else
5301     {
5302       /* if the result is used in the next
5303          ifx conditional branch then generate
5304          code a little differently */
5305       if (ifx)
5306         genIfxJump (ifx, "c", NULL, NULL, result);
5307       else
5308         outBitC (result);
5309       /* leave the result in acc */
5310     }
5311 }
5312
5313 /*-----------------------------------------------------------------*/
5314 /* genCmpGt :- greater than comparison                             */
5315 /*-----------------------------------------------------------------*/
5316 static void
5317 genCmpGt (iCode * ic, iCode * ifx)
5318 {
5319   operand *left, *right, *result;
5320   sym_link *letype, *retype;
5321   int sign;
5322
5323   D(emitcode (";     genCmpGt",""));
5324
5325   left = IC_LEFT (ic);
5326   right = IC_RIGHT (ic);
5327   result = IC_RESULT (ic);
5328
5329   letype = getSpec (operandType (left));
5330   retype = getSpec (operandType (right));
5331   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5332            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5333   /* assign the amsops */
5334   aopOp (left, ic, FALSE);
5335   aopOp (right, ic, FALSE);
5336   aopOp (result, ic, TRUE);
5337
5338   genCmp (right, left, result, ifx, sign, ic);
5339
5340   freeAsmop (result, NULL, ic, TRUE);
5341 }
5342
5343 /*-----------------------------------------------------------------*/
5344 /* genCmpLt - less than comparisons                                */
5345 /*-----------------------------------------------------------------*/
5346 static void
5347 genCmpLt (iCode * ic, iCode * ifx)
5348 {
5349   operand *left, *right, *result;
5350   sym_link *letype, *retype;
5351   int sign;
5352
5353   D(emitcode (";     genCmpLt",""));
5354
5355   left = IC_LEFT (ic);
5356   right = IC_RIGHT (ic);
5357   result = IC_RESULT (ic);
5358
5359   letype = getSpec (operandType (left));
5360   retype = getSpec (operandType (right));
5361   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5362            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5363   /* assign the amsops */
5364   aopOp (left, ic, FALSE);
5365   aopOp (right, ic, FALSE);
5366   aopOp (result, ic, TRUE);
5367
5368   genCmp (left, right, result, ifx, sign,ic);
5369
5370   freeAsmop (result, NULL, ic, TRUE);
5371 }
5372
5373 /*-----------------------------------------------------------------*/
5374 /* gencjneshort - compare and jump if not equal                    */
5375 /*-----------------------------------------------------------------*/
5376 static void
5377 gencjneshort (operand * left, operand * right, symbol * lbl)
5378 {
5379   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5380   int offset = 0;
5381   unsigned long lit = 0L;
5382
5383   /* if the left side is a literal or
5384      if the right is in a pointer register and left
5385      is not */
5386   if ((AOP_TYPE (left) == AOP_LIT) ||
5387       (AOP_TYPE (left) == AOP_IMMD) ||
5388       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5389     {
5390       operand *t = right;
5391       right = left;
5392       left = t;
5393     }
5394
5395   if (AOP_TYPE (right) == AOP_LIT)
5396     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5397
5398   /* if the right side is a literal then anything goes */
5399   if (AOP_TYPE (right) == AOP_LIT &&
5400       AOP_TYPE (left) != AOP_DIR  &&
5401       AOP_TYPE (left) != AOP_IMMD)
5402     {
5403       while (size--)
5404         {
5405           emitcode ("cjne", "%s,%s,%05d$",
5406                     aopGet (left, offset, FALSE, FALSE),
5407                     aopGet (right, offset, FALSE, FALSE),
5408                     lbl->key + 100);
5409           offset++;
5410         }
5411     }
5412
5413   /* if the right side is in a register or in direct space or
5414      if the left is a pointer register & right is not */
5415   else if (AOP_TYPE (right) == AOP_REG ||
5416            AOP_TYPE (right) == AOP_DIR ||
5417            AOP_TYPE (right) == AOP_LIT ||
5418            AOP_TYPE (right) == AOP_IMMD ||
5419            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5420            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5421     {
5422       while (size--)
5423         {
5424           MOVA (aopGet (left, offset, FALSE, FALSE));
5425           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5426               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5427             emitcode ("jnz", "%05d$", lbl->key + 100);
5428           else
5429             emitcode ("cjne", "a,%s,%05d$",
5430                       aopGet (right, offset, FALSE, TRUE),
5431                       lbl->key + 100);
5432           offset++;
5433         }
5434     }
5435   else
5436     {
5437       /* right is a pointer reg need both a & b */
5438       while (size--)
5439         {
5440           char *l;
5441           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5442           wassertl(!BINUSE, "B was in use");
5443           l = aopGet (left, offset, FALSE, FALSE);
5444           if (strcmp (l, "b"))
5445             emitcode ("mov", "b,%s", l);
5446           MOVA (aopGet (right, offset, FALSE, FALSE));
5447           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5448           offset++;
5449         }
5450     }
5451 }
5452
5453 /*-----------------------------------------------------------------*/
5454 /* gencjne - compare and jump if not equal                         */
5455 /*-----------------------------------------------------------------*/
5456 static void
5457 gencjne (operand * left, operand * right, symbol * lbl)
5458 {
5459   symbol *tlbl = newiTempLabel (NULL);
5460
5461   gencjneshort (left, right, lbl);
5462
5463   emitcode ("mov", "a,%s", one);
5464   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5465   emitcode ("", "%05d$:", lbl->key + 100);
5466   emitcode ("clr", "a");
5467   emitcode ("", "%05d$:", tlbl->key + 100);
5468 }
5469
5470 /*-----------------------------------------------------------------*/
5471 /* genCmpEq - generates code for equal to                          */
5472 /*-----------------------------------------------------------------*/
5473 static void
5474 genCmpEq (iCode * ic, iCode * ifx)
5475 {
5476   operand *left, *right, *result;
5477
5478   D(emitcode (";     genCmpEq",""));
5479
5480   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5481   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5482   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5483
5484   /* if literal, literal on the right or
5485      if the right is in a pointer register and left
5486      is not */
5487   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5488       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5489     {
5490       operand *t = IC_RIGHT (ic);
5491       IC_RIGHT (ic) = IC_LEFT (ic);
5492       IC_LEFT (ic) = t;
5493     }
5494
5495   if (ifx && !AOP_SIZE (result))
5496     {
5497       symbol *tlbl;
5498       /* if they are both bit variables */
5499       if (AOP_TYPE (left) == AOP_CRY &&
5500           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5501         {
5502           if (AOP_TYPE (right) == AOP_LIT)
5503             {
5504               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5505               if (lit == 0L)
5506                 {
5507                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5508                   emitcode ("cpl", "c");
5509                 }
5510               else if (lit == 1L)
5511                 {
5512                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5513                 }
5514               else
5515                 {
5516                   emitcode ("clr", "c");
5517                 }
5518               /* AOP_TYPE(right) == AOP_CRY */
5519             }
5520           else
5521             {
5522               symbol *lbl = newiTempLabel (NULL);
5523               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5524               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5525               emitcode ("cpl", "c");
5526               emitcode ("", "%05d$:", (lbl->key + 100));
5527             }
5528           /* if true label then we jump if condition
5529              supplied is true */
5530           tlbl = newiTempLabel (NULL);
5531           if (IC_TRUE (ifx))
5532             {
5533               emitcode ("jnc", "%05d$", tlbl->key + 100);
5534               freeForBranchAsmop (result);
5535               freeForBranchAsmop (right);
5536               freeForBranchAsmop (left);
5537               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5538             }
5539           else
5540             {
5541               emitcode ("jc", "%05d$", tlbl->key + 100);
5542               freeForBranchAsmop (result);
5543               freeForBranchAsmop (right);
5544               freeForBranchAsmop (left);
5545               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5546             }
5547           emitcode ("", "%05d$:", tlbl->key + 100);
5548         }
5549       else
5550         {
5551           tlbl = newiTempLabel (NULL);
5552           gencjneshort (left, right, tlbl);
5553           if (IC_TRUE (ifx))
5554             {
5555               freeForBranchAsmop (result);
5556               freeForBranchAsmop (right);
5557               freeForBranchAsmop (left);
5558               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5559               emitcode ("", "%05d$:", tlbl->key + 100);
5560             }
5561           else
5562             {
5563               symbol *lbl = newiTempLabel (NULL);
5564               emitcode ("sjmp", "%05d$", lbl->key + 100);
5565               emitcode ("", "%05d$:", tlbl->key + 100);
5566               freeForBranchAsmop (result);
5567               freeForBranchAsmop (right);
5568               freeForBranchAsmop (left);
5569               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5570               emitcode ("", "%05d$:", lbl->key + 100);
5571             }
5572         }
5573       /* mark the icode as generated */
5574       ifx->generated = 1;
5575       goto release;
5576     }
5577
5578   /* if they are both bit variables */
5579   if (AOP_TYPE (left) == AOP_CRY &&
5580       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5581     {
5582       if (AOP_TYPE (right) == AOP_LIT)
5583         {
5584           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5585           if (lit == 0L)
5586             {
5587               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5588               emitcode ("cpl", "c");
5589             }
5590           else if (lit == 1L)
5591             {
5592               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5593             }
5594           else
5595             {
5596               emitcode ("clr", "c");
5597             }
5598           /* AOP_TYPE(right) == AOP_CRY */
5599         }
5600       else
5601         {
5602           symbol *lbl = newiTempLabel (NULL);
5603           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5604           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5605           emitcode ("cpl", "c");
5606           emitcode ("", "%05d$:", (lbl->key + 100));
5607         }
5608       /* c = 1 if egal */
5609       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5610         {
5611           outBitC (result);
5612           goto release;
5613         }
5614       if (ifx)
5615         {
5616           genIfxJump (ifx, "c", left, right, result);
5617           goto release;
5618         }
5619       /* if the result is used in an arithmetic operation
5620          then put the result in place */
5621       outBitC (result);
5622     }
5623   else
5624     {
5625       gencjne (left, right, newiTempLabel (NULL));
5626       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5627         {
5628           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5629           goto release;
5630         }
5631       if (ifx)
5632         {
5633           genIfxJump (ifx, "a", left, right, result);
5634           goto release;
5635         }
5636       /* if the result is used in an arithmetic operation
5637          then put the result in place */
5638       if (AOP_TYPE (result) != AOP_CRY)
5639         outAcc (result);
5640       /* leave the result in acc */
5641     }
5642
5643 release:
5644   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5645   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5646   freeAsmop (result, NULL, ic, TRUE);
5647 }
5648
5649 /*-----------------------------------------------------------------*/
5650 /* ifxForOp - returns the icode containing the ifx for operand     */
5651 /*-----------------------------------------------------------------*/
5652 static iCode *
5653 ifxForOp (operand * op, iCode * ic)
5654 {
5655   /* if true symbol then needs to be assigned */
5656   if (IS_TRUE_SYMOP (op))
5657     return NULL;
5658
5659   /* if this has register type condition and
5660      the next instruction is ifx with the same operand
5661      and live to of the operand is upto the ifx only then */
5662   if (ic->next &&
5663       ic->next->op == IFX &&
5664       IC_COND (ic->next)->key == op->key &&
5665       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5666     return ic->next;
5667
5668   return NULL;
5669 }
5670
5671 /*-----------------------------------------------------------------*/
5672 /* hasInc - operand is incremented before any other use            */
5673 /*-----------------------------------------------------------------*/
5674 static iCode *
5675 hasInc (operand *op, iCode *ic,int osize)
5676 {
5677   sym_link *type = operandType(op);
5678   sym_link *retype = getSpec (type);
5679   iCode *lic = ic->next;
5680   int isize ;
5681
5682   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5683   if (!IS_SYMOP(op)) return NULL;
5684
5685   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5686   if (IS_AGGREGATE(type->next)) return NULL;
5687   if (osize != (isize = getSize(type->next))) return NULL;
5688
5689   while (lic) {
5690     /* if operand of the form op = op + <sizeof *op> */
5691     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5692         isOperandEqual(IC_RESULT(lic),op) &&
5693         isOperandLiteral(IC_RIGHT(lic)) &&
5694         operandLitValue(IC_RIGHT(lic)) == isize) {
5695       return lic;
5696     }
5697     /* if the operand used or deffed */
5698     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5699       return NULL;
5700     }
5701     /* if GOTO or IFX */
5702     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5703     lic = lic->next;
5704   }
5705   return NULL;
5706 }
5707
5708 /*-----------------------------------------------------------------*/
5709 /* genAndOp - for && operation                                     */
5710 /*-----------------------------------------------------------------*/
5711 static void
5712 genAndOp (iCode * ic)
5713 {
5714   operand *left, *right, *result;
5715   symbol *tlbl;
5716
5717   D(emitcode (";     genAndOp",""));
5718
5719   /* note here that && operations that are in an
5720      if statement are taken away by backPatchLabels
5721      only those used in arthmetic operations remain */
5722   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5723   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5724   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5725
5726   /* if both are bit variables */
5727   if (AOP_TYPE (left) == AOP_CRY &&
5728       AOP_TYPE (right) == AOP_CRY)
5729     {
5730       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5731       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5732       outBitC (result);
5733     }
5734   else
5735     {
5736       tlbl = newiTempLabel (NULL);
5737       toBoolean (left);
5738       emitcode ("jz", "%05d$", tlbl->key + 100);
5739       toBoolean (right);
5740       emitcode ("", "%05d$:", tlbl->key + 100);
5741       outBitAcc (result);
5742     }
5743
5744   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5745   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5746   freeAsmop (result, NULL, ic, TRUE);
5747 }
5748
5749
5750 /*-----------------------------------------------------------------*/
5751 /* genOrOp - for || operation                                      */
5752 /*-----------------------------------------------------------------*/
5753 static void
5754 genOrOp (iCode * ic)
5755 {
5756   operand *left, *right, *result;
5757   symbol *tlbl;
5758
5759   D(emitcode (";     genOrOp",""));
5760
5761   /* note here that || operations that are in an
5762      if statement are taken away by backPatchLabels
5763      only those used in arthmetic operations remain */
5764   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5765   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5766   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5767
5768   /* if both are bit variables */
5769   if (AOP_TYPE (left) == AOP_CRY &&
5770       AOP_TYPE (right) == AOP_CRY)
5771     {
5772       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5773       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5774       outBitC (result);
5775     }
5776   else
5777     {
5778       tlbl = newiTempLabel (NULL);
5779       toBoolean (left);
5780       emitcode ("jnz", "%05d$", tlbl->key + 100);
5781       toBoolean (right);
5782       emitcode ("", "%05d$:", tlbl->key + 100);
5783       outBitAcc (result);
5784     }
5785
5786   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5787   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5788   freeAsmop (result, NULL, ic, TRUE);
5789 }
5790
5791 /*-----------------------------------------------------------------*/
5792 /* isLiteralBit - test if lit == 2^n                               */
5793 /*-----------------------------------------------------------------*/
5794 static int
5795 isLiteralBit (unsigned long lit)
5796 {
5797   unsigned long pw[32] =
5798   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5799    0x100L, 0x200L, 0x400L, 0x800L,
5800    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5801    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5802    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5803    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5804    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5805   int idx;
5806
5807   for (idx = 0; idx < 32; idx++)
5808     if (lit == pw[idx])
5809       return idx + 1;
5810   return 0;
5811 }
5812
5813 /*-----------------------------------------------------------------*/
5814 /* continueIfTrue -                                                */
5815 /*-----------------------------------------------------------------*/
5816 static void
5817 continueIfTrue (iCode * ic)
5818 {
5819   if (IC_TRUE (ic))
5820     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5821   ic->generated = 1;
5822 }
5823
5824 /*-----------------------------------------------------------------*/
5825 /* jmpIfTrue -                                                     */
5826 /*-----------------------------------------------------------------*/
5827 static void
5828 jumpIfTrue (iCode * ic)
5829 {
5830   if (!IC_TRUE (ic))
5831     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5832   ic->generated = 1;
5833 }
5834
5835 /*-----------------------------------------------------------------*/
5836 /* jmpTrueOrFalse -                                                */
5837 /*-----------------------------------------------------------------*/
5838 static void
5839 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5840 {
5841   // ugly but optimized by peephole
5842   if (IC_TRUE (ic))
5843     {
5844       symbol *nlbl = newiTempLabel (NULL);
5845       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5846       emitcode ("", "%05d$:", tlbl->key + 100);
5847       freeForBranchAsmop (result);
5848       freeForBranchAsmop (right);
5849       freeForBranchAsmop (left);
5850       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5851       emitcode ("", "%05d$:", nlbl->key + 100);
5852     }
5853   else
5854     {
5855       freeForBranchAsmop (result);
5856       freeForBranchAsmop (right);
5857       freeForBranchAsmop (left);
5858       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5859       emitcode ("", "%05d$:", tlbl->key + 100);
5860     }
5861   ic->generated = 1;
5862 }
5863
5864 /*-----------------------------------------------------------------*/
5865 /* genAnd  - code for and                                          */
5866 /*-----------------------------------------------------------------*/
5867 static void
5868 genAnd (iCode * ic, iCode * ifx)
5869 {
5870   operand *left, *right, *result;
5871   int size, offset = 0;
5872   unsigned long lit = 0L;
5873   int bytelit = 0;
5874   char buffer[10];
5875
5876   D(emitcode (";     genAnd",""));
5877
5878   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5879   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5880   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5881
5882 #ifdef DEBUG_TYPE
5883   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5884             AOP_TYPE (result),
5885             AOP_TYPE (left), AOP_TYPE (right));
5886   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5887             AOP_SIZE (result),
5888             AOP_SIZE (left), AOP_SIZE (right));
5889 #endif
5890
5891   /* if left is a literal & right is not then exchange them */
5892   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5893       AOP_NEEDSACC (left))
5894     {
5895       operand *tmp = right;
5896       right = left;
5897       left = tmp;
5898     }
5899
5900   /* if result = right then exchange left and right */
5901   if (sameRegs (AOP (result), AOP (right)))
5902     {
5903       operand *tmp = right;
5904       right = left;
5905       left = tmp;
5906     }
5907
5908   /* if right is bit then exchange them */
5909   if (AOP_TYPE (right) == AOP_CRY &&
5910       AOP_TYPE (left) != AOP_CRY)
5911     {
5912       operand *tmp = right;
5913       right = left;
5914       left = tmp;
5915     }
5916   if (AOP_TYPE (right) == AOP_LIT)
5917     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5918
5919   size = AOP_SIZE (result);
5920
5921   // if(bit & yy)
5922   // result = bit & yy;
5923   if (AOP_TYPE (left) == AOP_CRY)
5924     {
5925       // c = bit & literal;
5926       if (AOP_TYPE (right) == AOP_LIT)
5927         {
5928           if (lit & 1)
5929             {
5930               if (size && sameRegs (AOP (result), AOP (left)))
5931                 // no change
5932                 goto release;
5933               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5934             }
5935           else
5936             {
5937               // bit(result) = 0;
5938               if (size && (AOP_TYPE (result) == AOP_CRY))
5939                 {
5940                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5941                   goto release;
5942                 }
5943               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5944                 {
5945                   jumpIfTrue (ifx);
5946                   goto release;
5947                 }
5948               emitcode ("clr", "c");
5949             }
5950         }
5951       else
5952         {
5953           if (AOP_TYPE (right) == AOP_CRY)
5954             {
5955               // c = bit & bit;
5956               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5957               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5958             }
5959           else
5960             {
5961               // c = bit & val;
5962               MOVA (aopGet (right, 0, FALSE, FALSE));
5963               // c = lsb
5964               emitcode ("rrc", "a");
5965               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5966             }
5967         }
5968       // bit = c
5969       // val = c
5970       if (size)
5971         outBitC (result);
5972       // if(bit & ...)
5973       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5974         genIfxJump (ifx, "c", left, right, result);
5975       goto release;
5976     }
5977
5978   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5979   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5980   if ((AOP_TYPE (right) == AOP_LIT) &&
5981       (AOP_TYPE (result) == AOP_CRY) &&
5982       (AOP_TYPE (left) != AOP_CRY))
5983     {
5984       int posbit = isLiteralBit (lit);
5985       /* left &  2^n */
5986       if (posbit)
5987         {
5988           posbit--;
5989           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
5990           // bit = left & 2^n
5991           if (size)
5992             {
5993               switch (posbit & 0x07)
5994                 {
5995                   case 0: emitcode ("rrc", "a");
5996                           break;
5997                   case 7: emitcode ("rlc", "a");
5998                           break;
5999                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6000                           break;
6001                 }
6002             }
6003           // if(left &  2^n)
6004           else
6005             {
6006               if (ifx)
6007                 {
6008                   SNPRINTF (buffer, sizeof(buffer),
6009                             "acc.%d", posbit & 0x07);
6010                   genIfxJump (ifx, buffer, left, right, result);
6011                 }
6012               else
6013                 {// what is this case? just found it in ds390/gen.c
6014                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6015                 }
6016               goto release;
6017             }
6018         }
6019       else
6020         {
6021           symbol *tlbl = newiTempLabel (NULL);
6022           int sizel = AOP_SIZE (left);
6023           if (size)
6024             emitcode ("setb", "c");
6025           while (sizel--)
6026             {
6027               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6028                 {
6029                   MOVA (aopGet (left, offset, FALSE, FALSE));
6030                   // byte ==  2^n ?
6031                   if ((posbit = isLiteralBit (bytelit)) != 0)
6032                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6033                   else
6034                     {
6035                       if (bytelit != 0x0FFL)
6036                         emitcode ("anl", "a,%s",
6037                                   aopGet (right, offset, FALSE, TRUE));
6038                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6039                     }
6040                 }
6041               offset++;
6042             }
6043           // bit = left & literal
6044           if (size)
6045             {
6046               emitcode ("clr", "c");
6047               emitcode ("", "%05d$:", tlbl->key + 100);
6048             }
6049           // if(left & literal)
6050           else
6051             {
6052               if (ifx)
6053                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6054               else
6055                 emitcode ("", "%05d$:", tlbl->key + 100);
6056               goto release;
6057             }
6058         }
6059       outBitC (result);
6060       goto release;
6061     }
6062
6063   /* if left is same as result */
6064   if (sameRegs (AOP (result), AOP (left)))
6065     {
6066       for (; size--; offset++)
6067         {
6068           if (AOP_TYPE (right) == AOP_LIT)
6069             {
6070               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6071               if (bytelit == 0x0FF)
6072                 {
6073                   /* dummy read of volatile operand */
6074                   if (isOperandVolatile (left, FALSE))
6075                     MOVA (aopGet (left, offset, FALSE, FALSE));
6076                   else
6077                     continue;
6078                 }
6079               else if (bytelit == 0)
6080                 {
6081                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6082                 }
6083               else if (IS_AOP_PREG (result))
6084                 {
6085                   MOVA (aopGet (left, offset, FALSE, TRUE));
6086                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6087                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6088                 }
6089               else
6090                 emitcode ("anl", "%s,%s",
6091                           aopGet (left, offset, FALSE, TRUE),
6092                           aopGet (right, offset, FALSE, FALSE));
6093             }
6094           else
6095             {
6096               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
6097                 {
6098                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6099                 }
6100               else
6101                 {
6102                   MOVA (aopGet (right, offset, FALSE, FALSE));
6103                   if (IS_AOP_PREG (result))
6104                     {
6105                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6106                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6107                     }
6108                   else
6109                     emitcode ("anl", "%s,a",
6110                               aopGet (left, offset, FALSE, TRUE));
6111                 }
6112             }
6113         }
6114     }
6115   else
6116     {
6117       // left & result in different registers
6118       if (AOP_TYPE (result) == AOP_CRY)
6119         {
6120           // result = bit
6121           // if(size), result in bit
6122           // if(!size && ifx), conditional oper: if(left & right)
6123           symbol *tlbl = newiTempLabel (NULL);
6124           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6125           if (size)
6126             emitcode ("setb", "c");
6127           while (sizer--)
6128             {
6129               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6130                   && AOP_TYPE(left)==AOP_ACC)
6131                 {
6132                   if (offset)
6133                     emitcode("mov", "a,b");
6134                   emitcode ("anl", "a,%s",
6135                             aopGet (right, offset, FALSE, FALSE));
6136                 } else {
6137                   if (AOP_TYPE(left)==AOP_ACC)
6138                     {
6139                       if (!offset)
6140                         {
6141                           bool pushedB = pushB ();
6142                           emitcode("mov", "b,a");
6143                           MOVA (aopGet (right, offset, FALSE, FALSE));
6144                           emitcode("anl", "a,b");
6145                           popB (pushedB);
6146                         }
6147                       else
6148                         {
6149                           MOVA (aopGet (right, offset, FALSE, FALSE));
6150                           emitcode("anl", "a,b");
6151                         }
6152                 } else {
6153                       MOVA (aopGet (right, offset, FALSE, FALSE));
6154                   emitcode ("anl", "a,%s",
6155                                 aopGet (left, offset, FALSE, FALSE));
6156                 }
6157               }
6158               emitcode ("jnz", "%05d$", tlbl->key + 100);
6159               offset++;
6160             }
6161           if (size)
6162             {
6163               CLRC;
6164               emitcode ("", "%05d$:", tlbl->key + 100);
6165               outBitC (result);
6166             }
6167           else if (ifx)
6168             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6169           else
6170             emitcode ("", "%05d$:", tlbl->key + 100);
6171         }
6172       else
6173         {
6174           for (; (size--); offset++)
6175             {
6176               // normal case
6177               // result = left & right
6178               if (AOP_TYPE (right) == AOP_LIT)
6179                 {
6180                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6181                   if (bytelit == 0x0FF)
6182                     {
6183                       aopPut (result,
6184                               aopGet (left, offset, FALSE, FALSE),
6185                               offset,
6186                               isOperandVolatile (result, FALSE));
6187                       continue;
6188                     }
6189                   else if (bytelit == 0)
6190                     {
6191                       /* dummy read of volatile operand */
6192                       if (isOperandVolatile (left, FALSE))
6193                         MOVA (aopGet (left, offset, FALSE, FALSE));
6194                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6195                       continue;
6196                     }
6197                   else if (AOP_TYPE (left) == AOP_ACC)
6198                     {
6199                       if (!offset)
6200                         {
6201                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6202                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6203                           continue;
6204                         }
6205                       else
6206                         {
6207                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6208                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6209                           continue;
6210                         }
6211                     }
6212                 }
6213               // faster than result <- left, anl result,right
6214               // and better if result is SFR
6215               if (AOP_TYPE (left) == AOP_ACC)
6216                 {
6217                   if (offset)
6218                     emitcode("mov", "a,b");
6219                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6220                 }
6221               else
6222                 {
6223                   MOVA (aopGet (right, offset, FALSE, FALSE));
6224                   emitcode ("anl", "a,%s",
6225                             aopGet (left, offset, FALSE, FALSE));
6226                 }
6227               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6228             }
6229         }
6230     }
6231
6232 release:
6233   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6234   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6235   freeAsmop (result, NULL, ic, TRUE);
6236 }
6237
6238 /*-----------------------------------------------------------------*/
6239 /* genOr  - code for or                                            */
6240 /*-----------------------------------------------------------------*/
6241 static void
6242 genOr (iCode * ic, iCode * ifx)
6243 {
6244   operand *left, *right, *result;
6245   int size, offset = 0;
6246   unsigned long lit = 0L;
6247   int bytelit = 0;
6248
6249   D(emitcode (";     genOr",""));
6250
6251   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6252   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6253   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6254
6255 #ifdef DEBUG_TYPE
6256   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6257             AOP_TYPE (result),
6258             AOP_TYPE (left), AOP_TYPE (right));
6259   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6260             AOP_SIZE (result),
6261             AOP_SIZE (left), AOP_SIZE (right));
6262 #endif
6263
6264   /* if left is a literal & right is not then exchange them */
6265   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6266       AOP_NEEDSACC (left))
6267     {
6268       operand *tmp = right;
6269       right = left;
6270       left = tmp;
6271     }
6272
6273   /* if result = right then exchange them */
6274   if (sameRegs (AOP (result), AOP (right)))
6275     {
6276       operand *tmp = right;
6277       right = left;
6278       left = tmp;
6279     }
6280
6281   /* if right is bit then exchange them */
6282   if (AOP_TYPE (right) == AOP_CRY &&
6283       AOP_TYPE (left) != AOP_CRY)
6284     {
6285       operand *tmp = right;
6286       right = left;
6287       left = tmp;
6288     }
6289   if (AOP_TYPE (right) == AOP_LIT)
6290     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6291
6292   size = AOP_SIZE (result);
6293
6294   // if(bit | yy)
6295   // xx = bit | yy;
6296   if (AOP_TYPE (left) == AOP_CRY)
6297     {
6298       if (AOP_TYPE (right) == AOP_LIT)
6299         {
6300           // c = bit | literal;
6301           if (lit)
6302             {
6303               // lit != 0 => result = 1
6304               if (AOP_TYPE (result) == AOP_CRY)
6305                 {
6306                   if (size)
6307                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6308                   else if (ifx)
6309                     continueIfTrue (ifx);
6310                   goto release;
6311                 }
6312               emitcode ("setb", "c");
6313             }
6314           else
6315             {
6316               // lit == 0 => result = left
6317               if (size && sameRegs (AOP (result), AOP (left)))
6318                 goto release;
6319               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6320             }
6321         }
6322       else
6323         {
6324           if (AOP_TYPE (right) == AOP_CRY)
6325             {
6326               // c = bit | bit;
6327               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6328               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6329             }
6330           else
6331             {
6332               // c = bit | val;
6333               symbol *tlbl = newiTempLabel (NULL);
6334               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6335                 emitcode ("setb", "c");
6336               emitcode ("jb", "%s,%05d$",
6337                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6338               toBoolean (right);
6339               emitcode ("jnz", "%05d$", tlbl->key + 100);
6340               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6341                 {
6342                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6343                   goto release;
6344                 }
6345               else
6346                 {
6347                   CLRC;
6348                   emitcode ("", "%05d$:", tlbl->key + 100);
6349                 }
6350             }
6351         }
6352       // bit = c
6353       // val = c
6354       if (size)
6355         outBitC (result);
6356       // if(bit | ...)
6357       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6358         genIfxJump (ifx, "c", left, right, result);
6359       goto release;
6360     }
6361
6362   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6363   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6364   if ((AOP_TYPE (right) == AOP_LIT) &&
6365       (AOP_TYPE (result) == AOP_CRY) &&
6366       (AOP_TYPE (left) != AOP_CRY))
6367     {
6368       if (lit)
6369         {
6370           // result = 1
6371           if (size)
6372             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6373           else
6374             continueIfTrue (ifx);
6375           goto release;
6376         }
6377       else
6378         {
6379           // lit = 0, result = boolean(left)
6380           if (size)
6381             emitcode ("setb", "c");
6382           toBoolean (right);
6383           if (size)
6384             {
6385               symbol *tlbl = newiTempLabel (NULL);
6386               emitcode ("jnz", "%05d$", tlbl->key + 100);
6387               CLRC;
6388               emitcode ("", "%05d$:", tlbl->key + 100);
6389             }
6390           else
6391             {
6392               genIfxJump (ifx, "a", left, right, result);
6393               goto release;
6394             }
6395         }
6396       outBitC (result);
6397       goto release;
6398     }
6399
6400   /* if left is same as result */
6401   if (sameRegs (AOP (result), AOP (left)))
6402     {
6403       for (; size--; offset++)
6404         {
6405           if (AOP_TYPE (right) == AOP_LIT)
6406             {
6407               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6408               if (bytelit == 0)
6409                 {
6410                   /* dummy read of volatile operand */
6411                   if (isOperandVolatile (left, FALSE))
6412                     MOVA (aopGet (left, offset, FALSE, FALSE));
6413                   else
6414                     continue;
6415                 }
6416               else if (bytelit == 0x0FF)
6417                 {
6418                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6419                 }
6420               else if (IS_AOP_PREG (left))
6421                 {
6422                   MOVA (aopGet (left, offset, FALSE, TRUE));
6423                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6424                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6425                 }
6426               else
6427                 {
6428                   emitcode ("orl", "%s,%s",
6429                             aopGet (left, offset, FALSE, TRUE),
6430                             aopGet (right, offset, FALSE, FALSE));
6431                 }
6432             }
6433           else
6434             {
6435               if (AOP_TYPE (left) == AOP_ACC)
6436                 {
6437                   if (offset)
6438                     emitcode("mov", "a,b");
6439                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6440                 }
6441               else
6442                 {
6443                   MOVA (aopGet (right, offset, FALSE, FALSE));
6444                   if (IS_AOP_PREG (left))
6445                     {
6446                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6447                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6448                     }
6449                   else
6450                     {
6451                       emitcode ("orl", "%s,a",
6452                                 aopGet (left, offset, FALSE, TRUE));
6453                     }
6454                 }
6455             }
6456         }
6457     }
6458   else
6459     {
6460       // left & result in different registers
6461       if (AOP_TYPE (result) == AOP_CRY)
6462         {
6463           // result = bit
6464           // if(size), result in bit
6465           // if(!size && ifx), conditional oper: if(left | right)
6466           symbol *tlbl = newiTempLabel (NULL);
6467           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6468           if (size)
6469             emitcode ("setb", "c");
6470           while (sizer--)
6471             {
6472               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6473                 if (offset)
6474                   emitcode("mov", "a,b");
6475                 emitcode ("orl", "a,%s",
6476                           aopGet (right, offset, FALSE, FALSE));
6477               } else {
6478                 MOVA (aopGet (right, offset, FALSE, FALSE));
6479                 emitcode ("orl", "a,%s",
6480                           aopGet (left, offset, FALSE, FALSE));
6481               }
6482               emitcode ("jnz", "%05d$", tlbl->key + 100);
6483               offset++;
6484             }
6485           if (size)
6486             {
6487               CLRC;
6488               emitcode ("", "%05d$:", tlbl->key + 100);
6489               outBitC (result);
6490             }
6491           else if (ifx)
6492             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6493           else
6494             emitcode ("", "%05d$:", tlbl->key + 100);
6495         }
6496       else
6497         {
6498           for (; (size--); offset++)
6499             {
6500               // normal case
6501               // result = left | right
6502               if (AOP_TYPE (right) == AOP_LIT)
6503                 {
6504                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6505                   if (bytelit == 0)
6506                     {
6507                       aopPut (result,
6508                               aopGet (left, offset, FALSE, FALSE),
6509                               offset,
6510                               isOperandVolatile (result, FALSE));
6511                       continue;
6512                     }
6513                   else if (bytelit == 0x0FF)
6514                     {
6515                       /* dummy read of volatile operand */
6516                       if (isOperandVolatile (left, FALSE))
6517                         MOVA (aopGet (left, offset, FALSE, FALSE));
6518                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6519                       continue;
6520                     }
6521                 }
6522               // faster than result <- left, anl result,right
6523               // and better if result is SFR
6524               if (AOP_TYPE (left) == AOP_ACC)
6525                 {
6526                   if (offset)
6527                     emitcode("mov", "a,b");
6528                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6529                 }
6530               else
6531                 {
6532                   MOVA (aopGet (right, offset, FALSE, FALSE));
6533                   emitcode ("orl", "a,%s",
6534                             aopGet (left, offset, FALSE, FALSE));
6535                 }
6536               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6537             }
6538         }
6539     }
6540
6541 release:
6542   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6543   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6544   freeAsmop (result, NULL, ic, TRUE);
6545 }
6546
6547 /*-----------------------------------------------------------------*/
6548 /* genXor - code for xclusive or                                   */
6549 /*-----------------------------------------------------------------*/
6550 static void
6551 genXor (iCode * ic, iCode * ifx)
6552 {
6553   operand *left, *right, *result;
6554   int size, offset = 0;
6555   unsigned long lit = 0L;
6556   int bytelit = 0;
6557
6558   D(emitcode (";     genXor",""));
6559
6560   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6561   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6562   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6563
6564 #ifdef DEBUG_TYPE
6565   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6566             AOP_TYPE (result),
6567             AOP_TYPE (left), AOP_TYPE (right));
6568   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6569             AOP_SIZE (result),
6570             AOP_SIZE (left), AOP_SIZE (right));
6571 #endif
6572
6573   /* if left is a literal & right is not ||
6574      if left needs acc & right does not */
6575   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6576       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6577     {
6578       operand *tmp = right;
6579       right = left;
6580       left = tmp;
6581     }
6582
6583   /* if result = right then exchange them */
6584   if (sameRegs (AOP (result), AOP (right)))
6585     {
6586       operand *tmp = right;
6587       right = left;
6588       left = tmp;
6589     }
6590
6591   /* if right is bit then exchange them */
6592   if (AOP_TYPE (right) == AOP_CRY &&
6593       AOP_TYPE (left) != AOP_CRY)
6594     {
6595       operand *tmp = right;
6596       right = left;
6597       left = tmp;
6598     }
6599   if (AOP_TYPE (right) == AOP_LIT)
6600     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6601
6602   size = AOP_SIZE (result);
6603
6604   // if(bit ^ yy)
6605   // xx = bit ^ yy;
6606   if (AOP_TYPE (left) == AOP_CRY)
6607     {
6608       if (AOP_TYPE (right) == AOP_LIT)
6609         {
6610           // c = bit & literal;
6611           if (lit >> 1)
6612             {
6613               // lit>>1  != 0 => result = 1
6614               if (AOP_TYPE (result) == AOP_CRY)
6615                 {
6616                   if (size)
6617                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6618                   else if (ifx)
6619                     continueIfTrue (ifx);
6620                   goto release;
6621                 }
6622               emitcode ("setb", "c");
6623             }
6624           else
6625             {
6626               // lit == (0 or 1)
6627               if (lit == 0)
6628                 {
6629                   // lit == 0, result = left
6630                   if (size && sameRegs (AOP (result), AOP (left)))
6631                     goto release;
6632                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6633                 }
6634               else
6635                 {
6636                   // lit == 1, result = not(left)
6637                   if (size && sameRegs (AOP (result), AOP (left)))
6638                     {
6639                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6640                       goto release;
6641                     }
6642                   else
6643                     {
6644                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6645                       emitcode ("cpl", "c");
6646                     }
6647                 }
6648             }
6649
6650         }
6651       else
6652         {
6653           // right != literal
6654           symbol *tlbl = newiTempLabel (NULL);
6655           if (AOP_TYPE (right) == AOP_CRY)
6656             {
6657               // c = bit ^ bit;
6658               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6659             }
6660           else
6661             {
6662               int sizer = AOP_SIZE (right);
6663               // c = bit ^ val
6664               // if val>>1 != 0, result = 1
6665               emitcode ("setb", "c");
6666               while (sizer)
6667                 {
6668                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6669                   if (sizer == 1)
6670                     // test the msb of the lsb
6671                     emitcode ("anl", "a,#0xfe");
6672                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6673                   sizer--;
6674                 }
6675               // val = (0,1)
6676               emitcode ("rrc", "a");
6677             }
6678           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6679           emitcode ("cpl", "c");
6680           emitcode ("", "%05d$:", (tlbl->key + 100));
6681         }
6682       // bit = c
6683       // val = c
6684       if (size)
6685         outBitC (result);
6686       // if(bit | ...)
6687       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6688         genIfxJump (ifx, "c", left, right, result);
6689       goto release;
6690     }
6691
6692   /* if left is same as result */
6693   if (sameRegs (AOP (result), AOP (left)))
6694     {
6695       for (; size--; offset++)
6696         {
6697           if (AOP_TYPE (right) == AOP_LIT)
6698             {
6699               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6700               if (bytelit == 0)
6701                 {
6702                   /* dummy read of volatile operand */
6703                   if (isOperandVolatile (left, FALSE))
6704                     MOVA (aopGet (left, offset, FALSE, FALSE));
6705                   else
6706                     continue;
6707                 }
6708               else if (IS_AOP_PREG (left))
6709                 {
6710                   MOVA (aopGet (left, offset, FALSE, TRUE));
6711                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6712                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6713                 }
6714               else
6715                 {
6716                   emitcode ("xrl", "%s,%s",
6717                             aopGet (left, offset, FALSE, TRUE),
6718                             aopGet (right, offset, FALSE, FALSE));
6719                 }
6720             }
6721           else
6722             {
6723               if (AOP_TYPE (left) == AOP_ACC)
6724                 {
6725                   if (offset)
6726                     emitcode("mov", "a,b");
6727                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6728                 }
6729               else
6730                 {
6731                   MOVA (aopGet (right, offset, FALSE, FALSE));
6732                   if (IS_AOP_PREG (left))
6733                     {
6734                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6735                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6736                     }
6737                   else
6738                     emitcode ("xrl", "%s,a",
6739                               aopGet (left, offset, FALSE, TRUE));
6740                 }
6741             }
6742         }
6743     }
6744   else
6745     {
6746       // left & result in different registers
6747       if (AOP_TYPE (result) == AOP_CRY)
6748         {
6749           // result = bit
6750           // if(size), result in bit
6751           // if(!size && ifx), conditional oper: if(left ^ right)
6752           symbol *tlbl = newiTempLabel (NULL);
6753           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6754           if (size)
6755             emitcode ("setb", "c");
6756           while (sizer--)
6757             {
6758               if ((AOP_TYPE (right) == AOP_LIT) &&
6759                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6760                 {
6761                   MOVA (aopGet (left, offset, FALSE, FALSE));
6762                 }
6763               else
6764                 {
6765                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6766                     if (offset)
6767                       emitcode("mov", "a,b");
6768                     emitcode ("xrl", "a,%s",
6769                               aopGet (right, offset, FALSE, FALSE));
6770                   } else {
6771                     MOVA (aopGet (right, offset, FALSE, FALSE));
6772                     emitcode ("xrl", "a,%s",
6773                               aopGet (left, offset, FALSE, FALSE));
6774                   }
6775                 }
6776               emitcode ("jnz", "%05d$", tlbl->key + 100);
6777               offset++;
6778             }
6779           if (size)
6780             {
6781               CLRC;
6782               emitcode ("", "%05d$:", tlbl->key + 100);
6783               outBitC (result);
6784             }
6785           else if (ifx)
6786             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6787         }
6788       else
6789         {
6790           for (; (size--); offset++)
6791             {
6792               // normal case
6793               // result = left & right
6794               if (AOP_TYPE (right) == AOP_LIT)
6795                 {
6796                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6797                   if (bytelit == 0)
6798                     {
6799                       aopPut (result,
6800                               aopGet (left, offset, FALSE, FALSE),
6801                               offset,
6802                               isOperandVolatile (result, FALSE));
6803                       continue;
6804                     }
6805                 }
6806               // faster than result <- left, anl result,right
6807               // and better if result is SFR
6808               if (AOP_TYPE (left) == AOP_ACC)
6809                 {
6810                   if (offset)
6811                     emitcode("mov", "a,b");
6812                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6813                 }
6814               else
6815                 {
6816                   MOVA (aopGet (right, offset, FALSE, FALSE));
6817                   emitcode ("xrl", "a,%s",
6818                             aopGet (left, offset, FALSE, TRUE));
6819                 }
6820               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6821             }
6822         }
6823     }
6824
6825 release:
6826   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6827   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828   freeAsmop (result, NULL, ic, TRUE);
6829 }
6830
6831 /*-----------------------------------------------------------------*/
6832 /* genInline - write the inline code out                           */
6833 /*-----------------------------------------------------------------*/
6834 static void
6835 genInline (iCode * ic)
6836 {
6837   char *buffer, *bp, *bp1;
6838
6839   D(emitcode (";     genInline",""));
6840
6841   _G.inLine += (!options.asmpeep);
6842
6843   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6844   strcpy (buffer, IC_INLINE (ic));
6845
6846   /* emit each line as a code */
6847   while (*bp)
6848     {
6849       if (*bp == '\n')
6850         {
6851           *bp++ = '\0';
6852           emitcode (bp1, "");
6853           bp1 = bp;
6854         }
6855       else
6856         {
6857           /* Add \n for labels, not dirs such as c:\mydir */
6858           if ( (*bp == ':') && (isspace(bp[1])) )
6859             {
6860               bp++;
6861               *bp = '\0';
6862               bp++;
6863               emitcode (bp1, "");
6864               bp1 = bp;
6865             }
6866           else
6867             bp++;
6868         }
6869     }
6870   if (bp1 != bp)
6871     emitcode (bp1, "");
6872   /*     emitcode("",buffer); */
6873   _G.inLine -= (!options.asmpeep);
6874 }
6875
6876 /*-----------------------------------------------------------------*/
6877 /* genRRC - rotate right with carry                                */
6878 /*-----------------------------------------------------------------*/
6879 static void
6880 genRRC (iCode * ic)
6881 {
6882   operand *left, *result;
6883   int size, offset = 0;
6884   char *l;
6885
6886   D(emitcode (";     genRRC",""));
6887
6888   /* rotate right with carry */
6889   left = IC_LEFT (ic);
6890   result = IC_RESULT (ic);
6891   aopOp (left, ic, FALSE);
6892   aopOp (result, ic, FALSE);
6893
6894   /* move it to the result */
6895   size = AOP_SIZE (result);
6896   offset = size - 1;
6897   if (size == 1) { /* special case for 1 byte */
6898       l = aopGet (left, offset, FALSE, FALSE);
6899       MOVA (l);
6900       emitcode ("rr", "a");
6901       goto release;
6902   }
6903   /* no need to clear carry, bit7 will be written later */
6904   while (size--)
6905     {
6906       l = aopGet (left, offset, FALSE, FALSE);
6907       MOVA (l);
6908       emitcode ("rrc", "a");
6909       if (AOP_SIZE (result) > 1)
6910         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
6911     }
6912   /* now we need to put the carry into the
6913      highest order byte of the result */
6914   if (AOP_SIZE (result) > 1)
6915     {
6916       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
6917       MOVA (l);
6918     }
6919   emitcode ("mov", "acc.7,c");
6920  release:
6921   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6922   freeAsmop (left, NULL, ic, TRUE);
6923   freeAsmop (result, NULL, ic, TRUE);
6924 }
6925
6926 /*-----------------------------------------------------------------*/
6927 /* genRLC - generate code for rotate left with carry               */
6928 /*-----------------------------------------------------------------*/
6929 static void
6930 genRLC (iCode * ic)
6931 {
6932   operand *left, *result;
6933   int size, offset = 0;
6934   char *l;
6935
6936   D(emitcode (";     genRLC",""));
6937
6938   /* rotate right with carry */
6939   left = IC_LEFT (ic);
6940   result = IC_RESULT (ic);
6941   aopOp (left, ic, FALSE);
6942   aopOp (result, ic, FALSE);
6943
6944   /* move it to the result */
6945   size = AOP_SIZE (result);
6946   offset = 0;
6947   if (size--)
6948     {
6949       l = aopGet (left, offset, FALSE, FALSE);
6950       MOVA (l);
6951       if (size == 0) { /* special case for 1 byte */
6952               emitcode("rl","a");
6953               goto release;
6954       }
6955       emitcode("rlc","a"); /* bit0 will be written later */
6956       if (AOP_SIZE (result) > 1)
6957         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6958       while (size--)
6959         {
6960           l = aopGet (left, offset, FALSE, FALSE);
6961           MOVA (l);
6962           emitcode ("rlc", "a");
6963           if (AOP_SIZE (result) > 1)
6964             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6965         }
6966     }
6967   /* now we need to put the carry into the
6968      highest order byte of the result */
6969   if (AOP_SIZE (result) > 1)
6970     {
6971       l = aopGet (result, 0, FALSE, FALSE);
6972       MOVA (l);
6973     }
6974   emitcode ("mov", "acc.0,c");
6975  release:
6976   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6977   freeAsmop (left, NULL, ic, TRUE);
6978   freeAsmop (result, NULL, ic, TRUE);
6979 }
6980
6981 /*-----------------------------------------------------------------*/
6982 /* genGetHbit - generates code get highest order bit               */
6983 /*-----------------------------------------------------------------*/
6984 static void
6985 genGetHbit (iCode * ic)
6986 {
6987   operand *left, *result;
6988
6989   D(emitcode (";     genGetHbit",""));
6990
6991   left = IC_LEFT (ic);
6992   result = IC_RESULT (ic);
6993   aopOp (left, ic, FALSE);
6994   aopOp (result, ic, FALSE);
6995
6996   /* get the highest order byte into a */
6997   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
6998   if (AOP_TYPE (result) == AOP_CRY)
6999     {
7000       emitcode ("rlc", "a");
7001       outBitC (result);
7002     }
7003   else
7004     {
7005       emitcode ("rl", "a");
7006       emitcode ("anl", "a,#0x01");
7007       outAcc (result);
7008     }
7009
7010
7011   freeAsmop (left, NULL, ic, TRUE);
7012   freeAsmop (result, NULL, ic, TRUE);
7013 }
7014
7015 /*-----------------------------------------------------------------*/
7016 /* genSwap - generates code to swap nibbles or bytes               */
7017 /*-----------------------------------------------------------------*/
7018 static void
7019 genSwap (iCode * ic)
7020 {
7021   operand *left, *result;
7022
7023   D(emitcode (";     genSwap",""));
7024
7025   left = IC_LEFT (ic);
7026   result = IC_RESULT (ic);
7027   aopOp (left, ic, FALSE);
7028   aopOp (result, ic, FALSE);
7029
7030   switch (AOP_SIZE (left))
7031     {
7032     case 1: /* swap nibbles in byte */
7033       MOVA (aopGet (left, 0, FALSE, FALSE));
7034       emitcode ("swap", "a");
7035       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7036       break;
7037     case 2: /* swap bytes in word */
7038       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7039         {
7040           MOVA (aopGet (left, 0, FALSE, FALSE));
7041           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7042                   0, isOperandVolatile (result, FALSE));
7043           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7044         }
7045       else if (operandsEqu (left, result))
7046         {
7047           char * reg = "a";
7048           bool pushedB = FALSE, leftInB = FALSE;
7049
7050           MOVA (aopGet (left, 0, FALSE, FALSE));
7051           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7052             {
7053               pushedB = pushB ();
7054               emitcode ("mov", "b,a");
7055               reg = "b";
7056               leftInB = TRUE;
7057             }
7058           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7059                   0, isOperandVolatile (result, FALSE));
7060           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7061
7062           if (leftInB)
7063             popB (pushedB);
7064         }
7065       else
7066         {
7067           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7068                   0, isOperandVolatile (result, FALSE));
7069           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7070                   1, isOperandVolatile (result, FALSE));
7071         }
7072       break;
7073     default:
7074       wassertl(FALSE, "unsupported SWAP operand size");
7075     }
7076
7077   freeAsmop (left, NULL, ic, TRUE);
7078   freeAsmop (result, NULL, ic, TRUE);
7079 }
7080
7081
7082 /*-----------------------------------------------------------------*/
7083 /* AccRol - rotate left accumulator by known count                 */
7084 /*-----------------------------------------------------------------*/
7085 static void
7086 AccRol (int shCount)
7087 {
7088   shCount &= 0x0007;            // shCount : 0..7
7089
7090   switch (shCount)
7091     {
7092     case 0:
7093       break;
7094     case 1:
7095       emitcode ("rl", "a");
7096       break;
7097     case 2:
7098       emitcode ("rl", "a");
7099       emitcode ("rl", "a");
7100       break;
7101     case 3:
7102       emitcode ("swap", "a");
7103       emitcode ("rr", "a");
7104       break;
7105     case 4:
7106       emitcode ("swap", "a");
7107       break;
7108     case 5:
7109       emitcode ("swap", "a");
7110       emitcode ("rl", "a");
7111       break;
7112     case 6:
7113       emitcode ("rr", "a");
7114       emitcode ("rr", "a");
7115       break;
7116     case 7:
7117       emitcode ("rr", "a");
7118       break;
7119     }
7120 }
7121
7122 /*-----------------------------------------------------------------*/
7123 /* AccLsh - left shift accumulator by known count                  */
7124 /*-----------------------------------------------------------------*/
7125 static void
7126 AccLsh (int shCount)
7127 {
7128   if (shCount != 0)
7129     {
7130       if (shCount == 1)
7131         emitcode ("add", "a,acc");
7132       else if (shCount == 2)
7133         {
7134           emitcode ("add", "a,acc");
7135           emitcode ("add", "a,acc");
7136         }
7137       else
7138         {
7139           /* rotate left accumulator */
7140           AccRol (shCount);
7141           /* and kill the lower order bits */
7142           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7143         }
7144     }
7145 }
7146
7147 /*-----------------------------------------------------------------*/
7148 /* AccRsh - right shift accumulator by known count                 */
7149 /*-----------------------------------------------------------------*/
7150 static void
7151 AccRsh (int shCount)
7152 {
7153   if (shCount != 0)
7154     {
7155       if (shCount == 1)
7156         {
7157           CLRC;
7158           emitcode ("rrc", "a");
7159         }
7160       else
7161         {
7162           /* rotate right accumulator */
7163           AccRol (8 - shCount);
7164           /* and kill the higher order bits */
7165           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7166         }
7167     }
7168 }
7169
7170 /*-----------------------------------------------------------------*/
7171 /* AccSRsh - signed right shift accumulator by known count                 */
7172 /*-----------------------------------------------------------------*/
7173 static void
7174 AccSRsh (int shCount)
7175 {
7176   symbol *tlbl;
7177   if (shCount != 0)
7178     {
7179       if (shCount == 1)
7180         {
7181           emitcode ("mov", "c,acc.7");
7182           emitcode ("rrc", "a");
7183         }
7184       else if (shCount == 2)
7185         {
7186           emitcode ("mov", "c,acc.7");
7187           emitcode ("rrc", "a");
7188           emitcode ("mov", "c,acc.7");
7189           emitcode ("rrc", "a");
7190         }
7191       else
7192         {
7193           tlbl = newiTempLabel (NULL);
7194           /* rotate right accumulator */
7195           AccRol (8 - shCount);
7196           /* and kill the higher order bits */
7197           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7198           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7199           emitcode ("orl", "a,#0x%02x",
7200                     (unsigned char) ~SRMask[shCount]);
7201           emitcode ("", "%05d$:", tlbl->key + 100);
7202         }
7203     }
7204 }
7205
7206 /*-----------------------------------------------------------------*/
7207 /* shiftR1Left2Result - shift right one byte from left to result   */
7208 /*-----------------------------------------------------------------*/
7209 static void
7210 shiftR1Left2Result (operand * left, int offl,
7211                     operand * result, int offr,
7212                     int shCount, int sign)
7213 {
7214   MOVA (aopGet (left, offl, FALSE, FALSE));
7215   /* shift right accumulator */
7216   if (sign)
7217     AccSRsh (shCount);
7218   else
7219     AccRsh (shCount);
7220   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7221 }
7222
7223 /*-----------------------------------------------------------------*/
7224 /* shiftL1Left2Result - shift left one byte from left to result    */
7225 /*-----------------------------------------------------------------*/
7226 static void
7227 shiftL1Left2Result (operand * left, int offl,
7228                     operand * result, int offr, int shCount)
7229 {
7230   char *l;
7231   l = aopGet (left, offl, FALSE, FALSE);
7232   MOVA (l);
7233   /* shift left accumulator */
7234   AccLsh (shCount);
7235   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7236 }
7237
7238 /*-----------------------------------------------------------------*/
7239 /* movLeft2Result - move byte from left to result                  */
7240 /*-----------------------------------------------------------------*/
7241 static void
7242 movLeft2Result (operand * left, int offl,
7243                 operand * result, int offr, int sign)
7244 {
7245   char *l;
7246   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7247     {
7248       l = aopGet (left, offl, FALSE, FALSE);
7249
7250       if (*l == '@' && (IS_AOP_PREG (result)))
7251         {
7252           emitcode ("mov", "a,%s", l);
7253           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7254         }
7255       else
7256         {
7257           if (!sign)
7258             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7259           else
7260             {
7261               /* MSB sign in acc.7 ! */
7262               if (getDataSize (left) == offl + 1)
7263                 {
7264                   emitcode ("mov", "a,%s", l);
7265                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7266                 }
7267             }
7268         }
7269     }
7270 }
7271
7272 /*-----------------------------------------------------------------*/
7273 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7274 /*-----------------------------------------------------------------*/
7275 static void
7276 AccAXRrl1 (char *x)
7277 {
7278   emitcode ("rrc", "a");
7279   emitcode ("xch", "a,%s", x);
7280   emitcode ("rrc", "a");
7281   emitcode ("xch", "a,%s", x);
7282 }
7283
7284 /*-----------------------------------------------------------------*/
7285 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7286 /*-----------------------------------------------------------------*/
7287 static void
7288 AccAXLrl1 (char *x)
7289 {
7290   emitcode ("xch", "a,%s", x);
7291   emitcode ("rlc", "a");
7292   emitcode ("xch", "a,%s", x);
7293   emitcode ("rlc", "a");
7294 }
7295
7296 /*-----------------------------------------------------------------*/
7297 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7298 /*-----------------------------------------------------------------*/
7299 static void
7300 AccAXLsh1 (char *x)
7301 {
7302   emitcode ("xch", "a,%s", x);
7303   emitcode ("add", "a,acc");
7304   emitcode ("xch", "a,%s", x);
7305   emitcode ("rlc", "a");
7306 }
7307
7308 /*-----------------------------------------------------------------*/
7309 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7310 /*-----------------------------------------------------------------*/
7311 static void
7312 AccAXLsh (char *x, int shCount)
7313 {
7314   switch (shCount)
7315     {
7316     case 0:
7317       break;
7318     case 1:
7319       AccAXLsh1 (x);
7320       break;
7321     case 2:
7322       AccAXLsh1 (x);
7323       AccAXLsh1 (x);
7324       break;
7325     case 3:
7326     case 4:
7327     case 5:                     // AAAAABBB:CCCCCDDD
7328
7329       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7330
7331       emitcode ("anl", "a,#0x%02x",
7332                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7333
7334       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7335
7336       AccRol (shCount);         // DDDCCCCC:BBB00000
7337
7338       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7339
7340       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7341
7342       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7343
7344       emitcode ("anl", "a,#0x%02x",
7345                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7346
7347       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7348
7349       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7350
7351       break;
7352     case 6:                     // AAAAAABB:CCCCCCDD
7353       emitcode ("anl", "a,#0x%02x",
7354                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7355       emitcode ("mov", "c,acc.0");      // c = B
7356       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7357 #if 0 // REMOVE ME
7358       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7359       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7360 #else
7361       emitcode("rrc","a");
7362       emitcode("xch","a,%s", x);
7363       emitcode("rrc","a");
7364       emitcode("mov","c,acc.0"); //<< get correct bit
7365       emitcode("xch","a,%s", x);
7366
7367       emitcode("rrc","a");
7368       emitcode("xch","a,%s", x);
7369       emitcode("rrc","a");
7370       emitcode("xch","a,%s", x);
7371 #endif
7372       break;
7373     case 7:                     // a:x <<= 7
7374
7375       emitcode ("anl", "a,#0x%02x",
7376                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7377
7378       emitcode ("mov", "c,acc.0");      // c = B
7379
7380       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7381
7382       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7383
7384       break;
7385     default:
7386       break;
7387     }
7388 }
7389
7390 /*-----------------------------------------------------------------*/
7391 /* AccAXRsh - right shift a:x known count (0..7)                   */
7392 /*-----------------------------------------------------------------*/
7393 static void
7394 AccAXRsh (char *x, int shCount)
7395 {
7396   switch (shCount)
7397     {
7398     case 0:
7399       break;
7400     case 1:
7401       CLRC;
7402       AccAXRrl1 (x);            // 0->a:x
7403
7404       break;
7405     case 2:
7406       CLRC;
7407       AccAXRrl1 (x);            // 0->a:x
7408
7409       CLRC;
7410       AccAXRrl1 (x);            // 0->a:x
7411
7412       break;
7413     case 3:
7414     case 4:
7415     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7416
7417       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7418
7419       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7420
7421       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7422
7423       emitcode ("anl", "a,#0x%02x",
7424                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7425
7426       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7427
7428       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7429
7430       emitcode ("anl", "a,#0x%02x",
7431                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7432
7433       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7434
7435       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7436
7437       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7438
7439       break;
7440     case 6:                     // AABBBBBB:CCDDDDDD
7441
7442       emitcode ("mov", "c,acc.7");
7443       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7444
7445       emitcode ("mov", "c,acc.7");
7446       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7447
7448       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7449
7450       emitcode ("anl", "a,#0x%02x",
7451                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7452
7453       break;
7454     case 7:                     // ABBBBBBB:CDDDDDDD
7455
7456       emitcode ("mov", "c,acc.7");      // c = A
7457
7458       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7459
7460       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7461
7462       emitcode ("anl", "a,#0x%02x",
7463                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7464
7465       break;
7466     default:
7467       break;
7468     }
7469 }
7470
7471 /*-----------------------------------------------------------------*/
7472 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7473 /*-----------------------------------------------------------------*/
7474 static void
7475 AccAXRshS (char *x, int shCount)
7476 {
7477   symbol *tlbl;
7478   switch (shCount)
7479     {
7480     case 0:
7481       break;
7482     case 1:
7483       emitcode ("mov", "c,acc.7");
7484       AccAXRrl1 (x);            // s->a:x
7485
7486       break;
7487     case 2:
7488       emitcode ("mov", "c,acc.7");
7489       AccAXRrl1 (x);            // s->a:x
7490
7491       emitcode ("mov", "c,acc.7");
7492       AccAXRrl1 (x);            // s->a:x
7493
7494       break;
7495     case 3:
7496     case 4:
7497     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7498
7499       tlbl = newiTempLabel (NULL);
7500       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7501
7502       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7503
7504       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7505
7506       emitcode ("anl", "a,#0x%02x",
7507                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7508
7509       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7510
7511       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7512
7513       emitcode ("anl", "a,#0x%02x",
7514                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7515
7516       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7517
7518       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7519
7520       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7521
7522       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7523       emitcode ("orl", "a,#0x%02x",
7524                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7525
7526       emitcode ("", "%05d$:", tlbl->key + 100);
7527       break;                    // SSSSAAAA:BBBCCCCC
7528
7529     case 6:                     // AABBBBBB:CCDDDDDD
7530
7531       tlbl = newiTempLabel (NULL);
7532       emitcode ("mov", "c,acc.7");
7533       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7534
7535       emitcode ("mov", "c,acc.7");
7536       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7537
7538       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7539
7540       emitcode ("anl", "a,#0x%02x",
7541                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7542
7543       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7544       emitcode ("orl", "a,#0x%02x",
7545                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7546
7547       emitcode ("", "%05d$:", tlbl->key + 100);
7548       break;
7549     case 7:                     // ABBBBBBB:CDDDDDDD
7550
7551       tlbl = newiTempLabel (NULL);
7552       emitcode ("mov", "c,acc.7");      // c = A
7553
7554       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7555
7556       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7557
7558       emitcode ("anl", "a,#0x%02x",
7559                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7560
7561       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7562       emitcode ("orl", "a,#0x%02x",
7563                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7564
7565       emitcode ("", "%05d$:", tlbl->key + 100);
7566       break;
7567     default:
7568       break;
7569     }
7570 }
7571
7572 /*-----------------------------------------------------------------*/
7573 /* shiftL2Left2Result - shift left two bytes from left to result   */
7574 /*-----------------------------------------------------------------*/
7575 static void
7576 shiftL2Left2Result (operand * left, int offl,
7577                     operand * result, int offr, int shCount)
7578 {
7579   if (sameRegs (AOP (result), AOP (left)) &&
7580       ((offl + MSB16) == offr))
7581     {
7582       /* don't crash result[offr] */
7583       MOVA (aopGet (left, offl, FALSE, FALSE));
7584       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7585     }
7586   else
7587     {
7588       movLeft2Result (left, offl, result, offr, 0);
7589       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7590     }
7591   /* ax << shCount (x = lsb(result)) */
7592   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
7593   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7594 }
7595
7596
7597 /*-----------------------------------------------------------------*/
7598 /* shiftR2Left2Result - shift right two bytes from left to result  */
7599 /*-----------------------------------------------------------------*/
7600 static void
7601 shiftR2Left2Result (operand * left, int offl,
7602                     operand * result, int offr,
7603                     int shCount, int sign)
7604 {
7605   if (sameRegs (AOP (result), AOP (left)) &&
7606       ((offl + MSB16) == offr))
7607     {
7608       /* don't crash result[offr] */
7609       MOVA (aopGet (left, offl, FALSE, FALSE));
7610       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7611     }
7612   else
7613     {
7614       movLeft2Result (left, offl, result, offr, 0);
7615       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7616     }
7617   /* a:x >> shCount (x = lsb(result)) */
7618   if (sign)
7619     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
7620   else
7621     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
7622   if (getDataSize (result) > 1)
7623     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7624 }
7625
7626 /*-----------------------------------------------------------------*/
7627 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7628 /*-----------------------------------------------------------------*/
7629 static void
7630 shiftLLeftOrResult (operand * left, int offl,
7631                     operand * result, int offr, int shCount)
7632 {
7633   MOVA (aopGet (left, offl, FALSE, FALSE));
7634   /* shift left accumulator */
7635   AccLsh (shCount);
7636   /* or with result */
7637   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7638   /* back to result */
7639   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7640 }
7641
7642 /*-----------------------------------------------------------------*/
7643 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7644 /*-----------------------------------------------------------------*/
7645 static void
7646 shiftRLeftOrResult (operand * left, int offl,
7647                     operand * result, int offr, int shCount)
7648 {
7649   MOVA (aopGet (left, offl, FALSE, FALSE));
7650   /* shift right accumulator */
7651   AccRsh (shCount);
7652   /* or with result */
7653   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7654   /* back to result */
7655   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7656 }
7657
7658 /*-----------------------------------------------------------------*/
7659 /* genlshOne - left shift a one byte quantity by known count       */
7660 /*-----------------------------------------------------------------*/
7661 static void
7662 genlshOne (operand * result, operand * left, int shCount)
7663 {
7664   D(emitcode (";     genlshOne",""));
7665
7666   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7667 }
7668
7669 /*-----------------------------------------------------------------*/
7670 /* genlshTwo - left shift two bytes by known amount != 0           */
7671 /*-----------------------------------------------------------------*/
7672 static void
7673 genlshTwo (operand * result, operand * left, int shCount)
7674 {
7675   int size;
7676
7677   D(emitcode (";     genlshTwo",""));
7678
7679   size = getDataSize (result);
7680
7681   /* if shCount >= 8 */
7682   if (shCount >= 8)
7683     {
7684       shCount -= 8;
7685
7686       if (size > 1)
7687         {
7688           if (shCount)
7689             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7690           else
7691             movLeft2Result (left, LSB, result, MSB16, 0);
7692         }
7693       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7694     }
7695
7696   /*  1 <= shCount <= 7 */
7697   else
7698     {
7699       if (size == 1)
7700         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7701       else
7702         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7703     }
7704 }
7705
7706 /*-----------------------------------------------------------------*/
7707 /* shiftLLong - shift left one long from left to result            */
7708 /* offl = LSB or MSB16                                             */
7709 /*-----------------------------------------------------------------*/
7710 static void
7711 shiftLLong (operand * left, operand * result, int offr)
7712 {
7713   char *l;
7714   int size = AOP_SIZE (result);
7715
7716   if (size >= LSB + offr)
7717     {
7718       l = aopGet (left, LSB, FALSE, FALSE);
7719       MOVA (l);
7720       emitcode ("add", "a,acc");
7721       if (sameRegs (AOP (left), AOP (result)) &&
7722           size >= MSB16 + offr && offr != LSB)
7723         emitcode ("xch", "a,%s",
7724                   aopGet (left, LSB + offr, FALSE, FALSE));
7725       else
7726         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
7727     }
7728
7729   if (size >= MSB16 + offr)
7730     {
7731       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7732         {
7733           l = aopGet (left, MSB16, FALSE, FALSE);
7734           MOVA (l);
7735         }
7736       emitcode ("rlc", "a");
7737       if (sameRegs (AOP (left), AOP (result)) &&
7738           size >= MSB24 + offr && offr != LSB)
7739         emitcode ("xch", "a,%s",
7740                   aopGet (left, MSB16 + offr, FALSE, FALSE));
7741       else
7742         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7743     }
7744
7745   if (size >= MSB24 + offr)
7746     {
7747       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7748         {
7749           l = aopGet (left, MSB24, FALSE, FALSE);
7750           MOVA (l);
7751         }
7752       emitcode ("rlc", "a");
7753       if (sameRegs (AOP (left), AOP (result)) &&
7754           size >= MSB32 + offr && offr != LSB)
7755         emitcode ("xch", "a,%s",
7756                   aopGet (left, MSB24 + offr, FALSE, FALSE));
7757       else
7758         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7759     }
7760
7761   if (size > MSB32 + offr)
7762     {
7763       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7764         {
7765           l = aopGet (left, MSB32, FALSE, FALSE);
7766           MOVA (l);
7767         }
7768       emitcode ("rlc", "a");
7769       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7770     }
7771   if (offr != LSB)
7772     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7773 }
7774
7775 /*-----------------------------------------------------------------*/
7776 /* genlshFour - shift four byte by a known amount != 0             */
7777 /*-----------------------------------------------------------------*/
7778 static void
7779 genlshFour (operand * result, operand * left, int shCount)
7780 {
7781   int size;
7782
7783   D(emitcode (";     genlshFour",""));
7784
7785   size = AOP_SIZE (result);
7786
7787   /* if shifting more that 3 bytes */
7788   if (shCount >= 24)
7789     {
7790       shCount -= 24;
7791       if (shCount)
7792         /* lowest order of left goes to the highest
7793            order of the destination */
7794         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7795       else
7796         movLeft2Result (left, LSB, result, MSB32, 0);
7797       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7798       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7799       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
7800       return;
7801     }
7802
7803   /* more than two bytes */
7804   else if (shCount >= 16)
7805     {
7806       /* lower order two bytes goes to higher order two bytes */
7807       shCount -= 16;
7808       /* if some more remaining */
7809       if (shCount)
7810         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7811       else
7812         {
7813           movLeft2Result (left, MSB16, result, MSB32, 0);
7814           movLeft2Result (left, LSB, result, MSB24, 0);
7815         }
7816       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7817       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7818       return;
7819     }
7820
7821   /* if more than 1 byte */
7822   else if (shCount >= 8)
7823     {
7824       /* lower order three bytes goes to higher order  three bytes */
7825       shCount -= 8;
7826       if (size == 2)
7827         {
7828           if (shCount)
7829             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7830           else
7831             movLeft2Result (left, LSB, result, MSB16, 0);
7832         }
7833       else
7834         {                       /* size = 4 */
7835           if (shCount == 0)
7836             {
7837               movLeft2Result (left, MSB24, result, MSB32, 0);
7838               movLeft2Result (left, MSB16, result, MSB24, 0);
7839               movLeft2Result (left, LSB, result, MSB16, 0);
7840               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7841             }
7842           else if (shCount == 1)
7843             shiftLLong (left, result, MSB16);
7844           else
7845             {
7846               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7847               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7848               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7849               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7850             }
7851         }
7852     }
7853
7854   /* 1 <= shCount <= 7 */
7855   else if (shCount <= 2)
7856     {
7857       shiftLLong (left, result, LSB);
7858       if (shCount == 2)
7859         shiftLLong (result, result, LSB);
7860     }
7861   /* 3 <= shCount <= 7, optimize */
7862   else
7863     {
7864       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7865       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7866       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7867     }
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genLeftShiftLiteral - left shifting by known count              */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genLeftShiftLiteral (operand * left,
7875                      operand * right,
7876                      operand * result,
7877                      iCode * ic)
7878 {
7879   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7880   int size;
7881
7882   D(emitcode (";     genLeftShiftLiteral",""));
7883
7884   freeAsmop (right, NULL, ic, TRUE);
7885
7886   aopOp (left, ic, FALSE);
7887   aopOp (result, ic, FALSE);
7888
7889   size = getSize (operandType (result));
7890
7891 #if VIEW_SIZE
7892   emitcode ("; shift left ", "result %d, left %d", size,
7893             AOP_SIZE (left));
7894 #endif
7895
7896   /* I suppose that the left size >= result size */
7897   if (shCount == 0)
7898     {
7899       while (size--)
7900         {
7901           movLeft2Result (left, size, result, size, 0);
7902         }
7903     }
7904
7905   else if (shCount >= (size * 8))
7906     while (size--)
7907       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
7908   else
7909     {
7910       switch (size)
7911         {
7912         case 1:
7913           genlshOne (result, left, shCount);
7914           break;
7915
7916         case 2:
7917           genlshTwo (result, left, shCount);
7918           break;
7919
7920         case 4:
7921           genlshFour (result, left, shCount);
7922           break;
7923         default:
7924           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7925                   "*** ack! mystery literal shift!\n");
7926           break;
7927         }
7928     }
7929   freeAsmop (left, NULL, ic, TRUE);
7930   freeAsmop (result, NULL, ic, TRUE);
7931 }
7932
7933 /*-----------------------------------------------------------------*/
7934 /* genLeftShift - generates code for left shifting                 */
7935 /*-----------------------------------------------------------------*/
7936 static void
7937 genLeftShift (iCode * ic)
7938 {
7939   operand *left, *right, *result;
7940   int size, offset;
7941   char *l;
7942   symbol *tlbl, *tlbl1;
7943   bool pushedB;
7944
7945   D(emitcode (";     genLeftShift",""));
7946
7947   right = IC_RIGHT (ic);
7948   left = IC_LEFT (ic);
7949   result = IC_RESULT (ic);
7950
7951   aopOp (right, ic, FALSE);
7952
7953   /* if the shift count is known then do it
7954      as efficiently as possible */
7955   if (AOP_TYPE (right) == AOP_LIT)
7956     {
7957       genLeftShiftLiteral (left, right, result, ic);
7958       return;
7959     }
7960
7961   /* shift count is unknown then we have to form
7962      a loop get the loop count in B : Note: we take
7963      only the lower order byte since shifting
7964      more that 32 bits make no sense anyway, ( the
7965      largest size of an object can be only 32 bits ) */
7966
7967   pushedB = pushB ();
7968   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
7969   emitcode ("inc", "b");
7970   freeAsmop (right, NULL, ic, TRUE);
7971   aopOp (left, ic, FALSE);
7972   aopOp (result, ic, FALSE);
7973
7974   /* now move the left to the result if they are not the same */
7975   if (!sameRegs (AOP (left), AOP (result)) &&
7976       AOP_SIZE (result) > 1)
7977     {
7978
7979       size = AOP_SIZE (result);
7980       offset = 0;
7981       while (size--)
7982         {
7983           l = aopGet (left, offset, FALSE, TRUE);
7984           if (*l == '@' && (IS_AOP_PREG (result)))
7985             {
7986
7987               emitcode ("mov", "a,%s", l);
7988               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7989             }
7990           else
7991             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
7992           offset++;
7993         }
7994     }
7995
7996   tlbl = newiTempLabel (NULL);
7997   size = AOP_SIZE (result);
7998   offset = 0;
7999   tlbl1 = newiTempLabel (NULL);
8000
8001   /* if it is only one byte then */
8002   if (size == 1)
8003     {
8004       symbol *tlbl1 = newiTempLabel (NULL);
8005
8006       l = aopGet (left, 0, FALSE, FALSE);
8007       MOVA (l);
8008       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8009       emitcode ("", "%05d$:", tlbl->key + 100);
8010       emitcode ("add", "a,acc");
8011       emitcode ("", "%05d$:", tlbl1->key + 100);
8012       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8013       popB (pushedB);
8014       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8015       goto release;
8016     }
8017
8018   reAdjustPreg (AOP (result));
8019
8020   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8021   emitcode ("", "%05d$:", tlbl->key + 100);
8022   l = aopGet (result, offset, FALSE, FALSE);
8023   MOVA (l);
8024   emitcode ("add", "a,acc");
8025   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8026   while (--size)
8027     {
8028       l = aopGet (result, offset, FALSE, FALSE);
8029       MOVA (l);
8030       emitcode ("rlc", "a");
8031       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8032     }
8033   reAdjustPreg (AOP (result));
8034
8035   emitcode ("", "%05d$:", tlbl1->key + 100);
8036   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8037   popB (pushedB);
8038 release:
8039   freeAsmop (left, NULL, ic, TRUE);
8040   freeAsmop (result, NULL, ic, TRUE);
8041 }
8042
8043 /*-----------------------------------------------------------------*/
8044 /* genrshOne - right shift a one byte quantity by known count      */
8045 /*-----------------------------------------------------------------*/
8046 static void
8047 genrshOne (operand * result, operand * left,
8048            int shCount, int sign)
8049 {
8050   D(emitcode (";     genrshOne",""));
8051
8052   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8053 }
8054
8055 /*-----------------------------------------------------------------*/
8056 /* genrshTwo - right shift two bytes by known amount != 0          */
8057 /*-----------------------------------------------------------------*/
8058 static void
8059 genrshTwo (operand * result, operand * left,
8060            int shCount, int sign)
8061 {
8062   D(emitcode (";     genrshTwo",""));
8063
8064   /* if shCount >= 8 */
8065   if (shCount >= 8)
8066     {
8067       shCount -= 8;
8068       if (shCount)
8069         shiftR1Left2Result (left, MSB16, result, LSB,
8070                             shCount, sign);
8071       else
8072         movLeft2Result (left, MSB16, result, LSB, sign);
8073       addSign (result, MSB16, sign);
8074     }
8075
8076   /*  1 <= shCount <= 7 */
8077   else
8078     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8079 }
8080
8081 /*-----------------------------------------------------------------*/
8082 /* shiftRLong - shift right one long from left to result           */
8083 /* offl = LSB or MSB16                                             */
8084 /*-----------------------------------------------------------------*/
8085 static void
8086 shiftRLong (operand * left, int offl,
8087             operand * result, int sign)
8088 {
8089   int isSameRegs=sameRegs(AOP(left),AOP(result));
8090
8091   if (isSameRegs && offl>1) {
8092     // we are in big trouble, but this shouldn't happen
8093     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8094   }
8095
8096   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8097
8098   if (offl==MSB16) {
8099     // shift is > 8
8100     if (sign) {
8101       emitcode ("rlc", "a");
8102       emitcode ("subb", "a,acc");
8103       if (isSameRegs)
8104         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8105       else {
8106         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8107         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8108       }
8109     } else {
8110       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8111     }
8112   }
8113
8114   if (!sign) {
8115     emitcode ("clr", "c");
8116   } else {
8117     emitcode ("mov", "c,acc.7");
8118   }
8119
8120   emitcode ("rrc", "a");
8121
8122   if (isSameRegs && offl==MSB16) {
8123     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8124   } else {
8125     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8126     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8127   }
8128
8129   emitcode ("rrc", "a");
8130   if (isSameRegs && offl==1) {
8131     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8132   } else {
8133     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8134     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8135   }
8136   emitcode ("rrc", "a");
8137   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8138
8139   if (offl == LSB)
8140     {
8141       MOVA (aopGet (left, LSB, FALSE, FALSE));
8142       emitcode ("rrc", "a");
8143       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8144     }
8145 }
8146
8147 /*-----------------------------------------------------------------*/
8148 /* genrshFour - shift four byte by a known amount != 0             */
8149 /*-----------------------------------------------------------------*/
8150 static void
8151 genrshFour (operand * result, operand * left,
8152             int shCount, int sign)
8153 {
8154   D(emitcode (";     genrshFour",""));
8155
8156   /* if shifting more that 3 bytes */
8157   if (shCount >= 24)
8158     {
8159       shCount -= 24;
8160       if (shCount)
8161         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8162       else
8163         movLeft2Result (left, MSB32, result, LSB, sign);
8164       addSign (result, MSB16, sign);
8165     }
8166   else if (shCount >= 16)
8167     {
8168       shCount -= 16;
8169       if (shCount)
8170         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8171       else
8172         {
8173           movLeft2Result (left, MSB24, result, LSB, 0);
8174           movLeft2Result (left, MSB32, result, MSB16, sign);
8175         }
8176       addSign (result, MSB24, sign);
8177     }
8178   else if (shCount >= 8)
8179     {
8180       shCount -= 8;
8181       if (shCount == 1)
8182         shiftRLong (left, MSB16, result, sign);
8183       else if (shCount == 0)
8184         {
8185           movLeft2Result (left, MSB16, result, LSB, 0);
8186           movLeft2Result (left, MSB24, result, MSB16, 0);
8187           movLeft2Result (left, MSB32, result, MSB24, sign);
8188           addSign (result, MSB32, sign);
8189         }
8190       else
8191         {
8192           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8193           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8194           /* the last shift is signed */
8195           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8196           addSign (result, MSB32, sign);
8197         }
8198     }
8199   else
8200     {                           /* 1 <= shCount <= 7 */
8201       if (shCount <= 2)
8202         {
8203           shiftRLong (left, LSB, result, sign);
8204           if (shCount == 2)
8205             shiftRLong (result, LSB, result, sign);
8206         }
8207       else
8208         {
8209           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8210           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8211           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8212         }
8213     }
8214 }
8215
8216 /*-----------------------------------------------------------------*/
8217 /* genRightShiftLiteral - right shifting by known count            */
8218 /*-----------------------------------------------------------------*/
8219 static void
8220 genRightShiftLiteral (operand * left,
8221                       operand * right,
8222                       operand * result,
8223                       iCode * ic,
8224                       int sign)
8225 {
8226   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8227   int size;
8228
8229   D(emitcode (";     genRightShiftLiteral",""));
8230
8231   freeAsmop (right, NULL, ic, TRUE);
8232
8233   aopOp (left, ic, FALSE);
8234   aopOp (result, ic, FALSE);
8235
8236 #if VIEW_SIZE
8237   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8238             AOP_SIZE (left));
8239 #endif
8240
8241   size = getDataSize (left);
8242   /* test the LEFT size !!! */
8243
8244   /* I suppose that the left size >= result size */
8245   if (shCount == 0)
8246     {
8247       size = getDataSize (result);
8248       while (size--)
8249         movLeft2Result (left, size, result, size, 0);
8250     }
8251
8252   else if (shCount >= (size * 8))
8253     {
8254       if (sign) {
8255         /* get sign in acc.7 */
8256         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8257       }
8258       addSign (result, LSB, sign);
8259     }
8260   else
8261     {
8262       switch (size)
8263         {
8264         case 1:
8265           genrshOne (result, left, shCount, sign);
8266           break;
8267
8268         case 2:
8269           genrshTwo (result, left, shCount, sign);
8270           break;
8271
8272         case 4:
8273           genrshFour (result, left, shCount, sign);
8274           break;
8275         default:
8276           break;
8277         }
8278     }
8279   freeAsmop (left, NULL, ic, TRUE);
8280   freeAsmop (result, NULL, ic, TRUE);
8281 }
8282
8283 /*-----------------------------------------------------------------*/
8284 /* genSignedRightShift - right shift of signed number              */
8285 /*-----------------------------------------------------------------*/
8286 static void
8287 genSignedRightShift (iCode * ic)
8288 {
8289   operand *right, *left, *result;
8290   int size, offset;
8291   char *l;
8292   symbol *tlbl, *tlbl1;
8293   bool pushedB;
8294
8295   D(emitcode (";     genSignedRightShift",""));
8296
8297   /* we do it the hard way put the shift count in b
8298      and loop thru preserving the sign */
8299
8300   right = IC_RIGHT (ic);
8301   left = IC_LEFT (ic);
8302   result = IC_RESULT (ic);
8303
8304   aopOp (right, ic, FALSE);
8305
8306
8307   if (AOP_TYPE (right) == AOP_LIT)
8308     {
8309       genRightShiftLiteral (left, right, result, ic, 1);
8310       return;
8311     }
8312   /* shift count is unknown then we have to form
8313      a loop get the loop count in B : Note: we take
8314      only the lower order byte since shifting
8315      more that 32 bits make no sense anyway, ( the
8316      largest size of an object can be only 32 bits ) */
8317
8318   pushedB = pushB ();
8319   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8320   emitcode ("inc", "b");
8321   freeAsmop (right, NULL, ic, TRUE);
8322   aopOp (left, ic, FALSE);
8323   aopOp (result, ic, FALSE);
8324
8325   /* now move the left to the result if they are not the
8326      same */
8327   if (!sameRegs (AOP (left), AOP (result)) &&
8328       AOP_SIZE (result) > 1)
8329     {
8330
8331       size = AOP_SIZE (result);
8332       offset = 0;
8333       while (size--)
8334         {
8335           l = aopGet (left, offset, FALSE, TRUE);
8336           if (*l == '@' && IS_AOP_PREG (result))
8337             {
8338
8339               emitcode ("mov", "a,%s", l);
8340               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8341             }
8342           else
8343             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8344           offset++;
8345         }
8346     }
8347
8348   /* mov the highest order bit to OVR */
8349   tlbl = newiTempLabel (NULL);
8350   tlbl1 = newiTempLabel (NULL);
8351
8352   size = AOP_SIZE (result);
8353   offset = size - 1;
8354   MOVA (aopGet (left, offset, FALSE, FALSE));
8355   emitcode ("rlc", "a");
8356   emitcode ("mov", "ov,c");
8357   /* if it is only one byte then */
8358   if (size == 1)
8359     {
8360       l = aopGet (left, 0, FALSE, FALSE);
8361       MOVA (l);
8362       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8363       emitcode ("", "%05d$:", tlbl->key + 100);
8364       emitcode ("mov", "c,ov");
8365       emitcode ("rrc", "a");
8366       emitcode ("", "%05d$:", tlbl1->key + 100);
8367       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8368       popB (pushedB);
8369       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8370       goto release;
8371     }
8372
8373   reAdjustPreg (AOP (result));
8374   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8375   emitcode ("", "%05d$:", tlbl->key + 100);
8376   emitcode ("mov", "c,ov");
8377   while (size--)
8378     {
8379       l = aopGet (result, offset, FALSE, FALSE);
8380       MOVA (l);
8381       emitcode ("rrc", "a");
8382       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8383     }
8384   reAdjustPreg (AOP (result));
8385   emitcode ("", "%05d$:", tlbl1->key + 100);
8386   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8387   popB (pushedB);
8388
8389 release:
8390   freeAsmop (left, NULL, ic, TRUE);
8391   freeAsmop (result, NULL, ic, TRUE);
8392 }
8393
8394 /*-----------------------------------------------------------------*/
8395 /* genRightShift - generate code for right shifting                */
8396 /*-----------------------------------------------------------------*/
8397 static void
8398 genRightShift (iCode * ic)
8399 {
8400   operand *right, *left, *result;
8401   sym_link *letype;
8402   int size, offset;
8403   char *l;
8404   symbol *tlbl, *tlbl1;
8405   bool pushedB;
8406
8407   D(emitcode (";     genRightShift",""));
8408
8409   /* if signed then we do it the hard way preserve the
8410      sign bit moving it inwards */
8411   letype = getSpec (operandType (IC_LEFT (ic)));
8412
8413   if (!SPEC_USIGN (letype))
8414     {
8415       genSignedRightShift (ic);
8416       return;
8417     }
8418
8419   /* signed & unsigned types are treated the same : i.e. the
8420      signed is NOT propagated inwards : quoting from the
8421      ANSI - standard : "for E1 >> E2, is equivalent to division
8422      by 2**E2 if unsigned or if it has a non-negative value,
8423      otherwise the result is implementation defined ", MY definition
8424      is that the sign does not get propagated */
8425
8426   right = IC_RIGHT (ic);
8427   left = IC_LEFT (ic);
8428   result = IC_RESULT (ic);
8429
8430   aopOp (right, ic, FALSE);
8431
8432   /* if the shift count is known then do it
8433      as efficiently as possible */
8434   if (AOP_TYPE (right) == AOP_LIT)
8435     {
8436       genRightShiftLiteral (left, right, result, ic, 0);
8437       return;
8438     }
8439
8440   /* shift count is unknown then we have to form
8441      a loop get the loop count in B : Note: we take
8442      only the lower order byte since shifting
8443      more that 32 bits make no sense anyway, ( the
8444      largest size of an object can be only 32 bits ) */
8445
8446   pushedB = pushB ();
8447   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8448   emitcode ("inc", "b");
8449   freeAsmop (right, NULL, ic, TRUE);
8450   aopOp (left, ic, FALSE);
8451   aopOp (result, ic, FALSE);
8452
8453   /* now move the left to the result if they are not the
8454      same */
8455   if (!sameRegs (AOP (left), AOP (result)) &&
8456       AOP_SIZE (result) > 1)
8457     {
8458
8459       size = AOP_SIZE (result);
8460       offset = 0;
8461       while (size--)
8462         {
8463           l = aopGet (left, offset, FALSE, TRUE);
8464           if (*l == '@' && IS_AOP_PREG (result))
8465             {
8466
8467               emitcode ("mov", "a,%s", l);
8468               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8469             }
8470           else
8471             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8472           offset++;
8473         }
8474     }
8475
8476   tlbl = newiTempLabel (NULL);
8477   tlbl1 = newiTempLabel (NULL);
8478   size = AOP_SIZE (result);
8479   offset = size - 1;
8480
8481   /* if it is only one byte then */
8482   if (size == 1)
8483     {
8484       l = aopGet (left, 0, FALSE, FALSE);
8485       MOVA (l);
8486       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8487       emitcode ("", "%05d$:", tlbl->key + 100);
8488       CLRC;
8489       emitcode ("rrc", "a");
8490       emitcode ("", "%05d$:", tlbl1->key + 100);
8491       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8492       popB (pushedB);
8493       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8494       goto release;
8495     }
8496
8497   reAdjustPreg (AOP (result));
8498   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8499   emitcode ("", "%05d$:", tlbl->key + 100);
8500   CLRC;
8501   while (size--)
8502     {
8503       l = aopGet (result, offset, FALSE, FALSE);
8504       MOVA (l);
8505       emitcode ("rrc", "a");
8506       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8507     }
8508   reAdjustPreg (AOP (result));
8509
8510   emitcode ("", "%05d$:", tlbl1->key + 100);
8511   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8512   popB (pushedB);
8513
8514 release:
8515   freeAsmop (left, NULL, ic, TRUE);
8516   freeAsmop (result, NULL, ic, TRUE);
8517 }
8518
8519 /*-----------------------------------------------------------------*/
8520 /* emitPtrByteGet - emits code to get a byte into A through a      */
8521 /*                  pointer register (R0, R1, or DPTR). The        */
8522 /*                  original value of A can be preserved in B.     */
8523 /*-----------------------------------------------------------------*/
8524 static void
8525 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8526 {
8527   switch (p_type)
8528     {
8529     case IPOINTER:
8530     case POINTER:
8531       if (preserveAinB)
8532         emitcode ("mov", "b,a");
8533       emitcode ("mov", "a,@%s", rname);
8534       break;
8535
8536     case PPOINTER:
8537       if (preserveAinB)
8538         emitcode ("mov", "b,a");
8539       emitcode ("movx", "a,@%s", rname);
8540       break;
8541
8542     case FPOINTER:
8543       if (preserveAinB)
8544         emitcode ("mov", "b,a");
8545       emitcode ("movx", "a,@dptr");
8546       break;
8547
8548     case CPOINTER:
8549       if (preserveAinB)
8550         emitcode ("mov", "b,a");
8551       emitcode ("clr", "a");
8552       emitcode ("movc", "a,@a+dptr");
8553       break;
8554
8555     case GPOINTER:
8556       if (preserveAinB)
8557         {
8558           emitcode ("push", "b");
8559           emitcode ("push", "acc");
8560         }
8561       emitcode ("lcall", "__gptrget");
8562       if (preserveAinB)
8563         emitcode ("pop", "b");
8564       break;
8565     }
8566 }
8567
8568 /*-----------------------------------------------------------------*/
8569 /* emitPtrByteSet - emits code to set a byte from src through a    */
8570 /*                  pointer register (R0, R1, or DPTR).            */
8571 /*-----------------------------------------------------------------*/
8572 static void
8573 emitPtrByteSet (char *rname, int p_type, char *src)
8574 {
8575   switch (p_type)
8576     {
8577     case IPOINTER:
8578     case POINTER:
8579       if (*src=='@')
8580         {
8581           MOVA (src);
8582           emitcode ("mov", "@%s,a", rname);
8583         }
8584       else
8585         emitcode ("mov", "@%s,%s", rname, src);
8586       break;
8587
8588     case PPOINTER:
8589       MOVA (src);
8590       emitcode ("movx", "@%s,a", rname);
8591       break;
8592
8593     case FPOINTER:
8594       MOVA (src);
8595       emitcode ("movx", "@dptr,a");
8596       break;
8597
8598     case GPOINTER:
8599       MOVA (src);
8600       emitcode ("lcall", "__gptrput");
8601       break;
8602     }
8603 }
8604
8605 /*-----------------------------------------------------------------*/
8606 /* genUnpackBits - generates code for unpacking bits               */
8607 /*-----------------------------------------------------------------*/
8608 static void
8609 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8610 {
8611   int offset = 0;       /* result byte offset */
8612   int rsize;            /* result size */
8613   int rlen = 0;         /* remaining bitfield length */
8614   sym_link *etype;      /* bitfield type information */
8615   int blen;             /* bitfield length */
8616   int bstr;             /* bitfield starting bit within byte */
8617   char buffer[10];
8618
8619   D(emitcode (";     genUnpackBits",""));
8620
8621   etype = getSpec (operandType (result));
8622   rsize = getSize (operandType (result));
8623   blen = SPEC_BLEN (etype);
8624   bstr = SPEC_BSTR (etype);
8625
8626   if (ifx && blen <= 8)
8627     {
8628       emitPtrByteGet (rname, ptype, FALSE);
8629       if (blen == 1)
8630         {
8631           SNPRINTF (buffer, sizeof(buffer),
8632                     "acc.%d", bstr);
8633           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8634         }
8635       else
8636         {
8637           if (blen < 8)
8638             emitcode ("anl", "a,#0x%02x",
8639                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8640           genIfxJump (ifx, "a", NULL, NULL, NULL);
8641         }
8642       return;
8643     }
8644   wassert (!ifx);
8645
8646   /* If the bitfield length is less than a byte */
8647   if (blen < 8)
8648     {
8649       emitPtrByteGet (rname, ptype, FALSE);
8650       AccRsh (bstr);
8651       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8652       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8653       goto finish;
8654     }
8655
8656   /* Bit field did not fit in a byte. Copy all
8657      but the partial byte at the end.  */
8658   for (rlen=blen;rlen>=8;rlen-=8)
8659     {
8660       emitPtrByteGet (rname, ptype, FALSE);
8661       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8662       if (rlen>8)
8663         emitcode ("inc", "%s", rname);
8664     }
8665
8666   /* Handle the partial byte at the end */
8667   if (rlen)
8668     {
8669       emitPtrByteGet (rname, ptype, FALSE);
8670       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8671       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8672     }
8673
8674 finish:
8675   if (offset < rsize)
8676     {
8677       rsize -= offset;
8678       while (rsize--)
8679         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
8680     }
8681 }
8682
8683
8684 /*-----------------------------------------------------------------*/
8685 /* genDataPointerGet - generates code when ptr offset is known     */
8686 /*-----------------------------------------------------------------*/
8687 static void
8688 genDataPointerGet (operand * left,
8689                    operand * result,
8690                    iCode * ic)
8691 {
8692   char *l;
8693   char buffer[256];
8694   int size, offset = 0;
8695
8696   D(emitcode (";     genDataPointerGet",""));
8697
8698   aopOp (result, ic, TRUE);
8699
8700   /* get the string representation of the name */
8701   l = aopGet (left, 0, FALSE, TRUE);
8702   size = AOP_SIZE (result);
8703   while (size--)
8704     {
8705       if (offset)
8706         sprintf (buffer, "(%s + %d)", l + 1, offset);
8707       else
8708         sprintf (buffer, "%s", l + 1);
8709       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
8710     }
8711
8712   freeAsmop (left, NULL, ic, TRUE);
8713   freeAsmop (result, NULL, ic, TRUE);
8714 }
8715
8716 /*-----------------------------------------------------------------*/
8717 /* genNearPointerGet - emitcode for near pointer fetch             */
8718 /*-----------------------------------------------------------------*/
8719 static void
8720 genNearPointerGet (operand * left,
8721                    operand * result,
8722                    iCode * ic,
8723                    iCode * pi,
8724                    iCode * ifx)
8725 {
8726   asmop *aop = NULL;
8727   regs *preg = NULL;
8728   char *rname;
8729   sym_link *rtype, *retype;
8730   sym_link *ltype = operandType (left);
8731   char buffer[80];
8732
8733   D(emitcode (";     genNearPointerGet",""));
8734
8735   rtype = operandType (result);
8736   retype = getSpec (rtype);
8737
8738   aopOp (left, ic, FALSE);
8739
8740   /* if left is rematerialisable and
8741      result is not bitfield variable type and
8742      the left is pointer to data space i.e
8743      lower 128 bytes of space */
8744   if (AOP_TYPE (left) == AOP_IMMD &&
8745       !IS_BITFIELD (retype) &&
8746       DCL_TYPE (ltype) == POINTER)
8747     {
8748       genDataPointerGet (left, result, ic);
8749       return;
8750     }
8751
8752  /* if the value is already in a pointer register
8753      then don't need anything more */
8754   if (!AOP_INPREG (AOP (left)))
8755     {
8756       if (IS_AOP_PREG (left))
8757         {
8758           // Aha, it is a pointer, just in disguise.
8759           rname = aopGet (left, 0, FALSE, FALSE);
8760           if (*rname != '@')
8761             {
8762               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8763                       __FILE__, __LINE__);
8764             }
8765           else
8766             {
8767               // Expected case.
8768               emitcode ("mov", "a%s,%s", rname + 1, rname);
8769               rname++;  // skip the '@'.
8770             }
8771         }
8772       else
8773         {
8774           /* otherwise get a free pointer register */
8775           aop = newAsmop (0);
8776           preg = getFreePtr (ic, &aop, FALSE);
8777           emitcode ("mov", "%s,%s",
8778                     preg->name,
8779                     aopGet (left, 0, FALSE, TRUE));
8780           rname = preg->name;
8781         }
8782     }
8783   else
8784     rname = aopGet (left, 0, FALSE, FALSE);
8785
8786   //aopOp (result, ic, FALSE);
8787   aopOp (result, ic, result?TRUE:FALSE);
8788
8789   /* if bitfield then unpack the bits */
8790   if (IS_BITFIELD (retype))
8791     genUnpackBits (result, rname, POINTER, ifx);
8792   else
8793     {
8794       /* we have can just get the values */
8795       int size = AOP_SIZE (result);
8796       int offset = 0;
8797
8798       while (size--)
8799         {
8800           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8801             {
8802
8803               emitcode ("mov", "a,@%s", rname);
8804               if (!ifx)
8805               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8806             }
8807           else
8808             {
8809               sprintf (buffer, "@%s", rname);
8810               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
8811             }
8812           offset++;
8813           if (size || pi)
8814             emitcode ("inc", "%s", rname);
8815         }
8816     }
8817
8818   /* now some housekeeping stuff */
8819   if (aop)       /* we had to allocate for this iCode */
8820     {
8821       if (pi) { /* post increment present */
8822         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8823       }
8824       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8825     }
8826   else
8827     {
8828       /* we did not allocate which means left
8829          already in a pointer register, then
8830          if size > 0 && this could be used again
8831          we have to point it back to where it
8832          belongs */
8833       if ((AOP_SIZE (result) > 1 &&
8834            !OP_SYMBOL (left)->remat &&
8835            (OP_SYMBOL (left)->liveTo > ic->seq ||
8836             ic->depth)) &&
8837           !pi)
8838         {
8839           int size = AOP_SIZE (result) - 1;
8840           while (size--)
8841             emitcode ("dec", "%s", rname);
8842         }
8843     }
8844
8845   if (ifx && !ifx->generated)
8846     {
8847       genIfxJump (ifx, "a", left, NULL, result);
8848     }
8849
8850   /* done */
8851   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8852   freeAsmop (left, NULL, ic, TRUE);
8853   if (pi) pi->generated = 1;
8854 }
8855
8856 /*-----------------------------------------------------------------*/
8857 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8858 /*-----------------------------------------------------------------*/
8859 static void
8860 genPagedPointerGet (operand * left,
8861                     operand * result,
8862                     iCode * ic,
8863                     iCode *pi,
8864                     iCode *ifx)
8865 {
8866   asmop *aop = NULL;
8867   regs *preg = NULL;
8868   char *rname;
8869   sym_link *rtype, *retype;
8870
8871   D(emitcode (";     genPagedPointerGet",""));
8872
8873   rtype = operandType (result);
8874   retype = getSpec (rtype);
8875
8876   aopOp (left, ic, FALSE);
8877
8878   /* if the value is already in a pointer register
8879      then don't need anything more */
8880   if (!AOP_INPREG (AOP (left)))
8881     {
8882       /* otherwise get a free pointer register */
8883       aop = newAsmop (0);
8884       preg = getFreePtr (ic, &aop, FALSE);
8885       emitcode ("mov", "%s,%s",
8886                 preg->name,
8887                 aopGet (left, 0, FALSE, TRUE));
8888       rname = preg->name;
8889     }
8890   else
8891     rname = aopGet (left, 0, FALSE, FALSE);
8892
8893   aopOp (result, ic, FALSE);
8894
8895   /* if bitfield then unpack the bits */
8896   if (IS_BITFIELD (retype))
8897     genUnpackBits (result, rname, PPOINTER, ifx);
8898   else
8899     {
8900       /* we have can just get the values */
8901       int size = AOP_SIZE (result);
8902       int offset = 0;
8903
8904       while (size--)
8905         {
8906
8907           emitcode ("movx", "a,@%s", rname);
8908           if (!ifx)
8909           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8910
8911           offset++;
8912
8913           if (size || pi)
8914             emitcode ("inc", "%s", rname);
8915         }
8916     }
8917
8918   /* now some housekeeping stuff */
8919   if (aop) /* we had to allocate for this iCode */
8920     {
8921       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8922       freeAsmop (NULL, aop, ic, TRUE);
8923     }
8924   else
8925     {
8926       /* we did not allocate which means left
8927          already in a pointer register, then
8928          if size > 0 && this could be used again
8929          we have to point it back to where it
8930          belongs */
8931       if ((AOP_SIZE (result) > 1 &&
8932            !OP_SYMBOL (left)->remat &&
8933            (OP_SYMBOL (left)->liveTo > ic->seq ||
8934             ic->depth)) &&
8935           !pi)
8936         {
8937           int size = AOP_SIZE (result) - 1;
8938           while (size--)
8939             emitcode ("dec", "%s", rname);
8940         }
8941     }
8942
8943   if (ifx && !ifx->generated)
8944     {
8945       genIfxJump (ifx, "a", left, NULL, result);
8946     }
8947
8948   /* done */
8949   freeAsmop (left, NULL, ic, TRUE);
8950   freeAsmop (result, NULL, ic, TRUE);
8951   if (pi) pi->generated = 1;
8952
8953 }
8954
8955 /*--------------------------------------------------------------------*/
8956 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8957 /*--------------------------------------------------------------------*/
8958 static void
8959 loadDptrFromOperand (operand *op, bool loadBToo)
8960 {
8961   if (AOP_TYPE (op) != AOP_STR)
8962     {
8963       /* if this is rematerializable */
8964       if (AOP_TYPE (op) == AOP_IMMD)
8965         {
8966           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
8967           if (loadBToo)
8968             {
8969               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8970                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
8971               else
8972                 {
8973                   wassertl(FALSE, "need pointerCode");
8974                   emitcode ("", "; mov b,???");
8975                   /* genPointerGet and genPointerSet originally did different
8976                   ** things for this case. Both seem wrong.
8977                   ** from genPointerGet:
8978                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8979                   ** from genPointerSet:
8980                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
8981                   */
8982                 }
8983             }
8984         }
8985       else if (AOP_TYPE (op) == AOP_DPTR)
8986         {
8987           if (loadBToo)
8988             {
8989               MOVA (aopGet (op, 0, FALSE, FALSE));
8990               emitcode ("push", "acc");
8991               MOVA (aopGet (op, 1, FALSE, FALSE));
8992               emitcode ("push", "acc");
8993               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8994               emitcode ("pop", "dph");
8995               emitcode ("pop", "dpl");
8996             }
8997           else
8998             {
8999               MOVA (aopGet (op, 0, FALSE, FALSE));
9000               emitcode ("push", "acc");
9001               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9002               emitcode ("pop", "dpl");
9003             }
9004         }
9005       else
9006         {                       /* we need to get it byte by byte */
9007           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9008           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9009           if (loadBToo)
9010             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9011         }
9012     }
9013 }
9014
9015 /*-----------------------------------------------------------------*/
9016 /* genFarPointerGet - gget value from far space                    */
9017 /*-----------------------------------------------------------------*/
9018 static void
9019 genFarPointerGet (operand * left,
9020                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9021 {
9022   int size, offset;
9023   sym_link *retype = getSpec (operandType (result));
9024
9025   D(emitcode (";     genFarPointerGet",""));
9026
9027   aopOp (left, ic, FALSE);
9028   loadDptrFromOperand (left, FALSE);
9029
9030   /* so dptr now contains the address */
9031   aopOp (result, ic, FALSE);
9032
9033   /* if bit then unpack */
9034   if (IS_BITFIELD (retype))
9035     genUnpackBits (result, "dptr", FPOINTER, ifx);
9036   else
9037     {
9038       size = AOP_SIZE (result);
9039       offset = 0;
9040
9041       while (size--)
9042         {
9043           emitcode ("movx", "a,@dptr");
9044           if (!ifx)
9045             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9046           if (size || pi)
9047             emitcode ("inc", "dptr");
9048         }
9049     }
9050
9051   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9052     {
9053     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9054     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9055     pi->generated = 1;
9056   }
9057
9058   if (ifx && !ifx->generated)
9059     {
9060       genIfxJump (ifx, "a", left, NULL, result);
9061     }
9062
9063   freeAsmop (left, NULL, ic, TRUE);
9064   freeAsmop (result, NULL, ic, TRUE);
9065 }
9066
9067 /*-----------------------------------------------------------------*/
9068 /* genCodePointerGet - gget value from code space                  */
9069 /*-----------------------------------------------------------------*/
9070 static void
9071 genCodePointerGet (operand * left,
9072                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9073 {
9074   int size, offset;
9075   sym_link *retype = getSpec (operandType (result));
9076
9077   D(emitcode (";     genCodePointerGet",""));
9078
9079   aopOp (left, ic, FALSE);
9080   loadDptrFromOperand (left, FALSE);
9081
9082   /* so dptr now contains the address */
9083   aopOp (result, ic, FALSE);
9084
9085   /* if bit then unpack */
9086   if (IS_BITFIELD (retype))
9087     genUnpackBits (result, "dptr", CPOINTER, ifx);
9088   else
9089     {
9090       size = AOP_SIZE (result);
9091       offset = 0;
9092
9093       while (size--)
9094         {
9095           if (pi)
9096             {
9097               emitcode ("clr", "a");
9098               emitcode ("movc", "a,@a+dptr");
9099               if (!ifx)
9100               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9101               emitcode ("inc", "dptr");
9102             }
9103           else
9104             {
9105               emitcode ("mov", "a,#0x%02x", offset);
9106               emitcode ("movc", "a,@a+dptr");
9107               if (!ifx)
9108               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9109             }
9110         }
9111     }
9112
9113   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9114     {
9115     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9116     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9117     pi->generated = 1;
9118   }
9119
9120   if (ifx && !ifx->generated)
9121     {
9122       genIfxJump (ifx, "a", left, NULL, result);
9123     }
9124
9125   freeAsmop (left, NULL, ic, TRUE);
9126   freeAsmop (result, NULL, ic, TRUE);
9127 }
9128
9129 /*-----------------------------------------------------------------*/
9130 /* genGenPointerGet - gget value from generic pointer space        */
9131 /*-----------------------------------------------------------------*/
9132 static void
9133 genGenPointerGet (operand * left,
9134                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9135 {
9136   int size, offset;
9137   sym_link *retype = getSpec (operandType (result));
9138
9139   D(emitcode (";     genGenPointerGet",""));
9140
9141   aopOp (left, ic, FALSE);
9142   loadDptrFromOperand (left, TRUE);
9143
9144   /* so dptr know contains the address */
9145   aopOp (result, ic, FALSE);
9146
9147   /* if bit then unpack */
9148   if (IS_BITFIELD (retype))
9149     genUnpackBits (result, "dptr", GPOINTER, ifx);
9150   else
9151     {
9152       size = AOP_SIZE (result);
9153       offset = 0;
9154
9155       while (size--)
9156         {
9157           emitcode ("lcall", "__gptrget");
9158           if (!ifx)
9159           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9160           if (size || pi)
9161             emitcode ("inc", "dptr");
9162         }
9163     }
9164
9165   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9166     {
9167     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9168     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9169     pi->generated = 1;
9170   }
9171
9172   if (ifx && !ifx->generated)
9173     {
9174       genIfxJump (ifx, "a", left, NULL, result);
9175     }
9176
9177
9178   freeAsmop (left, NULL, ic, TRUE);
9179   freeAsmop (result, NULL, ic, TRUE);
9180 }
9181
9182 /*-----------------------------------------------------------------*/
9183 /* genPointerGet - generate code for pointer get                   */
9184 /*-----------------------------------------------------------------*/
9185 static void
9186 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9187 {
9188   operand *left, *result;
9189   sym_link *type, *etype;
9190   int p_type;
9191
9192   D(emitcode (";     genPointerGet",""));
9193
9194   left = IC_LEFT (ic);
9195   result = IC_RESULT (ic);
9196
9197   if (getSize (operandType (result))>1)
9198     ifx = NULL;
9199
9200   /* depending on the type of pointer we need to
9201      move it to the correct pointer register */
9202   type = operandType (left);
9203   etype = getSpec (type);
9204   /* if left is of type of pointer then it is simple */
9205   if (IS_PTR (type) && !IS_FUNC (type->next))
9206     p_type = DCL_TYPE (type);
9207   else
9208     {
9209       /* we have to go by the storage class */
9210       p_type = PTR_TYPE (SPEC_OCLS (etype));
9211     }
9212
9213   /* special case when cast remat */
9214   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9215       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9216           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9217           type = operandType (left);
9218           p_type = DCL_TYPE (type);
9219   }
9220   /* now that we have the pointer type we assign
9221      the pointer values */
9222   switch (p_type)
9223     {
9224
9225     case POINTER:
9226     case IPOINTER:
9227       genNearPointerGet (left, result, ic, pi, ifx);
9228       break;
9229
9230     case PPOINTER:
9231       genPagedPointerGet (left, result, ic, pi, ifx);
9232       break;
9233
9234     case FPOINTER:
9235       genFarPointerGet (left, result, ic, pi, ifx);
9236       break;
9237
9238     case CPOINTER:
9239       genCodePointerGet (left, result, ic, pi, ifx);
9240       break;
9241
9242     case GPOINTER:
9243       genGenPointerGet (left, result, ic, pi, ifx);
9244       break;
9245     }
9246
9247 }
9248
9249
9250
9251 /*-----------------------------------------------------------------*/
9252 /* genPackBits - generates code for packed bit storage             */
9253 /*-----------------------------------------------------------------*/
9254 static void
9255 genPackBits (sym_link * etype,
9256              operand * right,
9257              char *rname, int p_type)
9258 {
9259   int offset = 0;       /* source byte offset */
9260   int rlen = 0;         /* remaining bitfield length */
9261   int blen;             /* bitfield length */
9262   int bstr;             /* bitfield starting bit within byte */
9263   int litval;           /* source literal value (if AOP_LIT) */
9264   unsigned char mask;   /* bitmask within current byte */
9265
9266   D(emitcode (";     genPackBits",""));
9267
9268   blen = SPEC_BLEN (etype);
9269   bstr = SPEC_BSTR (etype);
9270
9271   /* If the bitfield length is less than a byte */
9272   if (blen < 8)
9273     {
9274       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9275               (unsigned char) (0xFF >> (8 - bstr)));
9276
9277       if (AOP_TYPE (right) == AOP_LIT)
9278         {
9279           /* Case with a bitfield length <8 and literal source
9280           */
9281           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9282           litval <<= bstr;
9283           litval &= (~mask) & 0xff;
9284           emitPtrByteGet (rname, p_type, FALSE);
9285           if ((mask|litval)!=0xff)
9286             emitcode ("anl","a,#0x%02x", mask);
9287           if (litval)
9288             emitcode ("orl","a,#0x%02x", litval);
9289         }
9290       else
9291         {
9292           if ((blen==1) && (p_type!=GPOINTER))
9293             {
9294               /* Case with a bitfield length == 1 and no generic pointer
9295               */
9296               if (AOP_TYPE (right) == AOP_CRY)
9297                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9298               else
9299                 {
9300                   MOVA (aopGet (right, 0, FALSE, FALSE));
9301                   emitcode ("rrc","a");
9302                 }
9303               emitPtrByteGet (rname, p_type, FALSE);
9304               emitcode ("mov","acc.%d,c",bstr);
9305             }
9306           else
9307             {
9308               bool pushedB;
9309               /* Case with a bitfield length < 8 and arbitrary source
9310               */
9311               MOVA (aopGet (right, 0, FALSE, FALSE));
9312               /* shift and mask source value */
9313               AccLsh (bstr);
9314               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9315
9316               pushedB = pushB ();
9317               /* transfer A to B and get next byte */
9318               emitPtrByteGet (rname, p_type, TRUE);
9319
9320               emitcode ("anl", "a,#0x%02x", mask);
9321               emitcode ("orl", "a,b");
9322               if (p_type == GPOINTER)
9323                 emitcode ("pop", "b");
9324
9325               popB (pushedB);
9326            }
9327         }
9328
9329       emitPtrByteSet (rname, p_type, "a");
9330       return;
9331     }
9332
9333   /* Bit length is greater than 7 bits. In this case, copy  */
9334   /* all except the partial byte at the end                 */
9335   for (rlen=blen;rlen>=8;rlen-=8)
9336     {
9337       emitPtrByteSet (rname, p_type,
9338                       aopGet (right, offset++, FALSE, TRUE) );
9339       if (rlen>8)
9340         emitcode ("inc", "%s", rname);
9341     }
9342
9343   /* If there was a partial byte at the end */
9344   if (rlen)
9345     {
9346       mask = (((unsigned char) -1 << rlen) & 0xff);
9347
9348       if (AOP_TYPE (right) == AOP_LIT)
9349         {
9350           /* Case with partial byte and literal source
9351           */
9352           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9353           litval >>= (blen-rlen);
9354           litval &= (~mask) & 0xff;
9355           emitPtrByteGet (rname, p_type, FALSE);
9356           if ((mask|litval)!=0xff)
9357             emitcode ("anl","a,#0x%02x", mask);
9358           if (litval)
9359             emitcode ("orl","a,#0x%02x", litval);
9360         }
9361       else
9362         {
9363           bool pushedB;
9364           /* Case with partial byte and arbitrary source
9365           */
9366           MOVA (aopGet (right, offset++, FALSE, FALSE));
9367           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9368
9369           pushedB = pushB ();
9370           /* transfer A to B and get next byte */
9371           emitPtrByteGet (rname, p_type, TRUE);
9372
9373           emitcode ("anl", "a,#0x%02x", mask);
9374           emitcode ("orl", "a,b");
9375           if (p_type == GPOINTER)
9376             emitcode ("pop", "b");
9377
9378           popB (pushedB);
9379         }
9380       emitPtrByteSet (rname, p_type, "a");
9381     }
9382
9383 }
9384
9385
9386 /*-----------------------------------------------------------------*/
9387 /* genDataPointerSet - remat pointer to data space                 */
9388 /*-----------------------------------------------------------------*/
9389 static void
9390 genDataPointerSet (operand * right,
9391                    operand * result,
9392                    iCode * ic)
9393 {
9394   int size, offset = 0;
9395   char *l, buffer[256];
9396
9397   D(emitcode (";     genDataPointerSet",""));
9398
9399   aopOp (right, ic, FALSE);
9400
9401   l = aopGet (result, 0, FALSE, TRUE);
9402   size = AOP_SIZE (right);
9403   while (size--)
9404     {
9405       if (offset)
9406         sprintf (buffer, "(%s + %d)", l + 1, offset);
9407       else
9408         sprintf (buffer, "%s", l + 1);
9409       emitcode ("mov", "%s,%s", buffer,
9410                 aopGet (right, offset++, FALSE, FALSE));
9411     }
9412
9413   freeAsmop (right, NULL, ic, TRUE);
9414   freeAsmop (result, NULL, ic, TRUE);
9415 }
9416
9417 /*-----------------------------------------------------------------*/
9418 /* genNearPointerSet - emitcode for near pointer put                */
9419 /*-----------------------------------------------------------------*/
9420 static void
9421 genNearPointerSet (operand * right,
9422                    operand * result,
9423                    iCode * ic,
9424                    iCode * pi)
9425 {
9426   asmop *aop = NULL;
9427   regs *preg = NULL;
9428   char *rname, *l;
9429   sym_link *retype, *letype;
9430   sym_link *ptype = operandType (result);
9431
9432   D(emitcode (";     genNearPointerSet",""));
9433
9434   retype = getSpec (operandType (right));
9435   letype = getSpec (ptype);
9436   aopOp (result, ic, FALSE);
9437
9438   /* if the result is rematerializable &
9439      in data space & not a bit variable */
9440   if (AOP_TYPE (result) == AOP_IMMD &&
9441       DCL_TYPE (ptype) == POINTER &&
9442       !IS_BITVAR (retype) &&
9443       !IS_BITVAR (letype))
9444     {
9445       genDataPointerSet (right, result, ic);
9446       return;
9447     }
9448
9449   /* if the value is already in a pointer register
9450      then don't need anything more */
9451   if (!AOP_INPREG (AOP (result)))
9452     {
9453         if (
9454             //AOP_TYPE (result) == AOP_STK
9455             IS_AOP_PREG(result)
9456             )
9457         {
9458             // Aha, it is a pointer, just in disguise.
9459             rname = aopGet (result, 0, FALSE, FALSE);
9460             if (*rname != '@')
9461             {
9462                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9463                         __FILE__, __LINE__);
9464             }
9465             else
9466             {
9467                 // Expected case.
9468                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9469                 rname++;  // skip the '@'.
9470             }
9471         }
9472         else
9473         {
9474             /* otherwise get a free pointer register */
9475             aop = newAsmop (0);
9476             preg = getFreePtr (ic, &aop, FALSE);
9477             emitcode ("mov", "%s,%s",
9478                       preg->name,
9479                       aopGet (result, 0, FALSE, TRUE));
9480             rname = preg->name;
9481         }
9482     }
9483     else
9484     {
9485         rname = aopGet (result, 0, FALSE, FALSE);
9486     }
9487
9488   aopOp (right, ic, FALSE);
9489
9490   /* if bitfield then unpack the bits */
9491   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9492     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9493   else
9494     {
9495       /* we have can just get the values */
9496       int size = AOP_SIZE (right);
9497       int offset = 0;
9498
9499       while (size--)
9500         {
9501           l = aopGet (right, offset, FALSE, TRUE);
9502           if (*l == '@')
9503             {
9504               MOVA (l);
9505               emitcode ("mov", "@%s,a", rname);
9506             }
9507           else
9508             emitcode ("mov", "@%s,%s", rname, l);
9509           if (size || pi)
9510             emitcode ("inc", "%s", rname);
9511           offset++;
9512         }
9513     }
9514
9515   /* now some housekeeping stuff */
9516   if (aop) /* we had to allocate for this iCode */
9517     {
9518       if (pi)
9519         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9520       freeAsmop (NULL, aop, ic, TRUE);
9521     }
9522   else
9523     {
9524       /* we did not allocate which means left
9525          already in a pointer register, then
9526          if size > 0 && this could be used again
9527          we have to point it back to where it
9528          belongs */
9529       if ((AOP_SIZE (right) > 1 &&
9530            !OP_SYMBOL (result)->remat &&
9531            (OP_SYMBOL (result)->liveTo > ic->seq ||
9532             ic->depth)) &&
9533           !pi)
9534         {
9535           int size = AOP_SIZE (right) - 1;
9536           while (size--)
9537             emitcode ("dec", "%s", rname);
9538         }
9539     }
9540
9541   /* done */
9542   if (pi) pi->generated = 1;
9543   freeAsmop (result, NULL, ic, TRUE);
9544   freeAsmop (right, NULL, ic, TRUE);
9545 }
9546
9547 /*-----------------------------------------------------------------*/
9548 /* genPagedPointerSet - emitcode for Paged pointer put             */
9549 /*-----------------------------------------------------------------*/
9550 static void
9551 genPagedPointerSet (operand * right,
9552                     operand * result,
9553                     iCode * ic,
9554                     iCode * pi)
9555 {
9556   asmop *aop = NULL;
9557   regs *preg = NULL;
9558   char *rname, *l;
9559   sym_link *retype, *letype;
9560
9561   D(emitcode (";     genPagedPointerSet",""));
9562
9563   retype = getSpec (operandType (right));
9564   letype = getSpec (operandType (result));
9565
9566   aopOp (result, ic, FALSE);
9567
9568   /* if the value is already in a pointer register
9569      then don't need anything more */
9570   if (!AOP_INPREG (AOP (result)))
9571     {
9572       /* otherwise get a free pointer register */
9573       aop = newAsmop (0);
9574       preg = getFreePtr (ic, &aop, FALSE);
9575       emitcode ("mov", "%s,%s",
9576                 preg->name,
9577                 aopGet (result, 0, FALSE, TRUE));
9578       rname = preg->name;
9579     }
9580   else
9581     rname = aopGet (result, 0, FALSE, FALSE);
9582
9583   aopOp (right, ic, FALSE);
9584
9585   /* if bitfield then unpack the bits */
9586   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9587     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9588   else
9589     {
9590       /* we have can just get the values */
9591       int size = AOP_SIZE (right);
9592       int offset = 0;
9593
9594       while (size--)
9595         {
9596           l = aopGet (right, offset, FALSE, TRUE);
9597
9598           MOVA (l);
9599           emitcode ("movx", "@%s,a", rname);
9600
9601           if (size || pi)
9602             emitcode ("inc", "%s", rname);
9603
9604           offset++;
9605         }
9606     }
9607
9608   /* now some housekeeping stuff */
9609   if (aop) /* we had to allocate for this iCode */
9610     {
9611       if (pi)
9612         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9613       freeAsmop (NULL, aop, ic, TRUE);
9614     }
9615   else
9616     {
9617       /* we did not allocate which means left
9618          already in a pointer register, then
9619          if size > 0 && this could be used again
9620          we have to point it back to where it
9621          belongs */
9622       if (AOP_SIZE (right) > 1 &&
9623           !OP_SYMBOL (result)->remat &&
9624           (OP_SYMBOL (result)->liveTo > ic->seq ||
9625            ic->depth))
9626         {
9627           int size = AOP_SIZE (right) - 1;
9628           while (size--)
9629             emitcode ("dec", "%s", rname);
9630         }
9631     }
9632
9633   /* done */
9634   if (pi) pi->generated = 1;
9635   freeAsmop (result, NULL, ic, TRUE);
9636   freeAsmop (right, NULL, ic, TRUE);
9637
9638
9639 }
9640
9641 /*-----------------------------------------------------------------*/
9642 /* genFarPointerSet - set value from far space                     */
9643 /*-----------------------------------------------------------------*/
9644 static void
9645 genFarPointerSet (operand * right,
9646                   operand * result, iCode * ic, iCode * pi)
9647 {
9648   int size, offset;
9649   sym_link *retype = getSpec (operandType (right));
9650   sym_link *letype = getSpec (operandType (result));
9651
9652   D(emitcode (";     genFarPointerSet",""));
9653
9654   aopOp (result, ic, FALSE);
9655   loadDptrFromOperand (result, FALSE);
9656
9657   /* so dptr know contains the address */
9658   aopOp (right, ic, FALSE);
9659
9660   /* if bit then unpack */
9661   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9662     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9663   else
9664     {
9665       size = AOP_SIZE (right);
9666       offset = 0;
9667
9668       while (size--)
9669         {
9670           char *l = aopGet (right, offset++, FALSE, FALSE);
9671           MOVA (l);
9672           emitcode ("movx", "@dptr,a");
9673           if (size || pi)
9674             emitcode ("inc", "dptr");
9675         }
9676     }
9677   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9678     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9679     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9680     pi->generated=1;
9681   }
9682   freeAsmop (result, NULL, ic, TRUE);
9683   freeAsmop (right, NULL, ic, TRUE);
9684 }
9685
9686 /*-----------------------------------------------------------------*/
9687 /* genGenPointerSet - set value from generic pointer space         */
9688 /*-----------------------------------------------------------------*/
9689 static void
9690 genGenPointerSet (operand * right,
9691                   operand * result, iCode * ic, iCode * pi)
9692 {
9693   int size, offset;
9694   sym_link *retype = getSpec (operandType (right));
9695   sym_link *letype = getSpec (operandType (result));
9696
9697   D(emitcode (";     genGenPointerSet",""));
9698
9699   aopOp (result, ic, FALSE);
9700   loadDptrFromOperand (result, TRUE);
9701
9702   /* so dptr know contains the address */
9703   aopOp (right, ic, FALSE);
9704
9705   /* if bit then unpack */
9706   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9707     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9708   else
9709     {
9710       size = AOP_SIZE (right);
9711       offset = 0;
9712
9713       while (size--)
9714         {
9715           char *l = aopGet (right, offset++, FALSE, FALSE);
9716           MOVA (l);
9717           emitcode ("lcall", "__gptrput");
9718           if (size || pi)
9719             emitcode ("inc", "dptr");
9720         }
9721     }
9722
9723   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9724     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9725     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9726     pi->generated=1;
9727   }
9728   freeAsmop (result, NULL, ic, TRUE);
9729   freeAsmop (right, NULL, ic, TRUE);
9730 }
9731
9732 /*-----------------------------------------------------------------*/
9733 /* genPointerSet - stores the value into a pointer location        */
9734 /*-----------------------------------------------------------------*/
9735 static void
9736 genPointerSet (iCode * ic, iCode *pi)
9737 {
9738   operand *right, *result;
9739   sym_link *type, *etype;
9740   int p_type;
9741
9742   D(emitcode (";     genPointerSet",""));
9743
9744   right = IC_RIGHT (ic);
9745   result = IC_RESULT (ic);
9746
9747   /* depending on the type of pointer we need to
9748      move it to the correct pointer register */
9749   type = operandType (result);
9750   etype = getSpec (type);
9751   /* if left is of type of pointer then it is simple */
9752   if (IS_PTR (type) && !IS_FUNC (type->next))
9753     {
9754       p_type = DCL_TYPE (type);
9755     }
9756   else
9757     {
9758       /* we have to go by the storage class */
9759       p_type = PTR_TYPE (SPEC_OCLS (etype));
9760     }
9761
9762   /* special case when cast remat */
9763   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9764       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9765           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9766           type = operandType (result);
9767           p_type = DCL_TYPE (type);
9768   }
9769   /* now that we have the pointer type we assign
9770      the pointer values */
9771   switch (p_type)
9772     {
9773
9774     case POINTER:
9775     case IPOINTER:
9776       genNearPointerSet (right, result, ic, pi);
9777       break;
9778
9779     case PPOINTER:
9780       genPagedPointerSet (right, result, ic, pi);
9781       break;
9782
9783     case FPOINTER:
9784       genFarPointerSet (right, result, ic, pi);
9785       break;
9786
9787     case GPOINTER:
9788       genGenPointerSet (right, result, ic, pi);
9789       break;
9790
9791     default:
9792       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9793               "genPointerSet: illegal pointer type");
9794     }
9795
9796 }
9797
9798 /*-----------------------------------------------------------------*/
9799 /* genIfx - generate code for Ifx statement                        */
9800 /*-----------------------------------------------------------------*/
9801 static void
9802 genIfx (iCode * ic, iCode * popIc)
9803 {
9804   operand *cond = IC_COND (ic);
9805   int isbit = 0;
9806
9807   D(emitcode (";     genIfx",""));
9808
9809   aopOp (cond, ic, FALSE);
9810
9811   /* get the value into acc */
9812   if (AOP_TYPE (cond) != AOP_CRY)
9813     toBoolean (cond);
9814   else
9815     isbit = 1;
9816   /* the result is now in the accumulator */
9817   freeAsmop (cond, NULL, ic, TRUE);
9818
9819   /* if there was something to be popped then do it */
9820   if (popIc)
9821     genIpop (popIc);
9822
9823   /* if the condition is a bit variable */
9824   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9825     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9826   else if (isbit && !IS_ITEMP (cond))
9827     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9828   else
9829     genIfxJump (ic, "a", NULL, NULL, NULL);
9830
9831   ic->generated = 1;
9832 }
9833
9834 /*-----------------------------------------------------------------*/
9835 /* genAddrOf - generates code for address of                       */
9836 /*-----------------------------------------------------------------*/
9837 static void
9838 genAddrOf (iCode * ic)
9839 {
9840   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9841   int size, offset;
9842
9843   D(emitcode (";     genAddrOf",""));
9844
9845   aopOp (IC_RESULT (ic), ic, FALSE);
9846
9847   /* if the operand is on the stack then we
9848      need to get the stack offset of this
9849      variable */
9850   if (sym->onStack)
9851     {
9852       /* if it has an offset then we need to compute
9853          it */
9854       if (sym->stack)
9855         {
9856           emitcode ("mov", "a,%s", SYM_BP (sym));
9857           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9858                                          ((char) (sym->stack - _G.nRegsSaved)) :
9859                                          ((char) sym->stack)) & 0xff);
9860           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9861         }
9862       else
9863         {
9864           /* we can just move _bp */
9865           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9866         }
9867       /* fill the result with zero */
9868       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9869
9870       offset = 1;
9871       while (size--)
9872         {
9873           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9874         }
9875
9876       goto release;
9877     }
9878
9879   /* object not on stack then we need the name */
9880   size = AOP_SIZE (IC_RESULT (ic));
9881   offset = 0;
9882
9883   while (size--)
9884     {
9885       char s[SDCC_NAME_MAX];
9886       if (offset)
9887         sprintf (s, "#(%s >> %d)",
9888                  sym->rname,
9889                  offset * 8);
9890       else
9891         sprintf (s, "#%s", sym->rname);
9892       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9893     }
9894
9895 release:
9896   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9897
9898 }
9899
9900 /*-----------------------------------------------------------------*/
9901 /* genFarFarAssign - assignment when both are in far space         */
9902 /*-----------------------------------------------------------------*/
9903 static void
9904 genFarFarAssign (operand * result, operand * right, iCode * ic)
9905 {
9906   int size = AOP_SIZE (right);
9907   int offset = 0;
9908   char *l;
9909
9910   D(emitcode (";     genFarFarAssign",""));
9911
9912   /* first push the right side on to the stack */
9913   while (size--)
9914     {
9915       l = aopGet (right, offset++, FALSE, FALSE);
9916       MOVA (l);
9917       emitcode ("push", "acc");
9918     }
9919
9920   freeAsmop (right, NULL, ic, FALSE);
9921   /* now assign DPTR to result */
9922   aopOp (result, ic, FALSE);
9923   size = AOP_SIZE (result);
9924   while (size--)
9925     {
9926       emitcode ("pop", "acc");
9927       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
9928     }
9929   freeAsmop (result, NULL, ic, FALSE);
9930
9931 }
9932
9933 /*-----------------------------------------------------------------*/
9934 /* genAssign - generate code for assignment                        */
9935 /*-----------------------------------------------------------------*/
9936 static void
9937 genAssign (iCode * ic)
9938 {
9939   operand *result, *right;
9940   int size, offset;
9941   unsigned long lit = 0L;
9942
9943   D(emitcode(";     genAssign",""));
9944
9945   result = IC_RESULT (ic);
9946   right = IC_RIGHT (ic);
9947
9948   /* if they are the same */
9949   if (operandsEqu (result, right) &&
9950       !isOperandVolatile (result, FALSE) &&
9951       !isOperandVolatile (right, FALSE))
9952     return;
9953
9954   aopOp (right, ic, FALSE);
9955
9956   /* special case both in far space */
9957   if (AOP_TYPE (right) == AOP_DPTR &&
9958       IS_TRUE_SYMOP (result) &&
9959       isOperandInFarSpace (result))
9960     {
9961
9962       genFarFarAssign (result, right, ic);
9963       return;
9964     }
9965
9966   aopOp (result, ic, TRUE);
9967
9968   /* if they are the same registers */
9969   if (sameRegs (AOP (right), AOP (result)) &&
9970       !isOperandVolatile (result, FALSE) &&
9971       !isOperandVolatile (right, FALSE))
9972     goto release;
9973
9974   /* if the result is a bit */
9975   if (AOP_TYPE (result) == AOP_CRY)
9976     {
9977
9978       /* if the right size is a literal then
9979          we know what the value is */
9980       if (AOP_TYPE (right) == AOP_LIT)
9981         {
9982           if (((int) operandLitValue (right)))
9983             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
9984           else
9985             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
9986           goto release;
9987         }
9988
9989       /* the right is also a bit variable */
9990       if (AOP_TYPE (right) == AOP_CRY)
9991         {
9992           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9993           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
9994           goto release;
9995         }
9996
9997       /* we need to or */
9998       toBoolean (right);
9999       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10000       goto release;
10001     }
10002
10003   /* bit variables done */
10004   /* general case */
10005   size = AOP_SIZE (result);
10006   offset = 0;
10007   if (AOP_TYPE (right) == AOP_LIT)
10008     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10009   if ((size > 1) &&
10010       (AOP_TYPE (result) != AOP_REG) &&
10011       (AOP_TYPE (right) == AOP_LIT) &&
10012       !IS_FLOAT (operandType (right)) &&
10013       (lit < 256L))
10014     {
10015       while ((size) && (lit))
10016         {
10017           aopPut (result,
10018                   aopGet (right, offset, FALSE, FALSE),
10019                   offset,
10020                   isOperandVolatile (result, FALSE));
10021           lit >>= 8;
10022           offset++;
10023           size--;
10024         }
10025       emitcode ("clr", "a");
10026       while (size--)
10027         {
10028           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10029           offset++;
10030         }
10031     }
10032   else
10033     {
10034       while (size--)
10035         {
10036           aopPut (result,
10037                   aopGet (right, offset, FALSE, FALSE),
10038                   offset,
10039                   isOperandVolatile (result, FALSE));
10040           offset++;
10041         }
10042     }
10043
10044 release:
10045   freeAsmop (right, NULL, ic, TRUE);
10046   freeAsmop (result, NULL, ic, TRUE);
10047 }
10048
10049 /*-----------------------------------------------------------------*/
10050 /* genJumpTab - generates code for jump table                      */
10051 /*-----------------------------------------------------------------*/
10052 static void
10053 genJumpTab (iCode * ic)
10054 {
10055   symbol *jtab,*jtablo,*jtabhi;
10056   char *l;
10057   unsigned int count;
10058
10059   D(emitcode (";     genJumpTab",""));
10060
10061   count = elementsInSet( IC_JTLABELS (ic) );
10062
10063   if( count <= 16 )
10064     {
10065       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10066          if the switch argument is in a register.
10067          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10068       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10069          How will multiply by three be updated ???*/
10070       aopOp (IC_JTCOND (ic), ic, FALSE);
10071       /* get the condition into accumulator */
10072       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10073       MOVA (l);
10074       /* multiply by three */
10075       emitcode ("add", "a,acc");
10076       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10077       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10078
10079       jtab = newiTempLabel (NULL);
10080       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10081       emitcode ("jmp", "@a+dptr");
10082       emitcode ("", "%05d$:", jtab->key + 100);
10083       /* now generate the jump labels */
10084       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10085            jtab = setNextItem (IC_JTLABELS (ic)))
10086         emitcode ("ljmp", "%05d$", jtab->key + 100);
10087     }
10088   else
10089     {
10090       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10091          if the switch argument is in a register.
10092          For n>6 this algorithm may be more compact */
10093       jtablo = newiTempLabel (NULL);
10094       jtabhi = newiTempLabel (NULL);
10095
10096       /* get the condition into accumulator.
10097          Using b as temporary storage, if register push/pop is needed */
10098       aopOp (IC_JTCOND (ic), ic, FALSE);
10099       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10100       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10101           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10102         {
10103           // (MB) what if B is in use???
10104           wassertl(!BINUSE, "B was in use");
10105           emitcode ("mov", "b,%s", l);
10106           l = "b";
10107         }
10108       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10109       MOVA (l);
10110       if( count <= 112 )
10111         {
10112           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10113           emitcode ("movc", "a,@a+pc");
10114           emitcode ("push", "acc");
10115
10116           MOVA (l);
10117           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10118           emitcode ("movc", "a,@a+pc");
10119           emitcode ("push", "acc");
10120         }
10121       else
10122         {
10123           /* this scales up to n<=255, but needs two more bytes
10124              and changes dptr */
10125           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10126           emitcode ("movc", "a,@a+dptr");
10127           emitcode ("push", "acc");
10128
10129           MOVA (l);
10130           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10131           emitcode ("movc", "a,@a+dptr");
10132           emitcode ("push", "acc");
10133         }
10134
10135       emitcode ("ret", "");
10136
10137       /* now generate jump table, LSB */
10138       emitcode ("", "%05d$:", jtablo->key + 100);
10139       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10140            jtab = setNextItem (IC_JTLABELS (ic)))
10141         emitcode (".db", "%05d$", jtab->key + 100);
10142
10143       /* now generate jump table, MSB */
10144       emitcode ("", "%05d$:", jtabhi->key + 100);
10145       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10146            jtab = setNextItem (IC_JTLABELS (ic)))
10147          emitcode (".db", "%05d$>>8", jtab->key + 100);
10148     }
10149 }
10150
10151 /*-----------------------------------------------------------------*/
10152 /* genCast - gen code for casting                                  */
10153 /*-----------------------------------------------------------------*/
10154 static void
10155 genCast (iCode * ic)
10156 {
10157   operand *result = IC_RESULT (ic);
10158   sym_link *ctype = operandType (IC_LEFT (ic));
10159   sym_link *rtype = operandType (IC_RIGHT (ic));
10160   operand *right = IC_RIGHT (ic);
10161   int size, offset;
10162
10163   D(emitcode(";     genCast",""));
10164
10165   /* if they are equivalent then do nothing */
10166   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10167     return;
10168
10169   aopOp (right, ic, FALSE);
10170   aopOp (result, ic, FALSE);
10171
10172   /* if the result is a bit (and not a bitfield) */
10173   // if (AOP_TYPE (result) == AOP_CRY)
10174   if (IS_BITVAR (OP_SYMBOL (result)->type)
10175       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10176     {
10177       /* if the right size is a literal then
10178          we know what the value is */
10179       if (AOP_TYPE (right) == AOP_LIT)
10180         {
10181           if (((int) operandLitValue (right)))
10182             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10183           else
10184             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10185
10186           goto release;
10187         }
10188
10189       /* the right is also a bit variable */
10190       if (AOP_TYPE (right) == AOP_CRY)
10191         {
10192           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10193           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10194           goto release;
10195         }
10196
10197       /* we need to or */
10198       toBoolean (right);
10199       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10200       goto release;
10201     }
10202
10203
10204   /* if they are the same size : or less */
10205   if (AOP_SIZE (result) <= AOP_SIZE (right))
10206     {
10207
10208       /* if they are in the same place */
10209       if (sameRegs (AOP (right), AOP (result)))
10210         goto release;
10211
10212       /* if they in different places then copy */
10213       size = AOP_SIZE (result);
10214       offset = 0;
10215       while (size--)
10216         {
10217           aopPut (result,
10218                   aopGet (right, offset, FALSE, FALSE),
10219                   offset,
10220                   isOperandVolatile (result, FALSE));
10221           offset++;
10222         }
10223       goto release;
10224     }
10225
10226
10227   /* if the result is of type pointer */
10228   if (IS_PTR (ctype))
10229     {
10230
10231       int p_type;
10232       sym_link *type = operandType (right);
10233       sym_link *etype = getSpec (type);
10234
10235       /* pointer to generic pointer */
10236       if (IS_GENPTR (ctype))
10237         {
10238           if (IS_PTR (type))
10239             p_type = DCL_TYPE (type);
10240           else
10241             {
10242               if (SPEC_SCLS(etype)==S_REGISTER) {
10243                 // let's assume it is a generic pointer
10244                 p_type=GPOINTER;
10245               } else {
10246                 /* we have to go by the storage class */
10247                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10248               }
10249             }
10250
10251           /* the first two bytes are known */
10252           size = GPTRSIZE - 1;
10253           offset = 0;
10254           while (size--)
10255             {
10256               aopPut (result,
10257                       aopGet (right, offset, FALSE, FALSE),
10258                       offset,
10259                       isOperandVolatile (result, FALSE));
10260               offset++;
10261             }
10262           /* the last byte depending on type */
10263             {
10264                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10265                 char gpValStr[10];
10266
10267                 if (gpVal == -1)
10268                 {
10269                     // pointerTypeToGPByte will have bitched.
10270                     exit(1);
10271                 }
10272
10273                 sprintf(gpValStr, "#0x%x", gpVal);
10274                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10275             }
10276           goto release;
10277         }
10278
10279       /* just copy the pointers */
10280       size = AOP_SIZE (result);
10281       offset = 0;
10282       while (size--)
10283         {
10284           aopPut (result,
10285                   aopGet (right, offset, FALSE, FALSE),
10286                   offset,
10287                   isOperandVolatile (result, FALSE));
10288           offset++;
10289         }
10290       goto release;
10291     }
10292
10293   /* so we now know that the size of destination is greater
10294      than the size of the source */
10295   /* we move to result for the size of source */
10296   size = AOP_SIZE (right);
10297   offset = 0;
10298   while (size--)
10299     {
10300       aopPut (result,
10301               aopGet (right, offset, FALSE, FALSE),
10302               offset,
10303               isOperandVolatile (result, FALSE));
10304       offset++;
10305     }
10306
10307   /* now depending on the sign of the source && destination */
10308   size = AOP_SIZE (result) - AOP_SIZE (right);
10309   /* if unsigned or not an integral type */
10310   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10311     {
10312       while (size--)
10313         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10314     }
10315   else
10316     {
10317       /* we need to extend the sign :{ */
10318       char *l = aopGet (right, AOP_SIZE (right) - 1,
10319                         FALSE, FALSE);
10320       MOVA (l);
10321       emitcode ("rlc", "a");
10322       emitcode ("subb", "a,acc");
10323       while (size--)
10324         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10325     }
10326
10327   /* we are done hurray !!!! */
10328
10329 release:
10330   freeAsmop (right, NULL, ic, TRUE);
10331   freeAsmop (result, NULL, ic, TRUE);
10332
10333 }
10334
10335 /*-----------------------------------------------------------------*/
10336 /* genDjnz - generate decrement & jump if not zero instrucion      */
10337 /*-----------------------------------------------------------------*/
10338 static int
10339 genDjnz (iCode * ic, iCode * ifx)
10340 {
10341   symbol *lbl, *lbl1;
10342   if (!ifx)
10343     return 0;
10344
10345   D(emitcode (";     genDjnz",""));
10346
10347   /* if the if condition has a false label
10348      then we cannot save */
10349   if (IC_FALSE (ifx))
10350     return 0;
10351
10352   /* if the minus is not of the form
10353      a = a - 1 */
10354   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10355       !IS_OP_LITERAL (IC_RIGHT (ic)))
10356     return 0;
10357
10358   if (operandLitValue (IC_RIGHT (ic)) != 1)
10359     return 0;
10360
10361   /* if the size of this greater than one then no
10362      saving */
10363   if (getSize (operandType (IC_RESULT (ic))) > 1)
10364     return 0;
10365
10366   /* otherwise we can save BIG */
10367   lbl = newiTempLabel (NULL);
10368   lbl1 = newiTempLabel (NULL);
10369
10370   aopOp (IC_RESULT (ic), ic, FALSE);
10371
10372   if (AOP_NEEDSACC(IC_RESULT(ic)))
10373   {
10374       /* If the result is accessed indirectly via
10375        * the accumulator, we must explicitly write
10376        * it back after the decrement.
10377        */
10378       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10379
10380       if (strcmp(rByte, "a"))
10381       {
10382            /* Something is hopelessly wrong */
10383            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10384                    __FILE__, __LINE__);
10385            /* We can just give up; the generated code will be inefficient,
10386             * but what the hey.
10387             */
10388            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10389            return 0;
10390       }
10391       emitcode ("dec", "%s", rByte);
10392       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10393       emitcode ("jnz", "%05d$", lbl->key + 100);
10394   }
10395   else if (IS_AOP_PREG (IC_RESULT (ic)))
10396     {
10397       emitcode ("dec", "%s",
10398                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10399       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10400       emitcode ("jnz", "%05d$", lbl->key + 100);
10401     }
10402   else
10403     {
10404       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10405                 lbl->key + 100);
10406     }
10407   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10408   emitcode ("", "%05d$:", lbl->key + 100);
10409   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10410   emitcode ("", "%05d$:", lbl1->key + 100);
10411
10412   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10413   ifx->generated = 1;
10414   return 1;
10415 }
10416
10417 /*-----------------------------------------------------------------*/
10418 /* genReceive - generate code for a receive iCode                  */
10419 /*-----------------------------------------------------------------*/
10420 static void
10421 genReceive (iCode * ic)
10422 {
10423     int size = getSize (operandType (IC_RESULT (ic)));
10424     int offset = 0;
10425   D(emitcode (";     genReceive",""));
10426
10427   if (ic->argreg == 1) { /* first parameter */
10428       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10429           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10430            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10431
10432           regs *tempRegs[4];
10433           int receivingA = 0;
10434           int roffset = 0;
10435
10436           for (offset = 0; offset<size; offset++)
10437             if (!strcmp (fReturn[offset], "a"))
10438               receivingA = 1;
10439
10440           if (!receivingA)
10441             {
10442               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10443                 {
10444                   for (offset = size-1; offset>0; offset--)
10445                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10446                   emitcode("mov","a,%s", fReturn[0]);
10447                   _G.accInUse++;
10448                   aopOp (IC_RESULT (ic), ic, FALSE);
10449                   _G.accInUse--;
10450                   aopPut (IC_RESULT (ic), "a", offset,
10451                           isOperandVolatile (IC_RESULT (ic), FALSE));
10452                   for (offset = 1; offset<size; offset++)
10453                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10454                             isOperandVolatile (IC_RESULT (ic), FALSE));
10455                   goto release;
10456                 }
10457             }
10458           else
10459             {
10460               if (getTempRegs(tempRegs, size, ic))
10461                 {
10462                   for (offset = 0; offset<size; offset++)
10463                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10464                   aopOp (IC_RESULT (ic), ic, FALSE);
10465                   for (offset = 0; offset<size; offset++)
10466                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10467                             isOperandVolatile (IC_RESULT (ic), FALSE));
10468                   goto release;
10469                 }
10470             }
10471
10472           offset = fReturnSizeMCS51 - size;
10473           while (size--) {
10474               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10475                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10476               offset++;
10477           }
10478           aopOp (IC_RESULT (ic), ic, FALSE);
10479           size = AOP_SIZE (IC_RESULT (ic));
10480           offset = 0;
10481           while (size--) {
10482               emitcode ("pop", "acc");
10483               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10484           }
10485
10486       } else {
10487           _G.accInUse++;
10488           aopOp (IC_RESULT (ic), ic, FALSE);
10489           _G.accInUse--;
10490           assignResultValue (IC_RESULT (ic));
10491       }
10492   } else { /* second receive onwards */
10493       int rb1off ;
10494       aopOp (IC_RESULT (ic), ic, FALSE);
10495       rb1off = ic->argreg;
10496       while (size--) {
10497           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10498       }
10499   }
10500
10501 release:
10502   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10503 }
10504
10505 /*-----------------------------------------------------------------*/
10506 /* genDummyRead - generate code for dummy read of volatiles        */
10507 /*-----------------------------------------------------------------*/
10508 static void
10509 genDummyRead (iCode * ic)
10510 {
10511   operand *op;
10512   int size, offset;
10513
10514   D(emitcode(";     genDummyRead",""));
10515
10516   op = IC_RIGHT (ic);
10517   if (op && IS_SYMOP (op))
10518     {
10519       aopOp (op, ic, FALSE);
10520
10521       /* if the result is a bit */
10522       if (AOP_TYPE (op) == AOP_CRY)
10523         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10524       else
10525         {
10526           /* bit variables done */
10527           /* general case */
10528           size = AOP_SIZE (op);
10529           offset = 0;
10530           while (size--)
10531           {
10532             MOVA (aopGet (op, offset, FALSE, FALSE));
10533             offset++;
10534           }
10535         }
10536
10537       freeAsmop (op, NULL, ic, TRUE);
10538     }
10539
10540   op = IC_LEFT (ic);
10541   if (op && IS_SYMOP (op))
10542     {
10543       aopOp (op, ic, FALSE);
10544
10545       /* if the result is a bit */
10546       if (AOP_TYPE (op) == AOP_CRY)
10547         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10548       else
10549         {
10550           /* bit variables done */
10551           /* general case */
10552           size = AOP_SIZE (op);
10553           offset = 0;
10554           while (size--)
10555           {
10556             MOVA (aopGet (op, offset, FALSE, FALSE));
10557             offset++;
10558           }
10559         }
10560
10561       freeAsmop (op, NULL, ic, TRUE);
10562     }
10563 }
10564
10565 /*-----------------------------------------------------------------*/
10566 /* genCritical - generate code for start of a critical sequence    */
10567 /*-----------------------------------------------------------------*/
10568 static void
10569 genCritical (iCode *ic)
10570 {
10571   symbol *tlbl = newiTempLabel (NULL);
10572
10573   D(emitcode(";     genCritical",""));
10574
10575   if (IC_RESULT (ic))
10576     {
10577       aopOp (IC_RESULT (ic), ic, TRUE);
10578       aopPut (IC_RESULT (ic), one, 0, 0);
10579       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10580       aopPut (IC_RESULT (ic), zero, 0, 0);
10581       emitcode ("", "%05d$:", (tlbl->key + 100));
10582       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10583     }
10584   else
10585     {
10586       emitcode ("setb", "c");
10587       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10588       emitcode ("clr", "c");
10589       emitcode ("", "%05d$:", (tlbl->key + 100));
10590       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10591     }
10592 }
10593
10594 /*-----------------------------------------------------------------*/
10595 /* genEndCritical - generate code for end of a critical sequence   */
10596 /*-----------------------------------------------------------------*/
10597 static void
10598 genEndCritical (iCode *ic)
10599 {
10600   D(emitcode(";     genEndCritical",""));
10601
10602   if (IC_RIGHT (ic))
10603     {
10604       aopOp (IC_RIGHT (ic), ic, FALSE);
10605       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10606         {
10607           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10608           emitcode ("mov", "ea,c");
10609         }
10610       else
10611         {
10612           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10613             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
10614           emitcode ("rrc", "a");
10615           emitcode ("mov", "ea,c");
10616         }
10617       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10618     }
10619   else
10620     {
10621       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10622       emitcode ("mov", "ea,c");
10623     }
10624 }
10625
10626 /*-----------------------------------------------------------------*/
10627 /* gen51Code - generate code for 8051 based controllers            */
10628 /*-----------------------------------------------------------------*/
10629 void
10630 gen51Code (iCode * lic)
10631 {
10632   iCode *ic;
10633   int cln = 0;
10634   /* int cseq = 0; */
10635
10636   _G.currentFunc = NULL;
10637   lineHead = lineCurr = NULL;
10638
10639   /* print the allocation information */
10640   if (allocInfo && currFunc)
10641     printAllocInfo (currFunc, codeOutFile);
10642   /* if debug information required */
10643   if (options.debug && currFunc)
10644     {
10645       debugFile->writeFunction (currFunc, lic);
10646     }
10647   /* stack pointer name */
10648   if (options.useXstack)
10649     spname = "_spx";
10650   else
10651     spname = "sp";
10652
10653
10654   for (ic = lic; ic; ic = ic->next)
10655     {
10656       _G.current_iCode = ic;
10657
10658       if (ic->lineno && cln != ic->lineno)
10659         {
10660           if (options.debug)
10661             {
10662               debugFile->writeCLine (ic);
10663             }
10664           if (!options.noCcodeInAsm) {
10665             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10666                       printCLine(ic->filename, ic->lineno));
10667           }
10668           cln = ic->lineno;
10669         }
10670       #if 0
10671       if (ic->seqPoint && ic->seqPoint != cseq)
10672         {
10673           emitcode ("", "; sequence point %d", ic->seqPoint);
10674           cseq = ic->seqPoint;
10675         }
10676       #endif
10677       if (options.iCodeInAsm) {
10678         char regsInUse[80];
10679         int i;
10680
10681         for (i=0; i<8; i++) {
10682           sprintf (&regsInUse[i],
10683                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10684         }
10685         regsInUse[i]=0;
10686         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10687       }
10688       /* if the result is marked as
10689          spilt and rematerializable or code for
10690          this has already been generated then
10691          do nothing */
10692       if (resultRemat (ic) || ic->generated)
10693         continue;
10694
10695       /* depending on the operation */
10696       switch (ic->op)
10697         {
10698         case '!':
10699           genNot (ic);
10700           break;
10701
10702         case '~':
10703           genCpl (ic);
10704           break;
10705
10706         case UNARYMINUS:
10707           genUminus (ic);
10708           break;
10709
10710         case IPUSH:
10711           genIpush (ic);
10712           break;
10713
10714         case IPOP:
10715           /* IPOP happens only when trying to restore a
10716              spilt live range, if there is an ifx statement
10717              following this pop then the if statement might
10718              be using some of the registers being popped which
10719              would destory the contents of the register so
10720              we need to check for this condition and handle it */
10721           if (ic->next &&
10722               ic->next->op == IFX &&
10723               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10724             genIfx (ic->next, ic);
10725           else
10726             genIpop (ic);
10727           break;
10728
10729         case CALL:
10730           genCall (ic);
10731           break;
10732
10733         case PCALL:
10734           genPcall (ic);
10735           break;
10736
10737         case FUNCTION:
10738           genFunction (ic);
10739           break;
10740
10741         case ENDFUNCTION:
10742           genEndFunction (ic);
10743           break;
10744
10745         case RETURN:
10746           genRet (ic);
10747           break;
10748
10749         case LABEL:
10750           genLabel (ic);
10751           break;
10752
10753         case GOTO:
10754           genGoto (ic);
10755           break;
10756
10757         case '+':
10758           genPlus (ic);
10759           break;
10760
10761         case '-':
10762           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10763             genMinus (ic);
10764           break;
10765
10766         case '*':
10767           genMult (ic);
10768           break;
10769
10770         case '/':
10771           genDiv (ic);
10772           break;
10773
10774         case '%':
10775           genMod (ic);
10776           break;
10777
10778         case '>':
10779           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10780           break;
10781
10782         case '<':
10783           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10784           break;
10785
10786         case LE_OP:
10787         case GE_OP:
10788         case NE_OP:
10789
10790           /* note these two are xlated by algebraic equivalence
10791              during parsing SDCC.y */
10792           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10793                   "got '>=' or '<=' shouldn't have come here");
10794           break;
10795
10796         case EQ_OP:
10797           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10798           break;
10799
10800         case AND_OP:
10801           genAndOp (ic);
10802           break;
10803
10804         case OR_OP:
10805           genOrOp (ic);
10806           break;
10807
10808         case '^':
10809           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10810           break;
10811
10812         case '|':
10813           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10814           break;
10815
10816         case BITWISEAND:
10817           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10818           break;
10819
10820         case INLINEASM:
10821           genInline (ic);
10822           break;
10823
10824         case RRC:
10825           genRRC (ic);
10826           break;
10827
10828         case RLC:
10829           genRLC (ic);
10830           break;
10831
10832         case GETHBIT:
10833           genGetHbit (ic);
10834           break;
10835
10836         case LEFT_OP:
10837           genLeftShift (ic);
10838           break;
10839
10840         case RIGHT_OP:
10841           genRightShift (ic);
10842           break;
10843
10844         case GET_VALUE_AT_ADDRESS:
10845           genPointerGet (ic,
10846                          hasInc (IC_LEFT (ic), ic,
10847                                  getSize (operandType (IC_RESULT (ic)))),
10848                          ifxForOp (IC_RESULT (ic), ic) );
10849           break;
10850
10851         case '=':
10852           if (POINTER_SET (ic))
10853             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10854           else
10855             genAssign (ic);
10856           break;
10857
10858         case IFX:
10859           genIfx (ic, NULL);
10860           break;
10861
10862         case ADDRESS_OF:
10863           genAddrOf (ic);
10864           break;
10865
10866         case JUMPTABLE:
10867           genJumpTab (ic);
10868           break;
10869
10870         case CAST:
10871           genCast (ic);
10872           break;
10873
10874         case RECEIVE:
10875           genReceive (ic);
10876           break;
10877
10878         case SEND:
10879           addSet (&_G.sendSet, ic);
10880           break;
10881
10882         case DUMMY_READ_VOLATILE:
10883           genDummyRead (ic);
10884           break;
10885
10886         case CRITICAL:
10887           genCritical (ic);
10888           break;
10889
10890         case ENDCRITICAL:
10891           genEndCritical (ic);
10892           break;
10893
10894         case SWAP:
10895           genSwap (ic);
10896           break;
10897
10898         default:
10899           ic = ic;
10900         }
10901     }
10902
10903   _G.current_iCode = NULL;
10904
10905   /* now we are ready to call the
10906      peep hole optimizer */
10907   if (!options.nopeep)
10908     peepHole (&lineHead);
10909
10910   /* now do the actual printing */
10911   printLine (lineHead, codeOutFile);
10912   return;
10913 }