* as/mcs51/lkarea.c (lnkarea, lnkarea2): improved BSEG size calculation,
[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     return TRUE;
734
735   /* if left is a tmp & right is not */
736   if (IS_ITEMP (op1) &&
737       !IS_ITEMP (op2) &&
738       sym1->isspilt &&
739       (sym1->usl.spillLoc == sym2))
740     return TRUE;
741
742   if (IS_ITEMP (op2) &&
743       !IS_ITEMP (op1) &&
744       sym2->isspilt &&
745       sym1->level > 0 &&
746       (sym2->usl.spillLoc == sym1))
747     return TRUE;
748
749   return FALSE;
750 }
751
752 /*-----------------------------------------------------------------*/
753 /* sameRegs - two asmops have the same registers                   */
754 /*-----------------------------------------------------------------*/
755 static bool
756 sameRegs (asmop * aop1, asmop * aop2)
757 {
758   int i;
759
760   if (aop1 == aop2)
761     return TRUE;
762
763   if (aop1->type != AOP_REG ||
764       aop2->type != AOP_REG)
765     return FALSE;
766
767   if (aop1->size != aop2->size)
768     return FALSE;
769
770   for (i = 0; i < aop1->size; i++)
771     if (aop1->aopu.aop_reg[i] !=
772         aop2->aopu.aop_reg[i])
773       return FALSE;
774
775   return TRUE;
776 }
777
778 /*-----------------------------------------------------------------*/
779 /* aopOp - allocates an asmop for an operand  :                    */
780 /*-----------------------------------------------------------------*/
781 static void
782 aopOp (operand * op, iCode * ic, bool result)
783 {
784   asmop *aop;
785   symbol *sym;
786   int i;
787
788   if (!op)
789     return;
790
791   /* if this a literal */
792   if (IS_OP_LITERAL (op))
793     {
794       op->aop = aop = newAsmop (AOP_LIT);
795       aop->aopu.aop_lit = op->operand.valOperand;
796       aop->size = getSize (operandType (op));
797       return;
798     }
799
800   /* if already has a asmop then continue */
801   if (op->aop )
802     return;
803
804   /* if the underlying symbol has a aop */
805   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
806     {
807       op->aop = OP_SYMBOL (op)->aop;
808       return;
809     }
810
811   /* if this is a true symbol */
812   if (IS_TRUE_SYMOP (op))
813     {
814       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
815       return;
816     }
817
818   /* this is a temporary : this has
819      only five choices :
820      a) register
821      b) spillocation
822      c) rematerialize
823      d) conditional
824      e) can be a return use only */
825
826   sym = OP_SYMBOL (op);
827
828   /* if the type is a conditional */
829   if (sym->regType == REG_CND)
830     {
831       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
832       aop->size = 0;
833       return;
834     }
835
836   /* if it is spilt then two situations
837      a) is rematerialize
838      b) has a spill location */
839   if (sym->isspilt || sym->nRegs == 0)
840     {
841
842       /* rematerialize it NOW */
843       if (sym->remat)
844         {
845           sym->aop = op->aop = aop =
846             aopForRemat (sym);
847           aop->size = getSize (sym->type);
848           return;
849         }
850
851       if (sym->accuse)
852         {
853           int i;
854           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
855           aop->size = getSize (sym->type);
856           for (i = 0; i < 2; i++)
857             aop->aopu.aop_str[i] = accUse[i];
858           return;
859         }
860
861       if (sym->ruonly)
862         {
863           unsigned i;
864
865           aop = op->aop = sym->aop = newAsmop (AOP_STR);
866           aop->size = getSize (sym->type);
867           for (i = 0; i < fReturnSizeMCS51; i++)
868             aop->aopu.aop_str[i] = fReturn[i];
869           return;
870         }
871
872       if (sym->usl.spillLoc)
873         {
874           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
875             {
876               /* force a new aop if sizes differ */
877               sym->usl.spillLoc->aop = NULL;
878             }
879           sym->aop = op->aop = aop =
880                      aopForSym (ic, sym->usl.spillLoc, result);
881           aop->size = getSize (sym->type);
882           return;
883         }
884
885       /* else must be a dummy iTemp */
886       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
887       aop->size = getSize (sym->type);
888       return;
889     }
890
891   /* must be in a register */
892   sym->aop = op->aop = aop = newAsmop (AOP_REG);
893   aop->size = sym->nRegs;
894   for (i = 0; i < sym->nRegs; i++)
895     aop->aopu.aop_reg[i] = sym->regs[i];
896 }
897
898 /*-----------------------------------------------------------------*/
899 /* freeAsmop - free up the asmop given to an operand               */
900 /*----------------------------------------------------------------*/
901 static void
902 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
903 {
904   asmop *aop;
905
906   if (!op)
907     aop = aaop;
908   else
909     aop = op->aop;
910
911   if (!aop)
912     return;
913
914   if (aop->freed)
915     goto dealloc;
916
917   aop->freed = 1;
918
919   /* depending on the asmop type only three cases need work AOP_RO
920      , AOP_R1 && AOP_STK */
921   switch (aop->type)
922     {
923     case AOP_R0:
924       if (R0INB)
925         {
926           emitcode ("mov", "r0,b");
927           R0INB--;
928         }
929       else if (_G.r0Pushed)
930         {
931           if (pop)
932             {
933               emitcode ("pop", "ar0");
934               _G.r0Pushed--;
935             }
936         }
937       bitVectUnSetBit (ic->rUsed, R0_IDX);
938       break;
939
940     case AOP_R1:
941       if (R1INB)
942         {
943           emitcode ("mov", "r1,b");
944           R1INB--;
945         }
946       if (_G.r1Pushed)
947         {
948           if (pop)
949             {
950               emitcode ("pop", "ar1");
951               _G.r1Pushed--;
952             }
953         }
954       bitVectUnSetBit (ic->rUsed, R1_IDX);
955       break;
956
957     case AOP_STK:
958       {
959         int sz = aop->size;
960         int stk = aop->aopu.aop_stk + aop->size - 1;
961         bitVectUnSetBit (ic->rUsed, R0_IDX);
962         bitVectUnSetBit (ic->rUsed, R1_IDX);
963
964         getFreePtr (ic, &aop, FALSE);
965
966         if (stk)
967           {
968             emitcode ("mov", "a,_bp");
969             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
970             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
971           }
972         else
973           {
974             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
975           }
976
977         while (sz--)
978           {
979             emitcode ("pop", "acc");
980             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
981             if (!sz)
982               break;
983             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
984           }
985         op->aop = aop;
986         freeAsmop (op, NULL, ic, TRUE);
987         if (_G.r1Pushed)
988           {
989             emitcode ("pop", "ar1");
990             _G.r1Pushed--;
991           }
992
993         if (_G.r0Pushed)
994           {
995             emitcode ("pop", "ar0");
996             _G.r0Pushed--;
997           }
998       }
999     }
1000
1001 dealloc:
1002   /* all other cases just dealloc */
1003   if (op)
1004     {
1005       op->aop = NULL;
1006       if (IS_SYMOP (op))
1007         {
1008           OP_SYMBOL (op)->aop = NULL;
1009           /* if the symbol has a spill */
1010           if (SPIL_LOC (op))
1011             SPIL_LOC (op)->aop = NULL;
1012         }
1013     }
1014 }
1015
1016 /*------------------------------------------------------------------*/
1017 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1018 /*                      pop r0 or r1 off stack if pushed            */
1019 /*------------------------------------------------------------------*/
1020 static void
1021 freeForBranchAsmop (operand * op)
1022 {
1023   asmop *aop;
1024
1025   if (!op)
1026     return;
1027
1028   aop = op->aop;
1029
1030   if (!aop)
1031     return;
1032
1033   if (aop->freed)
1034     return;
1035
1036   switch (aop->type)
1037     {
1038     case AOP_R0:
1039       if (R0INB)
1040         {
1041           emitcode ("mov", "r0,b");
1042         }
1043       else if (_G.r0Pushed)
1044         {
1045           emitcode ("pop", "ar0");
1046         }
1047       break;
1048
1049     case AOP_R1:
1050       if (R1INB)
1051         {
1052           emitcode ("mov", "r1,b");
1053         }
1054       else if (_G.r1Pushed)
1055         {
1056           emitcode ("pop", "ar1");
1057         }
1058       break;
1059
1060     case AOP_STK:
1061       {
1062         int sz = aop->size;
1063         int stk = aop->aopu.aop_stk + aop->size - 1;
1064
1065         emitcode ("mov", "b,r0");
1066         if (stk)
1067           {
1068             emitcode ("mov", "a,_bp");
1069             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1070             emitcode ("mov", "r0,a");
1071           }
1072         else
1073           {
1074             emitcode ("mov", "r0,_bp");
1075           }
1076
1077         while (sz--)
1078           {
1079             emitcode ("pop", "acc");
1080             emitcode ("mov", "@r0,a");
1081             if (!sz)
1082               break;
1083             emitcode ("dec", "r0");
1084           }
1085         emitcode ("mov", "r0,b");
1086       }
1087     }
1088
1089 }
1090
1091 /*-----------------------------------------------------------------*/
1092 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1093 /*                 clobber the accumulator                         */
1094 /*-----------------------------------------------------------------*/
1095 static bool
1096 aopGetUsesAcc (operand * oper, int offset)
1097 {
1098   asmop * aop = AOP (oper);
1099
1100   if (offset > (aop->size - 1))
1101     return FALSE;
1102
1103   switch (aop->type)
1104     {
1105
1106     case AOP_R0:
1107     case AOP_R1:
1108       if (aop->paged)
1109         return TRUE;
1110       return FALSE;
1111     case AOP_DPTR:
1112       return TRUE;
1113     case AOP_IMMD:
1114       return FALSE;
1115     case AOP_DIR:
1116       return FALSE;
1117     case AOP_REG:
1118       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1119       return FALSE;
1120     case AOP_CRY:
1121       return TRUE;
1122     case AOP_ACC:
1123       if (offset)
1124         return FALSE;
1125       return TRUE;
1126     case AOP_LIT:
1127       return FALSE;
1128     case AOP_STR:
1129       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1130         return TRUE;
1131       return FALSE;
1132     case AOP_DUMMY:
1133       return FALSE;
1134     default:
1135       /* Error case --- will have been caught already */
1136       wassert(0);
1137       return FALSE;
1138     }
1139 }
1140
1141 /*-----------------------------------------------------------------*/
1142 /* aopGet - for fetching value of the aop                          */
1143 /*-----------------------------------------------------------------*/
1144 static char *
1145 aopGet (operand * oper, int offset, bool bit16, bool dname)
1146 {
1147   char *s = buffer;
1148   char *rs;
1149   asmop * aop = AOP (oper);
1150
1151   /* offset is greater than
1152      size then zero */
1153   if (offset > (aop->size - 1) &&
1154       aop->type != AOP_LIT)
1155     return zero;
1156
1157   /* depending on type */
1158   switch (aop->type)
1159     {
1160     case AOP_DUMMY:
1161       return zero;
1162
1163     case AOP_R0:
1164     case AOP_R1:
1165       /* if we need to increment it */
1166       while (offset > aop->coff)
1167         {
1168           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1169           aop->coff++;
1170         }
1171
1172       while (offset < aop->coff)
1173         {
1174           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1175           aop->coff--;
1176         }
1177
1178       aop->coff = offset;
1179       if (aop->paged)
1180         {
1181           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1182           return (dname ? "acc" : "a");
1183         }
1184       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1185       rs = Safe_calloc (1, strlen (s) + 1);
1186       strcpy (rs, s);
1187       return rs;
1188
1189     case AOP_DPTR:
1190       if (aop->code && aop->coff==0 && offset>=1) {
1191         emitcode ("mov", "a,#0x%02x", offset);
1192         emitcode ("movc", "a,@a+dptr");
1193         return (dname ? "acc" : "a");
1194       }
1195
1196       while (offset > aop->coff)
1197         {
1198           emitcode ("inc", "dptr");
1199           aop->coff++;
1200         }
1201
1202       while (offset < aop->coff)
1203         {
1204           emitcode ("lcall", "__decdptr");
1205           aop->coff--;
1206         }
1207
1208       aop->coff = offset;
1209       if (aop->code)
1210         {
1211           emitcode ("clr", "a");
1212           emitcode ("movc", "a,@a+dptr");
1213         }
1214       else
1215         {
1216           emitcode ("movx", "a,@dptr");
1217         }
1218       return (dname ? "acc" : "a");
1219
1220
1221     case AOP_IMMD:
1222       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1223               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1224       } else if (bit16)
1225         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1226       else if (offset)
1227         sprintf (s, "#(%s >> %d)",
1228                  aop->aopu.aop_immd.aop_immd1,
1229                  offset * 8);
1230       else
1231         sprintf (s, "#%s",
1232                  aop->aopu.aop_immd.aop_immd1);
1233       rs = Safe_calloc (1, strlen (s) + 1);
1234       strcpy (rs, s);
1235       return rs;
1236
1237     case AOP_DIR:
1238       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1239         sprintf (s, "(%s >> %d)",
1240                  aop->aopu.aop_dir, offset * 8);
1241       else if (offset)
1242         sprintf (s, "(%s + %d)",
1243                  aop->aopu.aop_dir,
1244                  offset);
1245       else
1246         sprintf (s, "%s", aop->aopu.aop_dir);
1247       rs = Safe_calloc (1, strlen (s) + 1);
1248       strcpy (rs, s);
1249       return rs;
1250
1251     case AOP_REG:
1252       if (dname)
1253         return aop->aopu.aop_reg[offset]->dname;
1254       else
1255         return aop->aopu.aop_reg[offset]->name;
1256
1257     case AOP_CRY:
1258       emitcode ("clr", "a");
1259       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1260       emitcode ("rlc", "a");
1261       return (dname ? "acc" : "a");
1262
1263     case AOP_ACC:
1264       if (!offset && dname)
1265         return "acc";
1266       return aop->aopu.aop_str[offset];
1267
1268     case AOP_LIT:
1269       return aopLiteral (aop->aopu.aop_lit, offset);
1270
1271     case AOP_STR:
1272       aop->coff = offset;
1273       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1274           dname)
1275         return "acc";
1276
1277       return aop->aopu.aop_str[offset];
1278
1279     }
1280
1281   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1282           "aopget got unsupported aop->type");
1283   exit (1);
1284 }
1285 /*-----------------------------------------------------------------*/
1286 /* aopPut - puts a string for a aop and indicates if acc is in use */
1287 /*-----------------------------------------------------------------*/
1288 static bool
1289 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1290 {
1291   char *d = buffer;
1292   bool accuse = FALSE;
1293   asmop * aop = AOP (result);
1294
1295   if (aop->size && offset > (aop->size - 1))
1296     {
1297       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1298               "aopPut got offset > aop->size");
1299       exit (1);
1300     }
1301
1302   /* will assign value to value */
1303   /* depending on where it is ofcourse */
1304   switch (aop->type)
1305     {
1306     case AOP_DUMMY:
1307       MOVA (s);         /* read s in case it was volatile */
1308       accuse = TRUE;
1309       break;
1310
1311     case AOP_DIR:
1312       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1313         sprintf (d, "(%s >> %d)",
1314                  aop->aopu.aop_dir, offset * 8);
1315       else if (offset)
1316         sprintf (d, "(%s + %d)",
1317                  aop->aopu.aop_dir, offset);
1318       else
1319         sprintf (d, "%s", aop->aopu.aop_dir);
1320
1321       if (strcmp (d, s) ||
1322           bvolatile)
1323           emitcode ("mov", "%s,%s", d, s);
1324       if (!strcmp (d, "acc"))
1325           accuse = TRUE;
1326
1327       break;
1328
1329     case AOP_REG:
1330       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1331           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1332         {
1333           if (*s == '@' ||
1334               strcmp (s, "r0") == 0 ||
1335               strcmp (s, "r1") == 0 ||
1336               strcmp (s, "r2") == 0 ||
1337               strcmp (s, "r3") == 0 ||
1338               strcmp (s, "r4") == 0 ||
1339               strcmp (s, "r5") == 0 ||
1340               strcmp (s, "r6") == 0 ||
1341               strcmp (s, "r7") == 0)
1342             emitcode ("mov", "%s,%s",
1343                       aop->aopu.aop_reg[offset]->dname, s);
1344           else
1345             emitcode ("mov", "%s,%s",
1346                       aop->aopu.aop_reg[offset]->name, s);
1347         }
1348       break;
1349
1350     case AOP_DPTR:
1351       if (aop->code)
1352         {
1353           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1354                   "aopPut writing to code space");
1355           exit (1);
1356         }
1357
1358       while (offset > aop->coff)
1359         {
1360           aop->coff++;
1361           emitcode ("inc", "dptr");
1362         }
1363
1364       while (offset < aop->coff)
1365         {
1366           aop->coff--;
1367           emitcode ("lcall", "__decdptr");
1368         }
1369
1370       aop->coff = offset;
1371
1372       /* if not in accumulator */
1373       MOVA (s);
1374
1375       emitcode ("movx", "@dptr,a");
1376       break;
1377
1378     case AOP_R0:
1379     case AOP_R1:
1380       while (offset > aop->coff)
1381         {
1382           aop->coff++;
1383           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1384         }
1385       while (offset < aop->coff)
1386         {
1387           aop->coff--;
1388           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1389         }
1390       aop->coff = offset;
1391
1392       if (aop->paged)
1393         {
1394           MOVA (s);
1395           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1396
1397         }
1398       else if (*s == '@')
1399         {
1400           MOVA (s);
1401           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1402         }
1403       else if (strcmp (s, "r0") == 0 ||
1404                strcmp (s, "r1") == 0 ||
1405                strcmp (s, "r2") == 0 ||
1406                strcmp (s, "r3") == 0 ||
1407                strcmp (s, "r4") == 0 ||
1408                strcmp (s, "r5") == 0 ||
1409                strcmp (s, "r6") == 0 ||
1410                strcmp (s, "r7") == 0)
1411         {
1412           char buffer[10];
1413           sprintf (buffer, "a%s", s);
1414           emitcode ("mov", "@%s,%s",
1415                     aop->aopu.aop_ptr->name, buffer);
1416         }
1417       else
1418         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1419
1420       break;
1421
1422     case AOP_STK:
1423       if (strcmp (s, "a") == 0)
1424         emitcode ("push", "acc");
1425       else
1426         if (*s=='@') {
1427           MOVA(s);
1428           emitcode ("push", "acc");
1429         } else {
1430           emitcode ("push", s);
1431         }
1432
1433       break;
1434
1435     case AOP_CRY:
1436       /* if not bit variable */
1437       if (!aop->aopu.aop_dir)
1438         {
1439           /* inefficient: move carry into A and use jz/jnz */
1440           emitcode ("clr", "a");
1441           emitcode ("rlc", "a");
1442           accuse = TRUE;
1443         }
1444       else
1445         {
1446           if (s == zero)
1447             emitcode ("clr", "%s", aop->aopu.aop_dir);
1448           else if (s == one)
1449             emitcode ("setb", "%s", aop->aopu.aop_dir);
1450           else if (!strcmp (s, "c"))
1451             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1452           else
1453             {
1454               MOVA (s);
1455               /* set C, if a >= 1 */
1456               emitcode ("add", "a,#0xff");
1457               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1458             }
1459         }
1460       break;
1461
1462     case AOP_STR:
1463       aop->coff = offset;
1464       if (strcmp (aop->aopu.aop_str[offset], s) ||
1465           bvolatile)
1466         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1467       break;
1468
1469     case AOP_ACC:
1470       accuse = TRUE;
1471       aop->coff = offset;
1472       if (!offset && (strcmp (s, "acc") == 0) &&
1473           !bvolatile)
1474         break;
1475
1476       if (strcmp (aop->aopu.aop_str[offset], s) &&
1477           !bvolatile)
1478         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1479       break;
1480
1481     default:
1482       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1483               "aopPut got unsupported aop->type");
1484       exit (1);
1485     }
1486
1487     return accuse;
1488 }
1489
1490
1491 #if 0
1492 /*-----------------------------------------------------------------*/
1493 /* pointToEnd :- points to the last byte of the operand            */
1494 /*-----------------------------------------------------------------*/
1495 static void
1496 pointToEnd (asmop * aop)
1497 {
1498   int count;
1499   if (!aop)
1500     return;
1501
1502   aop->coff = count = (aop->size - 1);
1503   switch (aop->type)
1504     {
1505     case AOP_R0:
1506     case AOP_R1:
1507       while (count--)
1508         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1509       break;
1510     case AOP_DPTR:
1511       while (count--)
1512         emitcode ("inc", "dptr");
1513       break;
1514     }
1515
1516 }
1517 #endif
1518
1519 /*-----------------------------------------------------------------*/
1520 /* reAdjustPreg - points a register back to where it should        */
1521 /*-----------------------------------------------------------------*/
1522 static void
1523 reAdjustPreg (asmop * aop)
1524 {
1525   if ((aop->coff==0) || aop->size <= 1)
1526     return;
1527
1528   switch (aop->type)
1529     {
1530     case AOP_R0:
1531     case AOP_R1:
1532       while (aop->coff--)
1533         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1534       break;
1535     case AOP_DPTR:
1536       while (aop->coff--)
1537         {
1538           emitcode ("lcall", "__decdptr");
1539         }
1540       break;
1541     }
1542   aop->coff = 0;
1543 }
1544
1545 /*-----------------------------------------------------------------*/
1546 /* opIsGptr: returns non-zero if the passed operand is       */
1547 /* a generic pointer type.             */
1548 /*-----------------------------------------------------------------*/
1549 static int
1550 opIsGptr (operand * op)
1551 {
1552   sym_link *type = operandType (op);
1553
1554   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1555     {
1556       return 1;
1557     }
1558   return 0;
1559 }
1560
1561 /*-----------------------------------------------------------------*/
1562 /* getDataSize - get the operand data size                         */
1563 /*-----------------------------------------------------------------*/
1564 static int
1565 getDataSize (operand * op)
1566 {
1567   int size;
1568   size = AOP_SIZE (op);
1569   if (size == GPTRSIZE)
1570     {
1571       sym_link *type = operandType (op);
1572       if (IS_GENPTR (type))
1573         {
1574           /* generic pointer; arithmetic operations
1575            * should ignore the high byte (pointer type).
1576            */
1577           size--;
1578         }
1579     }
1580   return size;
1581 }
1582
1583 /*-----------------------------------------------------------------*/
1584 /* outAcc - output Acc                                             */
1585 /*-----------------------------------------------------------------*/
1586 static void
1587 outAcc (operand * result)
1588 {
1589   int size, offset;
1590   size = getDataSize (result);
1591   if (size)
1592     {
1593       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1594       size--;
1595       offset = 1;
1596       /* unsigned or positive */
1597       while (size--)
1598         {
1599           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1600         }
1601     }
1602 }
1603
1604 /*-----------------------------------------------------------------*/
1605 /* outBitC - output a bit C                                        */
1606 /*-----------------------------------------------------------------*/
1607 static void
1608 outBitC (operand * result)
1609 {
1610   /* if the result is bit */
1611   if (AOP_TYPE (result) == AOP_CRY)
1612     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1613   else
1614     {
1615       emitcode ("clr", "a");
1616       emitcode ("rlc", "a");
1617       outAcc (result);
1618     }
1619 }
1620
1621 /*-----------------------------------------------------------------*/
1622 /* toBoolean - emit code for orl a,operator(sizeop)                */
1623 /*-----------------------------------------------------------------*/
1624 static void
1625 toBoolean (operand * oper)
1626 {
1627   int size = AOP_SIZE (oper) - 1;
1628   int offset = 1;
1629   bool AccUsed = FALSE;
1630   bool pushedB;
1631
1632   while (!AccUsed && size--)
1633     {
1634       AccUsed |= aopGetUsesAcc(oper, offset++);
1635     }
1636
1637   size = AOP_SIZE (oper) - 1;
1638   offset = 1;
1639   MOVA (aopGet (oper, 0, FALSE, FALSE));
1640   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1641     {
1642       pushedB = pushB ();
1643       emitcode("mov", "b,a");
1644       while (--size)
1645         {
1646           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1647           emitcode ("orl", "b,a");
1648         }
1649       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1650       emitcode ("orl", "a,b");
1651       popB (pushedB);
1652     }
1653   else
1654     {
1655       while (size--)
1656         {
1657           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1658         }
1659     }
1660 }
1661
1662
1663 /*-----------------------------------------------------------------*/
1664 /* genNot - generate code for ! operation                          */
1665 /*-----------------------------------------------------------------*/
1666 static void
1667 genNot (iCode * ic)
1668 {
1669   symbol *tlbl;
1670
1671   D(emitcode (";     genNot",""));
1672
1673   /* assign asmOps to operand & result */
1674   aopOp (IC_LEFT (ic), ic, FALSE);
1675   aopOp (IC_RESULT (ic), ic, TRUE);
1676
1677   /* if in bit space then a special case */
1678   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1679     {
1680       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1681       emitcode ("cpl", "c");
1682       outBitC (IC_RESULT (ic));
1683       goto release;
1684     }
1685
1686   toBoolean (IC_LEFT (ic));
1687
1688   tlbl = newiTempLabel (NULL);
1689   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1690   emitcode ("", "%05d$:", tlbl->key + 100);
1691   outBitC (IC_RESULT (ic));
1692
1693 release:
1694   /* release the aops */
1695   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1696   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1697 }
1698
1699
1700 /*-----------------------------------------------------------------*/
1701 /* genCpl - generate code for complement                           */
1702 /*-----------------------------------------------------------------*/
1703 static void
1704 genCpl (iCode * ic)
1705 {
1706   int offset = 0;
1707   int size;
1708   symbol *tlbl;
1709   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1710
1711   D(emitcode (";", "genCpl"));
1712
1713   /* assign asmOps to operand & result */
1714   aopOp (IC_LEFT (ic), ic, FALSE);
1715   aopOp (IC_RESULT (ic), ic, TRUE);
1716
1717   /* special case if in bit space */
1718   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1719     {
1720       char *l;
1721
1722       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1723           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1724         {
1725           /* promotion rules are responsible for this strange result:
1726              bit -> int -> ~int -> bit
1727              uchar -> int -> ~int -> bit
1728           */
1729           werror(W_COMPLEMENT);
1730           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1731           goto release;
1732         }
1733
1734       tlbl=newiTempLabel(NULL);
1735       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1736       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1737           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1738           IS_AOP_PREG (IC_LEFT (ic)))
1739         {
1740           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1741         }
1742       else
1743         {
1744           MOVA (l);
1745           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1746         }
1747       emitcode ("", "%05d$:", tlbl->key + 100);
1748       outBitC (IC_RESULT(ic));
1749       goto release;
1750     }
1751
1752   size = AOP_SIZE (IC_RESULT (ic));
1753   while (size--)
1754     {
1755       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1756       MOVA (l);
1757       emitcode ("cpl", "a");
1758       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1759     }
1760
1761
1762 release:
1763   /* release the aops */
1764   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1765   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1766 }
1767
1768 /*-----------------------------------------------------------------*/
1769 /* genUminusFloat - unary minus for floating points                */
1770 /*-----------------------------------------------------------------*/
1771 static void
1772 genUminusFloat (operand * op, operand * result)
1773 {
1774   int size, offset = 0;
1775   char *l;
1776
1777   D(emitcode (";     genUminusFloat",""));
1778
1779   /* for this we just copy and then flip the bit */
1780
1781   size = AOP_SIZE (op) - 1;
1782
1783   while (size--)
1784     {
1785       aopPut (result,
1786               aopGet (op, offset, FALSE, FALSE),
1787               offset,
1788               isOperandVolatile (result, FALSE));
1789       offset++;
1790     }
1791
1792   l = aopGet (op, offset, FALSE, FALSE);
1793
1794   MOVA (l);
1795
1796   emitcode ("cpl", "acc.7");
1797   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1798 }
1799
1800 /*-----------------------------------------------------------------*/
1801 /* genUminus - unary minus code generation                         */
1802 /*-----------------------------------------------------------------*/
1803 static void
1804 genUminus (iCode * ic)
1805 {
1806   int offset, size;
1807   sym_link *optype, *rtype;
1808
1809
1810   D(emitcode (";     genUminus",""));
1811
1812   /* assign asmops */
1813   aopOp (IC_LEFT (ic), ic, FALSE);
1814   aopOp (IC_RESULT (ic), ic, TRUE);
1815
1816   /* if both in bit space then special
1817      case */
1818   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1819       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1820     {
1821
1822       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1823       emitcode ("cpl", "c");
1824       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1825       goto release;
1826     }
1827
1828   optype = operandType (IC_LEFT (ic));
1829   rtype = operandType (IC_RESULT (ic));
1830
1831   /* if float then do float stuff */
1832   if (IS_FLOAT (optype))
1833     {
1834       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1835       goto release;
1836     }
1837
1838   /* otherwise subtract from zero */
1839   size = AOP_SIZE (IC_LEFT (ic));
1840   offset = 0;
1841   //CLRC ;
1842   while (size--)
1843     {
1844       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1845       if (!strcmp (l, "a"))
1846         {
1847           if (offset == 0)
1848             SETC;
1849           emitcode ("cpl", "a");
1850           emitcode ("addc", "a,#0");
1851         }
1852       else
1853         {
1854           if (offset == 0)
1855             CLRC;
1856           emitcode ("clr", "a");
1857           emitcode ("subb", "a,%s", l);
1858         }
1859       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1860     }
1861
1862   /* if any remaining bytes in the result */
1863   /* we just need to propagate the sign   */
1864   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1865     {
1866       emitcode ("rlc", "a");
1867       emitcode ("subb", "a,acc");
1868       while (size--)
1869         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1870     }
1871
1872 release:
1873   /* release the aops */
1874   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1875   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1876 }
1877
1878 /*-----------------------------------------------------------------*/
1879 /* saveRegisters - will look for a call and save the registers     */
1880 /*-----------------------------------------------------------------*/
1881 static void
1882 saveRegisters (iCode * lic)
1883 {
1884   int i;
1885   iCode *ic;
1886   bitVect *rsave;
1887
1888   /* look for call */
1889   for (ic = lic; ic; ic = ic->next)
1890     if (ic->op == CALL || ic->op == PCALL)
1891       break;
1892
1893   if (!ic)
1894     {
1895       fprintf (stderr, "found parameter push with no function call\n");
1896       return;
1897     }
1898
1899   /* if the registers have been saved already or don't need to be then
1900      do nothing */
1901   if (ic->regsSaved)
1902     return;
1903   if (IS_SYMOP(IC_LEFT(ic)) &&
1904       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1905        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1906     return;
1907
1908   /* save the registers in use at this time but skip the
1909      ones for the result */
1910   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1911                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1912
1913   ic->regsSaved = 1;
1914   if (options.useXstack)
1915     {
1916       int count = bitVectnBitsOn (rsave);
1917
1918       if (count == 1)
1919         {
1920           i = bitVectFirstBit (rsave);
1921           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1922           emitcode ("mov", "r0,%s", spname);
1923           emitcode ("inc", "%s", spname);// allocate before use
1924           emitcode ("movx", "@r0,a");
1925           if (bitVectBitValue (rsave, R0_IDX))
1926             emitcode ("mov", "r0,a");
1927         }
1928       else if (count != 0)
1929         {
1930           if (bitVectBitValue (rsave, R0_IDX))
1931             {
1932               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1933             }
1934           emitcode ("mov", "r0,%s", spname);
1935           MOVA ("r0");
1936           emitcode ("add", "a,#%d", count);
1937           emitcode ("mov", "%s,a", spname);
1938           for (i = 0; i < mcs51_nRegs; i++)
1939             {
1940               if (bitVectBitValue (rsave, i))
1941                 {
1942                   if (i == R0_IDX)
1943                     {
1944                       emitcode ("pop", "acc");
1945                       emitcode ("push", "acc");
1946                     }
1947                   else
1948                     {
1949                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1950                     }
1951                   emitcode ("movx", "@r0,a");
1952                   if (--count)
1953                     {
1954                       emitcode ("inc", "r0");
1955                     }
1956                 }
1957             }
1958           if (bitVectBitValue (rsave, R0_IDX))
1959             {
1960               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1961             }
1962         }
1963     }
1964   else
1965     for (i = 0; i < mcs51_nRegs; i++)
1966       {
1967         if (bitVectBitValue (rsave, i))
1968           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1969       }
1970 }
1971
1972 /*-----------------------------------------------------------------*/
1973 /* unsaveRegisters - pop the pushed registers                      */
1974 /*-----------------------------------------------------------------*/
1975 static void
1976 unsaveRegisters (iCode * ic)
1977 {
1978   int i;
1979   bitVect *rsave;
1980
1981   /* restore the registers in use at this time but skip the
1982      ones for the result */
1983   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1984                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1985
1986   if (options.useXstack)
1987     {
1988       int count = bitVectnBitsOn (rsave);
1989
1990       if (count == 1)
1991         {
1992           emitcode ("mov", "r0,%s", spname);
1993           emitcode ("dec", "r0");
1994           emitcode ("movx", "a,@r0");
1995           i = bitVectFirstBit (rsave);
1996           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1997           emitcode ("dec", "%s", spname);
1998         }
1999       else if (count != 0)
2000         {
2001           emitcode ("mov", "r0,%s", spname);
2002           for (i = mcs51_nRegs; i >= 0; i--)
2003             {
2004               if (bitVectBitValue (rsave, i))
2005                 {
2006                   emitcode ("dec", "r0");
2007                   emitcode ("movx", "a,@r0");
2008                   if (i != R0_IDX)
2009                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
2010                   else
2011                     emitcode ("push", "acc");
2012                 }
2013             }
2014           emitcode ("mov", "%s,r0", spname);
2015           if (bitVectBitValue (rsave, R0_IDX))
2016             {
2017               emitcode ("pop", "ar0");
2018             }
2019         }
2020     }
2021   else
2022     for (i = mcs51_nRegs; i >= 0; i--)
2023       {
2024         if (bitVectBitValue (rsave, i))
2025           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2026       }
2027 }
2028
2029
2030 /*-----------------------------------------------------------------*/
2031 /* pushSide -                */
2032 /*-----------------------------------------------------------------*/
2033 static void
2034 pushSide (operand * oper, int size)
2035 {
2036   int offset = 0;
2037   while (size--)
2038     {
2039       char *l = aopGet (oper, offset++, FALSE, TRUE);
2040       if (AOP_TYPE (oper) != AOP_REG &&
2041           AOP_TYPE (oper) != AOP_DIR &&
2042           strcmp (l, "a"))
2043         {
2044           MOVA (l);
2045           emitcode ("push", "acc");
2046         }
2047       else
2048         {
2049           emitcode ("push", "%s", l);
2050         }
2051     }
2052 }
2053
2054 /*-----------------------------------------------------------------*/
2055 /* assignResultValue - also indicates if acc is in use afterwards  */
2056 /*-----------------------------------------------------------------*/
2057 static bool
2058 assignResultValue (operand * oper)
2059 {
2060   int offset = 0;
2061   int size = AOP_SIZE (oper);
2062   bool accuse = FALSE;
2063
2064   while (size--)
2065     {
2066       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2067       offset++;
2068     }
2069   return accuse;
2070 }
2071
2072
2073 /*-----------------------------------------------------------------*/
2074 /* genXpush - pushes onto the external stack                       */
2075 /*-----------------------------------------------------------------*/
2076 static void
2077 genXpush (iCode * ic)
2078 {
2079   asmop *aop = newAsmop (0);
2080   regs *r;
2081   int size, offset = 0;
2082
2083   D(emitcode (";     genXpush",""));
2084
2085   aopOp (IC_LEFT (ic), ic, FALSE);
2086   r = getFreePtr (ic, &aop, FALSE);
2087
2088   size = AOP_SIZE (IC_LEFT (ic));
2089
2090   if (size == 1)
2091     {
2092       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2093       emitcode ("mov", "%s,%s", r->name, spname);
2094       emitcode ("inc", "%s", spname); // allocate space first
2095       emitcode ("movx", "@%s,a", r->name);
2096     }
2097   else
2098     {
2099       // allocate space first
2100       emitcode ("mov", "%s,%s", r->name, spname);
2101       MOVA (r->name);
2102       emitcode ("add", "a,#%d", size);
2103       emitcode ("mov", "%s,a", spname);
2104
2105       while (size--)
2106         {
2107           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2108           emitcode ("movx", "@%s,a", r->name);
2109           emitcode ("inc", "%s", r->name);
2110         }
2111     }
2112
2113   freeAsmop (NULL, aop, ic, TRUE);
2114   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2115 }
2116
2117 /*-----------------------------------------------------------------*/
2118 /* genIpush - generate code for pushing this gets a little complex */
2119 /*-----------------------------------------------------------------*/
2120 static void
2121 genIpush (iCode * ic)
2122 {
2123   int size, offset = 0;
2124   char *l;
2125
2126   D(emitcode (";     genIpush",""));
2127
2128   /* if this is not a parm push : ie. it is spill push
2129      and spill push is always done on the local stack */
2130   if (!ic->parmPush)
2131     {
2132
2133       /* and the item is spilt then do nothing */
2134       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2135         return;
2136
2137       aopOp (IC_LEFT (ic), ic, FALSE);
2138       size = AOP_SIZE (IC_LEFT (ic));
2139       /* push it on the stack */
2140       while (size--)
2141         {
2142           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2143           if (*l == '#')
2144             {
2145               MOVA (l);
2146               l = "acc";
2147             }
2148           emitcode ("push", "%s", l);
2149         }
2150       return;
2151     }
2152
2153   /* this is a paramter push: in this case we call
2154      the routine to find the call and save those
2155      registers that need to be saved */
2156   saveRegisters (ic);
2157
2158   /* if use external stack then call the external
2159      stack pushing routine */
2160   if (options.useXstack)
2161     {
2162       genXpush (ic);
2163       return;
2164     }
2165
2166   /* then do the push */
2167   aopOp (IC_LEFT (ic), ic, FALSE);
2168
2169   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2170   size = AOP_SIZE (IC_LEFT (ic));
2171
2172   while (size--)
2173     {
2174       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2175       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2176           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2177           strcmp (l, "a"))
2178         {
2179           MOVA (l);
2180           emitcode ("push", "acc");
2181         }
2182       else
2183           emitcode ("push", "%s", l);
2184     }
2185
2186   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2187 }
2188
2189 /*-----------------------------------------------------------------*/
2190 /* genIpop - recover the registers: can happen only for spilling   */
2191 /*-----------------------------------------------------------------*/
2192 static void
2193 genIpop (iCode * ic)
2194 {
2195   int size, offset;
2196
2197   D(emitcode (";     genIpop",""));
2198
2199   /* if the temp was not pushed then */
2200   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2201     return;
2202
2203   aopOp (IC_LEFT (ic), ic, FALSE);
2204   size = AOP_SIZE (IC_LEFT (ic));
2205   offset = (size - 1);
2206   while (size--)
2207     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2208                                    FALSE, TRUE));
2209
2210   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2211 }
2212
2213 /*-----------------------------------------------------------------*/
2214 /* saveRBank - saves an entire register bank on the stack          */
2215 /*-----------------------------------------------------------------*/
2216 static void
2217 saveRBank (int bank, iCode * ic, bool pushPsw)
2218 {
2219   int i;
2220   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2221   asmop *aop = NULL;
2222   regs *r = NULL;
2223
2224   if (options.useXstack)
2225     {
2226       if (!ic)
2227       {
2228           /* Assume r0 is available for use. */
2229           r = mcs51_regWithIdx (R0_IDX);;
2230       }
2231       else
2232       {
2233           aop = newAsmop (0);
2234           r = getFreePtr (ic, &aop, FALSE);
2235       }
2236       // allocate space first
2237       emitcode ("mov", "%s,%s", r->name, spname);
2238       MOVA (r->name);
2239       emitcode ("add", "a,#%d", count);
2240       emitcode ("mov", "%s,a", spname);
2241     }
2242
2243   for (i = 0; i < mcs51_nRegs; i++)
2244     {
2245       if (options.useXstack)
2246         {
2247           emitcode ("mov", "a,(%s+%d)",
2248                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2249           emitcode ("movx", "@%s,a", r->name);
2250           if (--count)
2251             emitcode ("inc", "%s", r->name);
2252         }
2253       else
2254         emitcode ("push", "(%s+%d)",
2255                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2256     }
2257
2258   if (pushPsw)
2259     {
2260       if (options.useXstack)
2261         {
2262           emitcode ("mov", "a,psw");
2263           emitcode ("movx", "@%s,a", r->name);
2264
2265         }
2266       else
2267         {
2268           emitcode ("push", "psw");
2269         }
2270
2271       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2272     }
2273
2274   if (aop)
2275     {
2276       freeAsmop (NULL, aop, ic, TRUE);
2277     }
2278
2279   if (ic)
2280   {
2281     ic->bankSaved = 1;
2282   }
2283 }
2284
2285 /*-----------------------------------------------------------------*/
2286 /* unsaveRBank - restores the register bank from stack             */
2287 /*-----------------------------------------------------------------*/
2288 static void
2289 unsaveRBank (int bank, iCode * ic, bool popPsw)
2290 {
2291   int i;
2292   asmop *aop = NULL;
2293   regs *r = NULL;
2294
2295   if (options.useXstack)
2296     {
2297       if (!ic)
2298         {
2299           /* Assume r0 is available for use. */
2300           r = mcs51_regWithIdx (R0_IDX);;
2301         }
2302       else
2303         {
2304           aop = newAsmop (0);
2305           r = getFreePtr (ic, &aop, FALSE);
2306         }
2307       emitcode ("mov", "%s,%s", r->name, spname);
2308     }
2309
2310   if (popPsw)
2311     {
2312       if (options.useXstack)
2313         {
2314           emitcode ("dec", "%s", r->name);
2315           emitcode ("movx", "a,@%s", r->name);
2316           emitcode ("mov", "psw,a");
2317         }
2318       else
2319         {
2320           emitcode ("pop", "psw");
2321         }
2322     }
2323
2324   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2325     {
2326       if (options.useXstack)
2327         {
2328           emitcode ("dec", "%s", r->name);
2329           emitcode ("movx", "a,@%s", r->name);
2330           emitcode ("mov", "(%s+%d),a",
2331                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2332         }
2333       else
2334         {
2335           emitcode ("pop", "(%s+%d)",
2336                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2337         }
2338     }
2339
2340   if (options.useXstack)
2341     {
2342       emitcode ("mov", "%s,%s", spname, r->name);
2343     }
2344
2345   if (aop)
2346     {
2347       freeAsmop (NULL, aop, ic, TRUE);
2348     }
2349 }
2350
2351 /*-----------------------------------------------------------------*/
2352 /* genSend - gen code for SEND                                     */
2353 /*-----------------------------------------------------------------*/
2354 static void genSend(set *sendSet)
2355 {
2356     iCode *sic;
2357     int rb1_count = 0 ;
2358
2359     for (sic = setFirstItem (sendSet); sic;
2360          sic = setNextItem (sendSet)) {
2361           int size, offset = 0;
2362           aopOp (IC_LEFT (sic), sic, FALSE);
2363           size = AOP_SIZE (IC_LEFT (sic));
2364
2365           if (sic->argreg == 1) {
2366               while (size--) {
2367                   char *l = aopGet (IC_LEFT (sic), offset,
2368                                     FALSE, FALSE);
2369                   if (strcmp (l, fReturn[offset]))
2370                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2371                   offset++;
2372               }
2373               rb1_count = 0;
2374           } else {
2375               while (size--) {
2376                   emitcode ("mov","b1_%d,%s",rb1_count++,
2377                             aopGet (IC_LEFT (sic), offset++,FALSE, FALSE));
2378               }
2379           }
2380           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2381     }
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* genCall - generates a call statement                            */
2386 /*-----------------------------------------------------------------*/
2387 static void
2388 genCall (iCode * ic)
2389 {
2390   sym_link *dtype;
2391 //  bool restoreBank = FALSE;
2392   bool swapBanks = FALSE;
2393   bool accuse = FALSE;
2394   bool accPushed = FALSE;
2395
2396   D(emitcode(";     genCall",""));
2397
2398   dtype = operandType (IC_LEFT (ic));
2399   /* if send set is not empty then assign */
2400   if (_G.sendSet)
2401     {
2402         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2403             genSend(reverseSet(_G.sendSet));
2404         } else {
2405             genSend(_G.sendSet);
2406         }
2407
2408       _G.sendSet = NULL;
2409     }
2410
2411   /* if we are calling a not _naked function that is not using
2412      the same register bank then we need to save the
2413      destination registers on the stack */
2414   dtype = operandType (IC_LEFT (ic));
2415   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2416       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2417        !IFFUNC_ISISR (dtype))
2418   {
2419       swapBanks = TRUE;
2420   }
2421
2422   /* if caller saves & we have not saved then */
2423   if (!ic->regsSaved)
2424       saveRegisters (ic);
2425
2426   if (swapBanks)
2427   {
2428         emitcode ("mov", "psw,#0x%02x",
2429            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2430   }
2431
2432   /* make the call */
2433   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2434     {
2435       if (IFFUNC_CALLEESAVES(dtype))
2436         {
2437           werror (E_BANKED_WITH_CALLEESAVES);
2438         }
2439       else
2440         {
2441           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2442                      OP_SYMBOL (IC_LEFT (ic))->rname :
2443                      OP_SYMBOL (IC_LEFT (ic))->name);
2444
2445           emitcode ("mov", "r0,#%s", l);
2446           emitcode ("mov", "r1,#(%s >> 8)", l);
2447           emitcode ("mov", "r2,#(%s >> 16)", l);
2448           emitcode ("lcall", "__sdcc_banked_call");
2449         }
2450     }
2451   else
2452     {
2453       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2454                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2455                                 OP_SYMBOL (IC_LEFT (ic))->name));
2456     }
2457
2458   if (swapBanks)
2459   {
2460        emitcode ("mov", "psw,#0x%02x",
2461           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2462   }
2463
2464   /* if we need assign a result value */
2465   if ((IS_ITEMP (IC_RESULT (ic)) &&
2466        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2467         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2468         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2469       IS_TRUE_SYMOP (IC_RESULT (ic)))
2470     {
2471
2472       _G.accInUse++;
2473       aopOp (IC_RESULT (ic), ic, FALSE);
2474       _G.accInUse--;
2475
2476       accuse = assignResultValue (IC_RESULT (ic));
2477
2478       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2479     }
2480
2481   /* adjust the stack for parameters if required */
2482   if (ic->parmBytes)
2483     {
2484       int i;
2485       if (ic->parmBytes > 3)
2486         {
2487           if (accuse)
2488             {
2489               emitcode ("push", "acc");
2490               accPushed = TRUE;
2491             }
2492
2493           emitcode ("mov", "a,%s", spname);
2494           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2495           emitcode ("mov", "%s,a", spname);
2496
2497           /* unsaveRegisters from xstack needs acc, but */
2498           /* unsaveRegisters from stack needs this popped */
2499           if (accPushed && !options.useXstack)
2500             {
2501               emitcode ("pop", "acc");
2502               accPushed = FALSE;
2503             }
2504         }
2505       else
2506         for (i = 0; i < ic->parmBytes; i++)
2507           emitcode ("dec", "%s", spname);
2508     }
2509
2510   /* if we hade saved some registers then unsave them */
2511   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2512     {
2513       if (accuse && !accPushed && options.useXstack)
2514         {
2515           /* xstack needs acc, but doesn't touch normal stack */
2516           emitcode ("push", "acc");
2517           accPushed = TRUE;
2518         }
2519       unsaveRegisters (ic);
2520     }
2521
2522 //  /* if register bank was saved then pop them */
2523 //  if (restoreBank)
2524 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2525
2526   if (accPushed)
2527     emitcode ("pop", "acc");
2528 }
2529
2530 /*-----------------------------------------------------------------*/
2531 /* -10l - generates a call by pointer statement                */
2532 /*-----------------------------------------------------------------*/
2533 static void
2534 genPcall (iCode * ic)
2535 {
2536   sym_link *dtype;
2537   sym_link *etype;
2538   symbol *rlbl = newiTempLabel (NULL);
2539 //  bool restoreBank=FALSE;
2540   bool swapBanks = FALSE;
2541
2542   D(emitcode(";     genPCall",""));
2543
2544   /* if caller saves & we have not saved then */
2545   if (!ic->regsSaved)
2546     saveRegisters (ic);
2547
2548   /* if we are calling a not _naked function that is not using
2549      the same register bank then we need to save the
2550      destination registers on the stack */
2551   dtype = operandType (IC_LEFT (ic))->next;
2552   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2553       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2554       !IFFUNC_ISISR (dtype))
2555   {
2556 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2557 //    restoreBank=TRUE;
2558       swapBanks = TRUE;
2559       // need caution message to user here
2560   }
2561
2562   etype = getSpec(dtype);
2563   if (IS_LITERAL(etype))
2564     {
2565       /* if send set is not empty then assign */
2566       if (_G.sendSet)
2567         {
2568           genSend(reverseSet(_G.sendSet));
2569           _G.sendSet = NULL;
2570         }
2571
2572       if (swapBanks)
2573         {
2574           emitcode ("mov", "psw,#0x%02x",
2575            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2576         }
2577
2578       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2579         {
2580           if (IFFUNC_CALLEESAVES(dtype))
2581             {
2582               werror (E_BANKED_WITH_CALLEESAVES);
2583             }
2584           else
2585             {
2586               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2587
2588               emitcode ("mov", "r0,#%s", l);
2589               emitcode ("mov", "r1,#(%s >> 8)", l);
2590               emitcode ("mov", "r2,#(%s >> 16)", l);
2591               emitcode ("lcall", "__sdcc_banked_call");
2592             }
2593         }
2594       else
2595         {
2596           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2597         }
2598     }
2599   else
2600     {
2601       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2602         {
2603           if (IFFUNC_CALLEESAVES(dtype))
2604             {
2605               werror (E_BANKED_WITH_CALLEESAVES);
2606             }
2607           else
2608             {
2609               aopOp (IC_LEFT (ic), ic, FALSE);
2610
2611               if (!swapBanks)
2612                 {
2613                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2614                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2615                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2616                 }
2617               else
2618                 {
2619                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2620                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2621                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2622                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2623                 }
2624
2625               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2626
2627               /* if send set is not empty then assign */
2628               if (_G.sendSet)
2629                 {
2630                   genSend(reverseSet(_G.sendSet));
2631                   _G.sendSet = NULL;
2632                 }
2633
2634               if (swapBanks)
2635                 {
2636                   emitcode ("mov", "psw,#0x%02x",
2637                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2638                 }
2639
2640               /* make the call */
2641               emitcode ("lcall", "__sdcc_banked_call");
2642             }
2643         }
2644       else
2645         {
2646           /* push the return address on to the stack */
2647           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2648           emitcode ("push", "acc");
2649           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2650           emitcode ("push", "acc");
2651
2652           /* now push the calling address */
2653           aopOp (IC_LEFT (ic), ic, FALSE);
2654
2655           pushSide (IC_LEFT (ic), FPTRSIZE);
2656
2657           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2658
2659           /* if send set is not empty the assign */
2660           if (_G.sendSet)
2661             {
2662               genSend(reverseSet(_G.sendSet));
2663               _G.sendSet = NULL;
2664             }
2665
2666           if (swapBanks)
2667             {
2668               emitcode ("mov", "psw,#0x%02x",
2669                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2670             }
2671
2672           /* make the call */
2673           emitcode ("ret", "");
2674           emitcode ("", "%05d$:", (rlbl->key + 100));
2675         }
2676     }
2677   if (swapBanks)
2678   {
2679        emitcode ("mov", "psw,#0x%02x",
2680           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2681   }
2682
2683   /* if we need assign a result value */
2684   if ((IS_ITEMP (IC_RESULT (ic)) &&
2685        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2686         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2687       IS_TRUE_SYMOP (IC_RESULT (ic)))
2688     {
2689
2690       _G.accInUse++;
2691       aopOp (IC_RESULT (ic), ic, FALSE);
2692       _G.accInUse--;
2693
2694       assignResultValue (IC_RESULT (ic));
2695
2696       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2697     }
2698
2699   /* adjust the stack for parameters if
2700      required */
2701   if (ic->parmBytes)
2702     {
2703       int i;
2704       if (ic->parmBytes > 3)
2705         {
2706           emitcode ("mov", "a,%s", spname);
2707           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2708           emitcode ("mov", "%s,a", spname);
2709         }
2710       else
2711         for (i = 0; i < ic->parmBytes; i++)
2712           emitcode ("dec", "%s", spname);
2713
2714     }
2715
2716 //  /* if register bank was saved then unsave them */
2717 //  if (restoreBank)
2718 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2719
2720   /* if we hade saved some registers then
2721      unsave them */
2722   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2723     unsaveRegisters (ic);
2724 }
2725
2726 /*-----------------------------------------------------------------*/
2727 /* resultRemat - result  is rematerializable                       */
2728 /*-----------------------------------------------------------------*/
2729 static int
2730 resultRemat (iCode * ic)
2731 {
2732   if (SKIP_IC (ic) || ic->op == IFX)
2733     return 0;
2734
2735   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2736     {
2737       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2738       if (sym->remat && !POINTER_SET (ic))
2739         return 1;
2740     }
2741
2742   return 0;
2743 }
2744
2745 #if defined(__BORLANDC__) || defined(_MSC_VER)
2746 #define STRCASECMP stricmp
2747 #else
2748 #define STRCASECMP strcasecmp
2749 #endif
2750
2751 /*-----------------------------------------------------------------*/
2752 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2753 /*-----------------------------------------------------------------*/
2754 static int
2755 regsCmp(void *p1, void *p2)
2756 {
2757   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2758 }
2759
2760 static bool
2761 inExcludeList (char *s)
2762 {
2763   const char *p = setFirstItem(options.excludeRegsSet);
2764
2765   if (p == NULL || STRCASECMP(p, "none") == 0)
2766     return FALSE;
2767
2768
2769   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2770 }
2771
2772 /*-----------------------------------------------------------------*/
2773 /* genFunction - generated code for function entry                 */
2774 /*-----------------------------------------------------------------*/
2775 static void
2776 genFunction (iCode * ic)
2777 {
2778   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2779   sym_link *ftype;
2780   bool     switchedPSW = FALSE;
2781   int      calleesaves_saved_register = -1;
2782   int      stackAdjust = sym->stack;
2783   int      accIsFree = sym->recvSize < 4;
2784   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2785   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2786
2787   _G.nRegsSaved = 0;
2788   /* create the function header */
2789   emitcode (";", "-----------------------------------------");
2790   emitcode (";", " function %s", sym->name);
2791   emitcode (";", "-----------------------------------------");
2792
2793   emitcode ("", "%s:", sym->rname);
2794   ftype = operandType (IC_LEFT (ic));
2795   _G.currentFunc = sym;
2796
2797   if (IFFUNC_ISNAKED(ftype))
2798   {
2799       emitcode(";", "naked function: no prologue.");
2800       return;
2801   }
2802
2803   /* here we need to generate the equates for the
2804      register bank if required */
2805   if (FUNC_REGBANK (ftype) != rbank)
2806     {
2807       int i;
2808
2809       rbank = FUNC_REGBANK (ftype);
2810       for (i = 0; i < mcs51_nRegs; i++)
2811         {
2812           if (strcmp (regs8051[i].base, "0") == 0)
2813             emitcode ("", "%s = 0x%02x",
2814                       regs8051[i].dname,
2815                       8 * rbank + regs8051[i].offset);
2816           else
2817             emitcode ("", "%s = %s + 0x%02x",
2818                       regs8051[i].dname,
2819                       regs8051[i].base,
2820                       8 * rbank + regs8051[i].offset);
2821         }
2822     }
2823
2824   /* if this is an interrupt service routine then
2825      save acc, b, dpl, dph  */
2826   if (IFFUNC_ISISR (sym->type))
2827     {
2828
2829       if (!inExcludeList ("acc"))
2830         emitcode ("push", "acc");
2831       if (!inExcludeList ("b"))
2832         emitcode ("push", "b");
2833       if (!inExcludeList ("dpl"))
2834         emitcode ("push", "dpl");
2835       if (!inExcludeList ("dph"))
2836         emitcode ("push", "dph");
2837       /* if this isr has no bank i.e. is going to
2838          run with bank 0 , then we need to save more
2839          registers :-) */
2840       if (!FUNC_REGBANK (sym->type))
2841         {
2842
2843           /* if this function does not call any other
2844              function then we can be economical and
2845              save only those registers that are used */
2846           if (!IFFUNC_HASFCALL(sym->type))
2847             {
2848               int i;
2849
2850               /* if any registers used */
2851               if (sym->regsUsed)
2852                 {
2853                   /* save the registers used */
2854                   for (i = 0; i < sym->regsUsed->size; i++)
2855                     {
2856                       if (bitVectBitValue (sym->regsUsed, i))
2857                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2858                     }
2859                 }
2860             }
2861           else
2862             {
2863
2864               /* this function has a function call. We cannot
2865                  determines register usage so we will have to push the
2866                  entire bank */
2867                 saveRBank (0, ic, FALSE);
2868                 if (options.parms_in_bank1) {
2869                     int i;
2870                     for (i=0; i < 8 ; i++ ) {
2871                         emitcode ("push","%s",rb1regs[i]);
2872                     }
2873                 }
2874             }
2875         }
2876         else
2877         {
2878             /* This ISR uses a non-zero bank.
2879              *
2880              * We assume that the bank is available for our
2881              * exclusive use.
2882              *
2883              * However, if this ISR calls a function which uses some
2884              * other bank, we must save that bank entirely.
2885              */
2886             unsigned long banksToSave = 0;
2887
2888             if (IFFUNC_HASFCALL(sym->type))
2889             {
2890
2891 #define MAX_REGISTER_BANKS 4
2892
2893                 iCode *i;
2894                 int ix;
2895
2896                 for (i = ic; i; i = i->next)
2897                 {
2898                     if (i->op == ENDFUNCTION)
2899                     {
2900                         /* we got to the end OK. */
2901                         break;
2902                     }
2903
2904                     if (i->op == CALL)
2905                     {
2906                         sym_link *dtype;
2907
2908                         dtype = operandType (IC_LEFT(i));
2909                         if (dtype
2910                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2911                         {
2912                              /* Mark this bank for saving. */
2913                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2914                              {
2915                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2916                              }
2917                              else
2918                              {
2919                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2920                              }
2921
2922                              /* And note that we don't need to do it in
2923                               * genCall.
2924                               */
2925                              i->bankSaved = 1;
2926                         }
2927                     }
2928                     if (i->op == PCALL)
2929                     {
2930                         /* This is a mess; we have no idea what
2931                          * register bank the called function might
2932                          * use.
2933                          *
2934                          * The only thing I can think of to do is
2935                          * throw a warning and hope.
2936                          */
2937                         werror(W_FUNCPTR_IN_USING_ISR);
2938                     }
2939                 }
2940
2941                 if (banksToSave && options.useXstack)
2942                 {
2943                     /* Since we aren't passing it an ic,
2944                      * saveRBank will assume r0 is available to abuse.
2945                      *
2946                      * So switch to our (trashable) bank now, so
2947                      * the caller's R0 isn't trashed.
2948                      */
2949                     emitcode ("push", "psw");
2950                     emitcode ("mov", "psw,#0x%02x",
2951                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2952                     switchedPSW = TRUE;
2953                 }
2954
2955                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2956                 {
2957                      if (banksToSave & (1 << ix))
2958                      {
2959                          saveRBank(ix, NULL, FALSE);
2960                      }
2961                 }
2962             }
2963             // TODO: this needs a closer look
2964             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2965         }
2966
2967       /* Set the register bank to the desired value if nothing else */
2968       /* has done so yet. */
2969       if (!switchedPSW)
2970         {
2971           emitcode ("push", "psw");
2972           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2973         }
2974     }
2975   else
2976     {
2977       /* This is a non-ISR function. The caller has already switched register */
2978       /* banks, if necessary, so just handle the callee-saves option. */
2979
2980       /* if callee-save to be used for this function
2981          then save the registers being used in this function */
2982       if (IFFUNC_CALLEESAVES(sym->type))
2983         {
2984           int i;
2985
2986           /* if any registers used */
2987           if (sym->regsUsed)
2988             {
2989               /* save the registers used */
2990               for (i = 0; i < sym->regsUsed->size; i++)
2991                 {
2992                   if (bitVectBitValue (sym->regsUsed, i))
2993                     {
2994                       /* remember one saved register for later usage */
2995                       if (calleesaves_saved_register < 0)
2996                         calleesaves_saved_register = i;
2997                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2998                       _G.nRegsSaved++;
2999                     }
3000                 }
3001             }
3002         }
3003     }
3004
3005
3006   if (fReentrant)
3007     {
3008       if (options.useXstack)
3009         {
3010           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3011             {
3012               emitcode ("mov", "r0,%s", spname);
3013               emitcode ("inc", "%s", spname);
3014               emitcode ("xch", "a,_bpx");
3015               emitcode ("movx", "@r0,a");
3016               emitcode ("inc", "r0");
3017               emitcode ("mov", "a,r0");
3018               emitcode ("xch", "a,_bpx");
3019             }
3020           if (sym->stack)
3021             {
3022               emitcode ("push", "_bp");     /* save the callers stack  */
3023               emitcode ("mov", "_bp,sp");
3024             }
3025         }
3026       else
3027         {
3028           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3029             {
3030               /* set up the stack */
3031               emitcode ("push", "_bp");     /* save the callers stack  */
3032               emitcode ("mov", "_bp,sp");
3033             }
3034         }
3035     }
3036
3037   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3038   /* before setting up the stack frame completely. */
3039   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3040     {
3041       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3042
3043       if (rsym->isitmp)
3044         {
3045           if (rsym && rsym->regType == REG_CND)
3046             rsym = NULL;
3047           if (rsym && (rsym->accuse || rsym->ruonly))
3048             rsym = NULL;
3049           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3050             rsym = rsym->usl.spillLoc;
3051         }
3052
3053       /* If the RECEIVE operand immediately spills to the first entry on the */
3054       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3055       /* rather than the usual @r0/r1 machinations. */
3056       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3057         {
3058           int ofs;
3059
3060           _G.current_iCode = ric;
3061           D(emitcode (";     genReceive",""));
3062           for (ofs=0; ofs < sym->recvSize; ofs++)
3063             {
3064               if (!strcmp (fReturn[ofs], "a"))
3065                 emitcode ("push", "acc");
3066               else
3067                 emitcode ("push", fReturn[ofs]);
3068             }
3069           stackAdjust -= sym->recvSize;
3070           if (stackAdjust<0)
3071             {
3072               assert (stackAdjust>=0);
3073               stackAdjust = 0;
3074             }
3075           _G.current_iCode = ic;
3076           ric->generated = 1;
3077           accIsFree = 1;
3078         }
3079       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3080       /* to free up the accumulator. */
3081       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3082         {
3083           int ofs;
3084
3085           _G.current_iCode = ric;
3086           D(emitcode (";     genReceive",""));
3087           for (ofs=0; ofs < sym->recvSize; ofs++)
3088             {
3089               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3090             }
3091           _G.current_iCode = ic;
3092           ric->generated = 1;
3093           accIsFree = 1;
3094         }
3095     }
3096
3097   /* adjust the stack for the function */
3098   if (stackAdjust)
3099     {
3100       int i = stackAdjust;
3101       if (i > 256)
3102         werror (W_STACK_OVERFLOW, sym->name);
3103
3104       if (i > 3 && accIsFree)
3105         {
3106           emitcode ("mov", "a,sp");
3107           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3108           emitcode ("mov", "sp,a");
3109         }
3110       else if (i > 5)
3111         {
3112           /* The accumulator is not free, so we will need another register */
3113           /* to clobber. No need to worry about a possible conflict with */
3114           /* the above early RECEIVE optimizations since they would have */
3115           /* freed the accumulator if they were generated. */
3116
3117           if (IFFUNC_CALLEESAVES(sym->type))
3118             {
3119               /* if it's a callee-saves function we need a saved register */
3120               if (calleesaves_saved_register >= 0)
3121                 {
3122                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3123                   emitcode ("mov", "a,sp");
3124                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3125                   emitcode ("mov", "sp,a");
3126                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3127                 }
3128               else
3129                 /* do it the hard way */
3130                 while (i--)
3131                   emitcode ("inc", "sp");
3132             }
3133           else
3134             {
3135               /* not callee-saves, we can clobber r0 */
3136               emitcode ("mov", "r0,a");
3137               emitcode ("mov", "a,sp");
3138               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3139               emitcode ("mov", "sp,a");
3140               emitcode ("mov", "a,r0");
3141             }
3142         }
3143       else
3144         while (i--)
3145           emitcode ("inc", "sp");
3146     }
3147
3148   if (sym->xstack)
3149     {
3150       char i = ((char) sym->xstack & 0xff);
3151
3152       if (i > 3 && accIsFree)
3153         {
3154           emitcode ("mov", "a,_spx");
3155           emitcode ("add", "a,#0x%02x", i);
3156           emitcode ("mov", "_spx,a");
3157         }
3158       else if (i > 5)
3159         {
3160           emitcode ("push", "acc");
3161           emitcode ("mov", "a,_spx");
3162           emitcode ("add", "a,#0x%02x", i);
3163           emitcode ("mov", "_spx,a");
3164           emitcode ("pop", "acc");
3165         }
3166       else
3167         {
3168           while (i--)
3169             emitcode ("inc", "_spx");
3170         }
3171     }
3172
3173   /* if critical function then turn interrupts off */
3174   if (IFFUNC_ISCRITICAL (ftype))
3175     {
3176       symbol *tlbl = newiTempLabel (NULL);
3177       emitcode ("setb", "c");
3178       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3179       emitcode ("clr", "c");
3180       emitcode ("", "%05d$:", (tlbl->key + 100));
3181       emitcode ("push", "psw"); /* save old ea via c in psw */
3182     }
3183 }
3184
3185 /*-----------------------------------------------------------------*/
3186 /* genEndFunction - generates epilogue for functions               */
3187 /*-----------------------------------------------------------------*/
3188 static void
3189 genEndFunction (iCode * ic)
3190 {
3191   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3192   lineNode *lnp = lineCurr;
3193   bitVect  *regsUsed;
3194   bitVect  *regsUsedPrologue;
3195   bitVect  *regsUnneeded;
3196   int      idx;
3197
3198   _G.currentFunc = NULL;
3199   if (IFFUNC_ISNAKED(sym->type))
3200   {
3201       emitcode(";", "naked function: no epilogue.");
3202       if (options.debug && currFunc)
3203         debugFile->writeEndFunction (currFunc, ic, 0);
3204       return;
3205   }
3206
3207   if (IFFUNC_ISCRITICAL (sym->type))
3208     {
3209       emitcode ("pop", "psw"); /* restore ea via c in psw */
3210       emitcode ("mov", "ea,c");
3211     }
3212
3213   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3214     {
3215       if (options.useXstack)
3216         {
3217           if (sym->stack)
3218             {
3219               emitcode ("mov", "sp,_bp");
3220               emitcode ("pop", "_bp");
3221             }
3222           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3223             {
3224               emitcode ("xch", "a,_bpx");
3225               emitcode ("mov", "r0,a");
3226               emitcode ("dec", "r0");
3227               emitcode ("movx", "a,@r0");
3228               emitcode ("xch", "a,_bpx");
3229               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3230             }
3231         }
3232       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3233         {
3234           emitcode ("mov", "sp,_bp");
3235           emitcode ("pop", "_bp");
3236         }
3237     }
3238
3239   /* restore the register bank  */
3240   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3241   {
3242     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3243      || !options.useXstack)
3244     {
3245         /* Special case of ISR using non-zero bank with useXstack
3246          * is handled below.
3247          */
3248         emitcode ("pop", "psw");
3249     }
3250   }
3251
3252   if (IFFUNC_ISISR (sym->type))
3253     {
3254
3255       /* now we need to restore the registers */
3256       /* if this isr has no bank i.e. is going to
3257          run with bank 0 , then we need to save more
3258          registers :-) */
3259       if (!FUNC_REGBANK (sym->type))
3260         {
3261           /* if this function does not call any other
3262              function then we can be economical and
3263              save only those registers that are used */
3264           if (!IFFUNC_HASFCALL(sym->type))
3265             {
3266               int i;
3267
3268               /* if any registers used */
3269               if (sym->regsUsed)
3270                 {
3271                   /* save the registers used */
3272                   for (i = sym->regsUsed->size; i >= 0; i--)
3273                     {
3274                       if (bitVectBitValue (sym->regsUsed, i))
3275                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3276                     }
3277                 }
3278             }
3279           else
3280             {
3281               if (options.parms_in_bank1) {
3282                   int i;
3283                   for (i = 7 ; i >= 0 ; i-- ) {
3284                       emitcode ("pop","%s",rb1regs[i]);
3285                   }
3286               }
3287               /* this function has  a function call cannot
3288                  determines register usage so we will have to pop the
3289                  entire bank */
3290               unsaveRBank (0, ic, FALSE);
3291             }
3292         }
3293         else
3294         {
3295             /* This ISR uses a non-zero bank.
3296              *
3297              * Restore any register banks saved by genFunction
3298              * in reverse order.
3299              */
3300             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3301             int ix;
3302
3303             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3304             {
3305                 if (savedBanks & (1 << ix))
3306                 {
3307                     unsaveRBank(ix, NULL, FALSE);
3308                 }
3309             }
3310
3311             if (options.useXstack)
3312             {
3313                 /* Restore bank AFTER calling unsaveRBank,
3314                  * since it can trash r0.
3315                  */
3316                 emitcode ("pop", "psw");
3317             }
3318         }
3319
3320       if (!inExcludeList ("dph"))
3321         emitcode ("pop", "dph");
3322       if (!inExcludeList ("dpl"))
3323         emitcode ("pop", "dpl");
3324       if (!inExcludeList ("b"))
3325         emitcode ("pop", "b");
3326       if (!inExcludeList ("acc"))
3327         emitcode ("pop", "acc");
3328
3329       /* if debug then send end of function */
3330       if (options.debug && currFunc)
3331         {
3332           debugFile->writeEndFunction (currFunc, ic, 1);
3333         }
3334
3335       emitcode ("reti", "");
3336     }
3337   else
3338     {
3339       if (IFFUNC_CALLEESAVES(sym->type))
3340         {
3341           int i;
3342
3343           /* if any registers used */
3344           if (sym->regsUsed)
3345             {
3346               /* save the registers used */
3347               for (i = sym->regsUsed->size; i >= 0; i--)
3348                 {
3349                   if (bitVectBitValue (sym->regsUsed, i) ||
3350                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3351                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3352                 }
3353             }
3354           else if (mcs51_ptrRegReq)
3355             {
3356               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3357               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3358             }
3359
3360         }
3361
3362       /* if debug then send end of function */
3363       if (options.debug && currFunc)
3364         {
3365           debugFile->writeEndFunction (currFunc, ic, 1);
3366         }
3367
3368       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3369         {
3370           emitcode ("ljmp", "__sdcc_banked_ret");
3371         }
3372       else
3373         {
3374           emitcode ("ret", "");
3375         }
3376     }
3377
3378   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3379     return;
3380
3381   /* If this was an interrupt handler using bank 0 that called another */
3382   /* function, then all registers must be saved; nothing to optimized. */
3383   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3384       && !FUNC_REGBANK(sym->type))
3385     return;
3386
3387   /* There are no push/pops to optimize if not callee-saves or ISR */
3388   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3389     return;
3390
3391   /* If there were stack parameters, we cannot optimize without also    */
3392   /* fixing all of the stack offsets; this is too dificult to consider. */
3393   if (FUNC_HASSTACKPARM(sym->type))
3394     return;
3395
3396   /* Compute the registers actually used */
3397   regsUsed = newBitVect (mcs51_nRegs);
3398   regsUsedPrologue = newBitVect (mcs51_nRegs);
3399   while (lnp)
3400     {
3401       if (lnp->ic && lnp->ic->op == FUNCTION)
3402         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3403       else
3404         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3405
3406       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3407           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3408         break;
3409       if (!lnp->prev)
3410         break;
3411       lnp = lnp->prev;
3412     }
3413
3414   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3415       && !bitVectBitValue (regsUsed, CND_IDX))
3416     {
3417       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3418       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3419           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3420         bitVectUnSetBit (regsUsed, CND_IDX);
3421     }
3422   else
3423     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3424
3425   /* If this was an interrupt handler that called another function */
3426   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3427   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3428     {
3429       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3430       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3431       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3432       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3433       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3434     }
3435
3436   /* Remove the unneeded push/pops */
3437   regsUnneeded = newBitVect (mcs51_nRegs);
3438   while (lnp)
3439     {
3440       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3441         {
3442           if (!strncmp(lnp->line, "push", 4))
3443             {
3444               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3445               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3446                 {
3447                   connectLine (lnp->prev, lnp->next);
3448                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3449                 }
3450             }
3451           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3452             {
3453               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3454               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3455                 {
3456                   connectLine (lnp->prev, lnp->next);
3457                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3458                 }
3459             }
3460         }
3461       lnp = lnp->next;
3462     }
3463
3464   for (idx = 0; idx < regsUnneeded->size; idx++)
3465     if (bitVectBitValue (regsUnneeded, idx))
3466       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3467
3468   freeBitVect (regsUnneeded);
3469   freeBitVect (regsUsed);
3470   freeBitVect (regsUsedPrologue);
3471 }
3472
3473 /*-----------------------------------------------------------------*/
3474 /* genRet - generate code for return statement                     */
3475 /*-----------------------------------------------------------------*/
3476 static void
3477 genRet (iCode * ic)
3478 {
3479   int size, offset = 0, pushed = 0;
3480
3481   D(emitcode (";     genRet",""));
3482
3483   /* if we have no return value then
3484      just generate the "ret" */
3485   if (!IC_LEFT (ic))
3486     goto jumpret;
3487
3488   /* we have something to return then
3489      move the return value into place */
3490   aopOp (IC_LEFT (ic), ic, FALSE);
3491   size = AOP_SIZE (IC_LEFT (ic));
3492
3493   while (size--)
3494     {
3495       char *l;
3496       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3497         {
3498           /* #NOCHANGE */
3499           l = aopGet (IC_LEFT (ic), offset++,
3500                       FALSE, TRUE);
3501           emitcode ("push", "%s", l);
3502           pushed++;
3503         }
3504       else
3505         {
3506           l = aopGet (IC_LEFT (ic), offset,
3507                       FALSE, FALSE);
3508           if (strcmp (fReturn[offset], l))
3509             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3510         }
3511     }
3512
3513   if (pushed)
3514     {
3515       while (pushed)
3516         {
3517           pushed--;
3518           if (strcmp (fReturn[pushed], "a"))
3519             emitcode ("pop", fReturn[pushed]);
3520           else
3521             emitcode ("pop", "acc");
3522         }
3523     }
3524   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3525
3526 jumpret:
3527   /* generate a jump to the return label
3528      if the next is not the return statement */
3529   if (!(ic->next && ic->next->op == LABEL &&
3530         IC_LABEL (ic->next) == returnLabel))
3531
3532     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3533
3534 }
3535
3536 /*-----------------------------------------------------------------*/
3537 /* genLabel - generates a label                                    */
3538 /*-----------------------------------------------------------------*/
3539 static void
3540 genLabel (iCode * ic)
3541 {
3542   /* special case never generate */
3543   if (IC_LABEL (ic) == entryLabel)
3544     return;
3545
3546   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3547 }
3548
3549 /*-----------------------------------------------------------------*/
3550 /* genGoto - generates a ljmp                                      */
3551 /*-----------------------------------------------------------------*/
3552 static void
3553 genGoto (iCode * ic)
3554 {
3555   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3556 }
3557
3558 /*-----------------------------------------------------------------*/
3559 /* findLabelBackwards: walks back through the iCode chain looking  */
3560 /* for the given label. Returns number of iCode instructions     */
3561 /* between that label and given ic.          */
3562 /* Returns zero if label not found.          */
3563 /*-----------------------------------------------------------------*/
3564 static int
3565 findLabelBackwards (iCode * ic, int key)
3566 {
3567   int count = 0;
3568
3569   while (ic->prev)
3570     {
3571       ic = ic->prev;
3572       count++;
3573
3574       /* If we have any pushes or pops, we cannot predict the distance.
3575          I don't like this at all, this should be dealt with in the
3576          back-end */
3577       if (ic->op == IPUSH || ic->op == IPOP) {
3578         return 0;
3579       }
3580
3581       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3582         {
3583           return count;
3584         }
3585     }
3586
3587   return 0;
3588 }
3589
3590 /*-----------------------------------------------------------------*/
3591 /* genPlusIncr :- does addition with increment if possible         */
3592 /*-----------------------------------------------------------------*/
3593 static bool
3594 genPlusIncr (iCode * ic)
3595 {
3596   unsigned int icount;
3597   unsigned int size = getDataSize (IC_RESULT (ic));
3598
3599   /* will try to generate an increment */
3600   /* if the right side is not a literal
3601      we cannot */
3602   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3603     return FALSE;
3604
3605   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3606
3607   D(emitcode (";     genPlusIncr",""));
3608
3609   /* if increment >=16 bits in register or direct space */
3610   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3611       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3612       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3613       (size > 1) &&
3614       (icount == 1))
3615     {
3616       symbol *tlbl;
3617       int emitTlbl;
3618       int labelRange;
3619
3620       /* If the next instruction is a goto and the goto target
3621        * is < 10 instructions previous to this, we can generate
3622        * jumps straight to that target.
3623        */
3624       if (ic->next && ic->next->op == GOTO
3625           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3626           && labelRange <= 10)
3627         {
3628           emitcode (";", "tail increment optimized");
3629           tlbl = IC_LABEL (ic->next);
3630           emitTlbl = 0;
3631         }
3632       else
3633         {
3634           tlbl = newiTempLabel (NULL);
3635           emitTlbl = 1;
3636         }
3637       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3638       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3639           IS_AOP_PREG (IC_RESULT (ic)))
3640         emitcode ("cjne", "%s,#0x00,%05d$",
3641                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3642                   tlbl->key + 100);
3643       else
3644         {
3645           emitcode ("clr", "a");
3646           emitcode ("cjne", "a,%s,%05d$",
3647                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3648                     tlbl->key + 100);
3649         }
3650
3651       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3652       if (size > 2)
3653         {
3654           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3655               IS_AOP_PREG (IC_RESULT (ic)))
3656             emitcode ("cjne", "%s,#0x00,%05d$",
3657                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3658                       tlbl->key + 100);
3659           else
3660             emitcode ("cjne", "a,%s,%05d$",
3661                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3662                       tlbl->key + 100);
3663
3664           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3665         }
3666       if (size > 3)
3667         {
3668           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3669               IS_AOP_PREG (IC_RESULT (ic)))
3670             emitcode ("cjne", "%s,#0x00,%05d$",
3671                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3672                       tlbl->key + 100);
3673           else
3674             {
3675               emitcode ("cjne", "a,%s,%05d$",
3676                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3677                         tlbl->key + 100);
3678             }
3679           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3680         }
3681
3682       if (emitTlbl)
3683         {
3684           emitcode ("", "%05d$:", tlbl->key + 100);
3685         }
3686       return TRUE;
3687     }
3688
3689   /* if result is dptr */
3690   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
3691       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
3692       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
3693       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
3694     {
3695       if (aopGetUsesAcc (IC_LEFT (ic), 0))
3696         return FALSE;
3697
3698       if (icount > 9)
3699         return FALSE;
3700
3701       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
3702         return FALSE;
3703
3704       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
3705       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
3706       while (icount--)
3707         emitcode ("inc", "dptr");
3708
3709       return TRUE;
3710     }
3711
3712   /* if the literal value of the right hand side
3713      is greater than 4 then it is not worth it */
3714   if (icount > 4)
3715     return FALSE;
3716
3717   /* if the sizes are greater than 1 then we cannot */
3718   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3719       AOP_SIZE (IC_LEFT (ic)) > 1)
3720     return FALSE;
3721
3722   /* we can if the aops of the left & result match or
3723      if they are in registers and the registers are the
3724      same */
3725   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3726     {
3727
3728       if (icount > 3)
3729         {
3730           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3731           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3732           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3733         }
3734       else
3735         {
3736
3737           while (icount--)
3738             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3739         }
3740
3741       return TRUE;
3742     }
3743
3744   return FALSE;
3745 }
3746
3747 /*-----------------------------------------------------------------*/
3748 /* outBitAcc - output a bit in acc                                 */
3749 /*-----------------------------------------------------------------*/
3750 static void
3751 outBitAcc (operand * result)
3752 {
3753   symbol *tlbl = newiTempLabel (NULL);
3754   /* if the result is a bit */
3755   if (AOP_TYPE (result) == AOP_CRY)
3756     {
3757       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
3758     }
3759   else
3760     {
3761       emitcode ("jz", "%05d$", tlbl->key + 100);
3762       emitcode ("mov", "a,%s", one);
3763       emitcode ("", "%05d$:", tlbl->key + 100);
3764       outAcc (result);
3765     }
3766 }
3767
3768 /*-----------------------------------------------------------------*/
3769 /* genPlusBits - generates code for addition of two bits           */
3770 /*-----------------------------------------------------------------*/
3771 static void
3772 genPlusBits (iCode * ic)
3773 {
3774   D(emitcode (";     genPlusBits",""));
3775
3776   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3777     {
3778       symbol *lbl = newiTempLabel (NULL);
3779       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3780       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3781       emitcode ("cpl", "c");
3782       emitcode ("", "%05d$:", (lbl->key + 100));
3783       outBitC (IC_RESULT (ic));
3784     }
3785   else
3786     {
3787       emitcode ("clr", "a");
3788       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3789       emitcode ("rlc", "a");
3790       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3791       emitcode ("addc", "a,#0x00");
3792       outAcc (IC_RESULT (ic));
3793     }
3794 }
3795
3796 #if 0
3797 /* This is the original version of this code.
3798
3799  * This is being kept around for reference,
3800  * because I am not entirely sure I got it right...
3801  */
3802 static void
3803 adjustArithmeticResult (iCode * ic)
3804 {
3805   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3806       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3807       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3808     aopPut (IC_RESULT (ic),
3809             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
3810             2,
3811             isOperandVolatile (IC_RESULT (ic), FALSE));
3812
3813   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3814       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3815       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3816     aopPut (IC_RESULT (ic),
3817             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
3818             2,
3819             isOperandVolatile (IC_RESULT (ic), FALSE));
3820
3821   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3822       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3823       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3824       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3825       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3826     {
3827       char buffer[5];
3828       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3829       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3830     }
3831 }
3832 #else
3833 /* This is the pure and virtuous version of this code.
3834  * I'm pretty certain it's right, but not enough to toss the old
3835  * code just yet...
3836  */
3837 static void
3838 adjustArithmeticResult (iCode * ic)
3839 {
3840   if (opIsGptr (IC_RESULT (ic)) &&
3841       opIsGptr (IC_LEFT (ic)) &&
3842       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3843     {
3844       aopPut (IC_RESULT (ic),
3845               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
3846               GPTRSIZE - 1,
3847               isOperandVolatile (IC_RESULT (ic), FALSE));
3848     }
3849
3850   if (opIsGptr (IC_RESULT (ic)) &&
3851       opIsGptr (IC_RIGHT (ic)) &&
3852       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3853     {
3854       aopPut (IC_RESULT (ic),
3855               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
3856               GPTRSIZE - 1,
3857               isOperandVolatile (IC_RESULT (ic), FALSE));
3858     }
3859
3860   if (opIsGptr (IC_RESULT (ic)) &&
3861       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3862       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3863       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3864       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3865     {
3866       char buffer[5];
3867       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
3868       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3869     }
3870 }
3871 #endif
3872
3873 /*-----------------------------------------------------------------*/
3874 /* genPlus - generates code for addition                           */
3875 /*-----------------------------------------------------------------*/
3876 static void
3877 genPlus (iCode * ic)
3878 {
3879   int size, offset = 0;
3880   int skip_bytes = 0;
3881   char *add = "add";
3882   operand *leftOp, *rightOp;
3883   operand * op;
3884
3885   /* special cases :- */
3886
3887   D(emitcode (";     genPlus",""));
3888
3889   aopOp (IC_LEFT (ic), ic, FALSE);
3890   aopOp (IC_RIGHT (ic), ic, FALSE);
3891   aopOp (IC_RESULT (ic), ic, TRUE);
3892
3893   /* if literal, literal on the right or
3894      if left requires ACC or right is already
3895      in ACC */
3896   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3897       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3898       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3899     {
3900       operand *t = IC_RIGHT (ic);
3901       IC_RIGHT (ic) = IC_LEFT (ic);
3902       IC_LEFT (ic) = t;
3903     }
3904
3905   /* if both left & right are in bit
3906      space */
3907   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3908       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3909     {
3910       genPlusBits (ic);
3911       goto release;
3912     }
3913
3914   /* if left in bit space & right literal */
3915   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3916       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3917     {
3918       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3919       /* if result in bit space */
3920       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3921         {
3922           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3923             emitcode ("cpl", "c");
3924           outBitC (IC_RESULT (ic));
3925         }
3926       else
3927         {
3928           size = getDataSize (IC_RESULT (ic));
3929           while (size--)
3930             {
3931               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
3932               emitcode ("addc", "a,#00");
3933               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3934             }
3935         }
3936       goto release;
3937     }
3938
3939   /* if I can do an increment instead
3940      of add then GOOD for ME */
3941   if (genPlusIncr (ic) == TRUE)
3942     goto release;
3943
3944   size = getDataSize (IC_RESULT (ic));
3945   leftOp = IC_LEFT(ic);
3946   rightOp = IC_RIGHT(ic);
3947   op=IC_LEFT(ic);
3948
3949   /* if this is an add for an array access
3950      at a 256 byte boundary */
3951   if ( 2 == size
3952        && AOP_TYPE (op) == AOP_IMMD
3953        && IS_SYMOP (op)
3954        && IS_SPEC (OP_SYM_ETYPE (op))
3955        && SPEC_ABSA (OP_SYM_ETYPE (op))
3956        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3957      )
3958     {
3959       D(emitcode (";     genPlus aligned array",""));
3960       aopPut (IC_RESULT (ic),
3961               aopGet (rightOp, 0, FALSE, FALSE),
3962               0,
3963               isOperandVolatile (IC_RESULT (ic), FALSE));
3964
3965       if( 1 == getDataSize (IC_RIGHT (ic)) )
3966         {
3967           aopPut (IC_RESULT (ic),
3968                   aopGet (leftOp, 1, FALSE, FALSE),
3969                   1,
3970                   isOperandVolatile (IC_RESULT (ic), FALSE));
3971         }
3972       else
3973         {
3974           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
3975           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3976           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3977         }
3978       goto release;
3979     }
3980
3981   /* if the lower bytes of a literal are zero skip the addition */
3982   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3983     {
3984        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3985               (skip_bytes+1 < size))
3986          {
3987            skip_bytes++;
3988          }
3989        if (skip_bytes)
3990          D(emitcode (";     genPlus shortcut",""));
3991     }
3992
3993   while (size--)
3994     {
3995       if( offset >= skip_bytes )
3996         {
3997           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3998             {
3999               bool pushedB;
4000               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4001               pushedB = pushB ();
4002               emitcode("xch", "a,b");
4003               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4004               emitcode (add, "a,b");
4005               popB (pushedB);
4006             }
4007           else if (aopGetUsesAcc (leftOp, offset))
4008             {
4009               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4010               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4011             }
4012           else
4013             {
4014               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4015               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4016             }
4017           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4018           add = "addc";  /* further adds must propagate carry */
4019         }
4020       else
4021         {
4022           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4023               isOperandVolatile (IC_RESULT (ic), FALSE))
4024             {
4025               /* just move */
4026               aopPut (IC_RESULT (ic),
4027                       aopGet (leftOp, offset, FALSE, FALSE),
4028                       offset,
4029                       isOperandVolatile (IC_RESULT (ic), FALSE));
4030             }
4031         }
4032       offset++;
4033     }
4034
4035   adjustArithmeticResult (ic);
4036
4037 release:
4038   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4039   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4040   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4041 }
4042
4043 /*-----------------------------------------------------------------*/
4044 /* genMinusDec :- does subtraction with deccrement if possible     */
4045 /*-----------------------------------------------------------------*/
4046 static bool
4047 genMinusDec (iCode * ic)
4048 {
4049   unsigned int icount;
4050   unsigned int size = getDataSize (IC_RESULT (ic));
4051
4052   /* will try to generate an increment */
4053   /* if the right side is not a literal
4054      we cannot */
4055   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4056     return FALSE;
4057
4058   /* if the literal value of the right hand side
4059      is greater than 4 then it is not worth it */
4060   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4061     return FALSE;
4062
4063   D(emitcode (";     genMinusDec",""));
4064
4065   /* if decrement >=16 bits in register or direct space */
4066   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4067       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4068       (size > 1) &&
4069       (icount == 1))
4070     {
4071       symbol *tlbl;
4072       int emitTlbl;
4073       int labelRange;
4074
4075       /* If the next instruction is a goto and the goto target
4076        * is <= 10 instructions previous to this, we can generate
4077        * jumps straight to that target.
4078        */
4079       if (ic->next && ic->next->op == GOTO
4080           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4081           && labelRange <= 10)
4082         {
4083           emitcode (";", "tail decrement optimized");
4084           tlbl = IC_LABEL (ic->next);
4085           emitTlbl = 0;
4086         }
4087       else
4088         {
4089           tlbl = newiTempLabel (NULL);
4090           emitTlbl = 1;
4091         }
4092
4093       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4094       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4095           IS_AOP_PREG (IC_RESULT (ic)))
4096         emitcode ("cjne", "%s,#0xff,%05d$"
4097                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4098                   ,tlbl->key + 100);
4099       else
4100         {
4101           emitcode ("mov", "a,#0xff");
4102           emitcode ("cjne", "a,%s,%05d$"
4103                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4104                     ,tlbl->key + 100);
4105         }
4106       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4107       if (size > 2)
4108         {
4109           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4110               IS_AOP_PREG (IC_RESULT (ic)))
4111             emitcode ("cjne", "%s,#0xff,%05d$"
4112                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4113                       ,tlbl->key + 100);
4114           else
4115             {
4116               emitcode ("cjne", "a,%s,%05d$"
4117                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4118                         ,tlbl->key + 100);
4119             }
4120           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4121         }
4122       if (size > 3)
4123         {
4124           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4125               IS_AOP_PREG (IC_RESULT (ic)))
4126             emitcode ("cjne", "%s,#0xff,%05d$"
4127                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4128                       ,tlbl->key + 100);
4129           else
4130             {
4131               emitcode ("cjne", "a,%s,%05d$"
4132                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4133                         ,tlbl->key + 100);
4134             }
4135           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4136         }
4137       if (emitTlbl)
4138         {
4139           emitcode ("", "%05d$:", tlbl->key + 100);
4140         }
4141       return TRUE;
4142     }
4143
4144   /* if the sizes are greater than 1 then we cannot */
4145   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4146       AOP_SIZE (IC_LEFT (ic)) > 1)
4147     return FALSE;
4148
4149   /* we can if the aops of the left & result match or
4150      if they are in registers and the registers are the
4151      same */
4152   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4153     {
4154
4155       while (icount--)
4156         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4157
4158       return TRUE;
4159     }
4160
4161   return FALSE;
4162 }
4163
4164 /*-----------------------------------------------------------------*/
4165 /* addSign - complete with sign                                    */
4166 /*-----------------------------------------------------------------*/
4167 static void
4168 addSign (operand * result, int offset, int sign)
4169 {
4170   int size = (getDataSize (result) - offset);
4171   if (size > 0)
4172     {
4173       if (sign)
4174         {
4175           emitcode ("rlc", "a");
4176           emitcode ("subb", "a,acc");
4177           while (size--)
4178             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4179         }
4180       else
4181         while (size--)
4182           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4183     }
4184 }
4185
4186 /*-----------------------------------------------------------------*/
4187 /* genMinusBits - generates code for subtraction  of two bits      */
4188 /*-----------------------------------------------------------------*/
4189 static void
4190 genMinusBits (iCode * ic)
4191 {
4192   symbol *lbl = newiTempLabel (NULL);
4193
4194   D(emitcode (";     genMinusBits",""));
4195
4196   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4197     {
4198       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4199       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4200       emitcode ("cpl", "c");
4201       emitcode ("", "%05d$:", (lbl->key + 100));
4202       outBitC (IC_RESULT (ic));
4203     }
4204   else
4205     {
4206       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4207       emitcode ("subb", "a,acc");
4208       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4209       emitcode ("inc", "a");
4210       emitcode ("", "%05d$:", (lbl->key + 100));
4211       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4212       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4213     }
4214 }
4215
4216 /*-----------------------------------------------------------------*/
4217 /* genMinus - generates code for subtraction                       */
4218 /*-----------------------------------------------------------------*/
4219 static void
4220 genMinus (iCode * ic)
4221 {
4222   int size, offset = 0;
4223
4224   D(emitcode (";     genMinus",""));
4225
4226   aopOp (IC_LEFT (ic), ic, FALSE);
4227   aopOp (IC_RIGHT (ic), ic, FALSE);
4228   aopOp (IC_RESULT (ic), ic, TRUE);
4229
4230   /* special cases :- */
4231   /* if both left & right are in bit space */
4232   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4233       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4234     {
4235       genMinusBits (ic);
4236       goto release;
4237     }
4238
4239   /* if I can do an decrement instead
4240      of subtract then GOOD for ME */
4241   if (genMinusDec (ic) == TRUE)
4242     goto release;
4243
4244   size = getDataSize (IC_RESULT (ic));
4245
4246   /* if literal, add a,#-lit, else normal subb */
4247   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4248     {
4249       unsigned long lit = 0L;
4250       bool useCarry = FALSE;
4251
4252       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4253       lit = -(long) lit;
4254
4255       while (size--)
4256         {
4257           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL)) {
4258             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4259             if (!offset && !size && lit== (unsigned long) -1) {
4260               emitcode ("dec", "a");
4261             } else if (!useCarry) {
4262           /* first add without previous c */
4263               emitcode ("add", "a,#0x%02x",
4264                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4265               useCarry = TRUE;
4266           } else {
4267             emitcode ("addc", "a,#0x%02x",
4268                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4269           }
4270             aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4271             } else {
4272               /* no need to add zeroes */
4273               offset++;
4274             }
4275         }
4276     }
4277   else
4278     {
4279       operand *leftOp, *rightOp;
4280
4281       leftOp = IC_LEFT(ic);
4282       rightOp = IC_RIGHT(ic);
4283
4284       while (size--)
4285         {
4286           if (aopGetUsesAcc(rightOp, offset)) {
4287             if (aopGetUsesAcc(leftOp, offset)) {
4288               bool pushedB;
4289
4290               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4291               pushedB = pushB ();
4292               emitcode ("mov", "b,a");
4293               if (offset == 0)
4294                 CLRC;
4295               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4296               emitcode ("subb", "a,b");
4297               popB (pushedB);
4298             } else {
4299               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4300               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4301               if (offset == 0) {
4302                 emitcode( "setb", "c");
4303               }
4304               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4305               emitcode("cpl", "a");
4306             }
4307           } else {
4308             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4309             if (offset == 0)
4310               CLRC;
4311             emitcode ("subb", "a,%s",
4312                       aopGet(rightOp, offset, FALSE, TRUE));
4313           }
4314
4315           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4316         }
4317     }
4318
4319
4320   adjustArithmeticResult (ic);
4321
4322 release:
4323   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4324   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4325   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4326 }
4327
4328
4329 /*-----------------------------------------------------------------*/
4330 /* genMultbits :- multiplication of bits                           */
4331 /*-----------------------------------------------------------------*/
4332 static void
4333 genMultbits (operand * left,
4334              operand * right,
4335              operand * result)
4336 {
4337   D(emitcode (";     genMultbits",""));
4338
4339   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4340   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4341   outBitC (result);
4342 }
4343
4344 /*-----------------------------------------------------------------*/
4345 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4346 /*-----------------------------------------------------------------*/
4347 static void
4348 genMultOneByte (operand * left,
4349                 operand * right,
4350                 operand * result)
4351 {
4352   symbol *lbl;
4353   int size = AOP_SIZE (result);
4354   bool runtimeSign, compiletimeSign;
4355   bool lUnsigned, rUnsigned, pushedB;
4356
4357   D(emitcode (";     genMultOneByte",""));
4358
4359   if (size < 1 || size > 2)
4360     {
4361       /* this should never happen */
4362       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4363                AOP_SIZE(result), __FILE__, lineno);
4364       exit (1);
4365     }
4366
4367   /* (if two literals: the value is computed before) */
4368   /* if one literal, literal on the right */
4369   if (AOP_TYPE (left) == AOP_LIT)
4370     {
4371       operand *t = right;
4372       right = left;
4373       left = t;
4374       /* emitcode (";", "swapped left and right"); */
4375     }
4376   /* if no literal, unsigned on the right: shorter code */
4377   if (   AOP_TYPE (right) != AOP_LIT
4378       && SPEC_USIGN (getSpec (operandType (left))))
4379     {
4380       operand *t = right;
4381       right = left;
4382       left = t;
4383     }
4384
4385   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4386   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4387
4388   pushedB = pushB ();
4389
4390   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4391                    no need to take care about the signedness! */
4392       || (lUnsigned && rUnsigned))
4393     {
4394       /* just an unsigned 8 * 8 = 8 multiply
4395          or 8u * 8u = 16u */
4396       /* emitcode (";","unsigned"); */
4397       /* TODO: check for accumulator clash between left & right aops? */
4398
4399       if (AOP_TYPE (right) == AOP_LIT)
4400         {
4401           /* moving to accumulator first helps peepholes */
4402           MOVA (aopGet (left, 0, FALSE, FALSE));
4403           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4404         }
4405       else
4406         {
4407           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4408           MOVA (aopGet (left, 0, FALSE, FALSE));
4409         }
4410
4411       emitcode ("mul", "ab");
4412       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4413       if (size == 2)
4414         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4415
4416       popB (pushedB);
4417       return;
4418     }
4419
4420   /* we have to do a signed multiply */
4421   /* emitcode (";", "signed"); */
4422
4423   /* now sign adjust for both left & right */
4424
4425   /* let's see what's needed: */
4426   /* apply negative sign during runtime */
4427   runtimeSign = FALSE;
4428   /* negative sign from literals */
4429   compiletimeSign = FALSE;
4430
4431   if (!lUnsigned)
4432     {
4433       if (AOP_TYPE(left) == AOP_LIT)
4434         {
4435           /* signed literal */
4436           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4437           if (val < 0)
4438             compiletimeSign = TRUE;
4439         }
4440       else
4441         /* signed but not literal */
4442         runtimeSign = TRUE;
4443     }
4444
4445   if (!rUnsigned)
4446     {
4447       if (AOP_TYPE(right) == AOP_LIT)
4448         {
4449           /* signed literal */
4450           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4451           if (val < 0)
4452             compiletimeSign ^= TRUE;
4453         }
4454       else
4455         /* signed but not literal */
4456         runtimeSign = TRUE;
4457     }
4458
4459   /* initialize F0, which stores the runtime sign */
4460   if (runtimeSign)
4461     {
4462       if (compiletimeSign)
4463         emitcode ("setb", "F0"); /* set sign flag */
4464       else
4465         emitcode ("clr", "F0"); /* reset sign flag */
4466     }
4467
4468   /* save the signs of the operands */
4469   if (AOP_TYPE(right) == AOP_LIT)
4470     {
4471       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4472
4473       if (!rUnsigned && val < 0)
4474         emitcode ("mov", "b,#0x%02x", -val);
4475       else
4476         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4477     }
4478   else /* ! literal */
4479     {
4480       if (rUnsigned)  /* emitcode (";", "signed"); */
4481
4482         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4483       else
4484         {
4485           MOVA (aopGet (right, 0, FALSE, FALSE));
4486           lbl = newiTempLabel (NULL);
4487           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4488           emitcode ("cpl", "F0"); /* complement sign flag */
4489           emitcode ("cpl", "a");  /* 2's complement */
4490           emitcode ("inc", "a");
4491           emitcode ("", "%05d$:", (lbl->key + 100));
4492           emitcode ("mov", "b,a");
4493         }
4494     }
4495
4496   if (AOP_TYPE(left) == AOP_LIT)
4497     {
4498       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4499
4500       if (!lUnsigned && val < 0)
4501         emitcode ("mov", "a,#0x%02x", -val);
4502       else
4503         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4504     }
4505   else /* ! literal */
4506     {
4507       MOVA (aopGet (left, 0, FALSE, FALSE));
4508
4509       if (!lUnsigned)
4510         {
4511           lbl = newiTempLabel (NULL);
4512           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4513           emitcode ("cpl", "F0"); /* complement sign flag */
4514           emitcode ("cpl", "a"); /* 2's complement */
4515           emitcode ("inc", "a");
4516           emitcode ("", "%05d$:", (lbl->key + 100));
4517         }
4518     }
4519
4520   /* now the multiplication */
4521   emitcode ("mul", "ab");
4522   if (runtimeSign || compiletimeSign)
4523     {
4524       lbl = newiTempLabel (NULL);
4525       if (runtimeSign)
4526         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4527       emitcode ("cpl", "a"); /* lsb 2's complement */
4528       if (size != 2)
4529         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4530       else
4531         {
4532           emitcode ("add", "a,#1"); /* this sets carry flag */
4533           emitcode ("xch", "a,b");
4534           emitcode ("cpl", "a"); /* msb 2's complement */
4535           emitcode ("addc", "a,#0");
4536           emitcode ("xch", "a,b");
4537         }
4538       emitcode ("", "%05d$:", (lbl->key + 100));
4539     }
4540   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4541   if (size == 2)
4542     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4543
4544   popB (pushedB);
4545 }
4546
4547 /*-----------------------------------------------------------------*/
4548 /* genMult - generates code for multiplication                     */
4549 /*-----------------------------------------------------------------*/
4550 static void
4551 genMult (iCode * ic)
4552 {
4553   operand *left = IC_LEFT (ic);
4554   operand *right = IC_RIGHT (ic);
4555   operand *result = IC_RESULT (ic);
4556
4557   D(emitcode (";     genMult",""));
4558
4559   /* assign the amsops */
4560   aopOp (left, ic, FALSE);
4561   aopOp (right, ic, FALSE);
4562   aopOp (result, ic, TRUE);
4563
4564   /* special cases first */
4565   /* both are bits */
4566   if (AOP_TYPE (left) == AOP_CRY &&
4567       AOP_TYPE (right) == AOP_CRY)
4568     {
4569       genMultbits (left, right, result);
4570       goto release;
4571     }
4572
4573   /* if both are of size == 1 */
4574 #if 0 // one of them can be a sloc shared with the result
4575     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4576 #else
4577   if (getSize(operandType(left)) == 1 &&
4578       getSize(operandType(right)) == 1)
4579 #endif
4580     {
4581       genMultOneByte (left, right, result);
4582       goto release;
4583     }
4584
4585   /* should have been converted to function call */
4586     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4587              getSize(OP_SYMBOL(right)->type));
4588   assert (0);
4589
4590 release:
4591   freeAsmop (result, NULL, ic, TRUE);
4592   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4593   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4594 }
4595
4596 /*-----------------------------------------------------------------*/
4597 /* genDivbits :- division of bits                                  */
4598 /*-----------------------------------------------------------------*/
4599 static void
4600 genDivbits (operand * left,
4601             operand * right,
4602             operand * result)
4603 {
4604   char *l;
4605   bool pushedB;
4606
4607   D(emitcode (";     genDivbits",""));
4608
4609   pushedB = pushB ();
4610
4611   /* the result must be bit */
4612   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4613   l = aopGet (left, 0, FALSE, FALSE);
4614
4615   MOVA (l);
4616
4617   emitcode ("div", "ab");
4618   emitcode ("rrc", "a");
4619
4620   popB (pushedB);
4621
4622   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4623 }
4624
4625 /*-----------------------------------------------------------------*/
4626 /* genDivOneByte : 8 bit division                                  */
4627 /*-----------------------------------------------------------------*/
4628 static void
4629 genDivOneByte (operand * left,
4630                operand * right,
4631                operand * result)
4632 {
4633   bool lUnsigned, rUnsigned, pushedB;
4634   bool runtimeSign, compiletimeSign;
4635   symbol *lbl;
4636   int size, offset;
4637
4638   D(emitcode (";     genDivOneByte",""));
4639
4640   /* Why is it necessary that genDivOneByte() can return an int result?
4641      Have a look at:
4642
4643         volatile unsigned char uc;
4644         volatile signed char sc1, sc2;
4645         volatile int i;
4646
4647         uc  = 255;
4648         sc1 = -1;
4649         i = uc / sc1;
4650
4651      Or:
4652
4653         sc1 = -128;
4654         sc2 = -1;
4655         i = sc1 / sc2;
4656
4657      In all cases a one byte result would overflow, the following cast to int
4658      would return the wrong result.
4659
4660      Two possible solution:
4661         a) cast operands to int, if ((unsigned) / (signed)) or
4662            ((signed) / (signed))
4663         b) return an 16 bit signed int; this is what we're doing here!
4664   */
4665
4666   size = AOP_SIZE (result) - 1;
4667   offset = 1;
4668   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4669   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4670
4671   pushedB = pushB ();
4672
4673   /* signed or unsigned */
4674   if (lUnsigned && rUnsigned)
4675     {
4676       /* unsigned is easy */
4677       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4678       MOVA (aopGet (left, 0, FALSE, FALSE));
4679       emitcode ("div", "ab");
4680       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4681       while (size--)
4682         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4683
4684       popB (pushedB);
4685       return;
4686     }
4687
4688   /* signed is a little bit more difficult */
4689
4690   /* now sign adjust for both left & right */
4691
4692   /* let's see what's needed: */
4693   /* apply negative sign during runtime */
4694   runtimeSign = FALSE;
4695   /* negative sign from literals */
4696   compiletimeSign = FALSE;
4697
4698   if (!lUnsigned)
4699     {
4700       if (AOP_TYPE(left) == AOP_LIT)
4701         {
4702           /* signed literal */
4703           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4704           if (val < 0)
4705             compiletimeSign = TRUE;
4706         }
4707       else
4708         /* signed but not literal */
4709         runtimeSign = TRUE;
4710     }
4711
4712   if (!rUnsigned)
4713     {
4714       if (AOP_TYPE(right) == AOP_LIT)
4715         {
4716           /* signed literal */
4717           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4718           if (val < 0)
4719             compiletimeSign ^= TRUE;
4720         }
4721       else
4722         /* signed but not literal */
4723         runtimeSign = TRUE;
4724     }
4725
4726   /* initialize F0, which stores the runtime sign */
4727   if (runtimeSign)
4728     {
4729       if (compiletimeSign)
4730         emitcode ("setb", "F0"); /* set sign flag */
4731       else
4732         emitcode ("clr", "F0"); /* reset sign flag */
4733     }
4734
4735   /* save the signs of the operands */
4736   if (AOP_TYPE(right) == AOP_LIT)
4737     {
4738       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4739
4740       if (!rUnsigned && val < 0)
4741         emitcode ("mov", "b,#0x%02x", -val);
4742       else
4743         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4744     }
4745   else /* ! literal */
4746     {
4747       if (rUnsigned)
4748         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4749       else
4750         {
4751           MOVA (aopGet (right, 0, FALSE, FALSE));
4752           lbl = newiTempLabel (NULL);
4753           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4754           emitcode ("cpl", "F0"); /* complement sign flag */
4755           emitcode ("cpl", "a");  /* 2's complement */
4756           emitcode ("inc", "a");
4757           emitcode ("", "%05d$:", (lbl->key + 100));
4758           emitcode ("mov", "b,a");
4759         }
4760     }
4761
4762   if (AOP_TYPE(left) == AOP_LIT)
4763     {
4764       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4765
4766       if (!lUnsigned && val < 0)
4767         emitcode ("mov", "a,#0x%02x", -val);
4768       else
4769         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4770     }
4771   else /* ! literal */
4772     {
4773       MOVA (aopGet (left, 0, FALSE, FALSE));
4774
4775       if (!lUnsigned)
4776         {
4777           lbl = newiTempLabel (NULL);
4778           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4779           emitcode ("cpl", "F0"); /* complement sign flag */
4780           emitcode ("cpl", "a");  /* 2's complement */
4781           emitcode ("inc", "a");
4782           emitcode ("", "%05d$:", (lbl->key + 100));
4783         }
4784     }
4785
4786   /* now the division */
4787   emitcode ("div", "ab");
4788
4789   if (runtimeSign || compiletimeSign)
4790     {
4791       lbl = newiTempLabel (NULL);
4792       if (runtimeSign)
4793         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4794       emitcode ("cpl", "a"); /* lsb 2's complement */
4795       emitcode ("inc", "a");
4796       emitcode ("", "%05d$:", (lbl->key + 100));
4797
4798       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4799       if (size > 0)
4800         {
4801           /* msb is 0x00 or 0xff depending on the sign */
4802           if (runtimeSign)
4803             {
4804               emitcode ("mov", "c,F0");
4805               emitcode ("subb", "a,acc");
4806               while (size--)
4807                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4808             }
4809           else /* compiletimeSign */
4810             while (size--)
4811               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
4812         }
4813     }
4814   else
4815     {
4816       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4817       while (size--)
4818         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4819     }
4820
4821   popB (pushedB);
4822 }
4823
4824 /*-----------------------------------------------------------------*/
4825 /* genDiv - generates code for division                            */
4826 /*-----------------------------------------------------------------*/
4827 static void
4828 genDiv (iCode * ic)
4829 {
4830   operand *left = IC_LEFT (ic);
4831   operand *right = IC_RIGHT (ic);
4832   operand *result = IC_RESULT (ic);
4833
4834   D(emitcode (";     genDiv",""));
4835
4836   /* assign the amsops */
4837   aopOp (left, ic, FALSE);
4838   aopOp (right, ic, FALSE);
4839   aopOp (result, ic, TRUE);
4840
4841   /* special cases first */
4842   /* both are bits */
4843   if (AOP_TYPE (left) == AOP_CRY &&
4844       AOP_TYPE (right) == AOP_CRY)
4845     {
4846       genDivbits (left, right, result);
4847       goto release;
4848     }
4849
4850   /* if both are of size == 1 */
4851   if (AOP_SIZE (left) == 1 &&
4852       AOP_SIZE (right) == 1)
4853     {
4854       genDivOneByte (left, right, result);
4855       goto release;
4856     }
4857
4858   /* should have been converted to function call */
4859   assert (0);
4860 release:
4861   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4862   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4863   freeAsmop (result, NULL, ic, TRUE);
4864 }
4865
4866 /*-----------------------------------------------------------------*/
4867 /* genModbits :- modulus of bits                                   */
4868 /*-----------------------------------------------------------------*/
4869 static void
4870 genModbits (operand * left,
4871             operand * right,
4872             operand * result)
4873 {
4874   char *l;
4875   bool pushedB;
4876
4877   D(emitcode (";     genModbits",""));
4878
4879   pushedB = pushB ();
4880
4881   /* the result must be bit */
4882   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4883   l = aopGet (left, 0, FALSE, FALSE);
4884
4885   MOVA (l);
4886
4887   emitcode ("div", "ab");
4888   emitcode ("mov", "a,b");
4889   emitcode ("rrc", "a");
4890
4891   popB (pushedB);
4892
4893   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4894 }
4895
4896 /*-----------------------------------------------------------------*/
4897 /* genModOneByte : 8 bit modulus                                   */
4898 /*-----------------------------------------------------------------*/
4899 static void
4900 genModOneByte (operand * left,
4901                operand * right,
4902                operand * result)
4903 {
4904   bool lUnsigned, rUnsigned, pushedB;
4905   bool runtimeSign, compiletimeSign;
4906   symbol *lbl;
4907   int size, offset;
4908
4909   D(emitcode (";     genModOneByte",""));
4910
4911   size = AOP_SIZE (result) - 1;
4912   offset = 1;
4913   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4914   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4915
4916   /* if right is a literal, check it for 2^n */
4917   if (AOP_TYPE(right) == AOP_LIT)
4918     {
4919       unsigned char val = abs((int) operandLitValue(right));
4920       symbol *lbl2 = NULL;
4921
4922       switch (val)
4923         {
4924           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4925           case 2:
4926           case 4:
4927           case 8:
4928           case 16:
4929           case 32:
4930           case 64:
4931           case 128:
4932             if (lUnsigned)
4933               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4934                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4935               /* because iCode should have been changed to genAnd  */
4936               /* see file "SDCCopt.c", function "convertToFcall()" */
4937
4938             MOVA (aopGet (left, 0, FALSE, FALSE));
4939             emitcode ("mov", "c,acc.7");
4940             emitcode ("anl", "a,#0x%02x", val - 1);
4941             lbl = newiTempLabel (NULL);
4942             emitcode ("jz", "%05d$", (lbl->key + 100));
4943             emitcode ("jnc", "%05d$", (lbl->key + 100));
4944             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4945             if (size)
4946               {
4947                 int size2 = size;
4948                 int offs2 = offset;
4949
4950                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4951                 while (size2--)
4952                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
4953                 lbl2 = newiTempLabel (NULL);
4954                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4955               }
4956             emitcode ("", "%05d$:", (lbl->key + 100));
4957             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4958             while (size--)
4959               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4960             if (lbl2)
4961               {
4962                 emitcode ("", "%05d$:", (lbl2->key + 100));
4963               }
4964             return;
4965
4966           default:
4967             break;
4968         }
4969     }
4970
4971   pushedB = pushB ();
4972
4973   /* signed or unsigned */
4974   if (lUnsigned && rUnsigned)
4975     {
4976       /* unsigned is easy */
4977       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4978       MOVA (aopGet (left, 0, FALSE, FALSE));
4979       emitcode ("div", "ab");
4980       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
4981       while (size--)
4982         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4983
4984       popB (pushedB);
4985       return;
4986     }
4987
4988   /* signed is a little bit more difficult */
4989
4990   /* now sign adjust for both left & right */
4991
4992   /* modulus: sign of the right operand has no influence on the result! */
4993   if (AOP_TYPE(right) == AOP_LIT)
4994     {
4995       signed char val = (char) operandLitValue(right);
4996
4997       if (!rUnsigned && val < 0)
4998         emitcode ("mov", "b,#0x%02x", -val);
4999       else
5000         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5001     }
5002   else /* not literal */
5003     {
5004       if (rUnsigned)
5005         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5006       else
5007         {
5008           MOVA (aopGet (right, 0, FALSE, FALSE));
5009           lbl = newiTempLabel (NULL);
5010           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5011           emitcode ("cpl", "a"); /* 2's complement */
5012           emitcode ("inc", "a");
5013           emitcode ("", "%05d$:", (lbl->key + 100));
5014           emitcode ("mov", "b,a");
5015         }
5016     }
5017
5018   /* let's see what's needed: */
5019   /* apply negative sign during runtime */
5020   runtimeSign = FALSE;
5021   /* negative sign from literals */
5022   compiletimeSign = FALSE;
5023
5024   /* sign adjust left side */
5025   if (AOP_TYPE(left) == AOP_LIT)
5026     {
5027       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5028
5029       if (!lUnsigned && val < 0)
5030         {
5031           compiletimeSign = TRUE; /* set sign flag */
5032           emitcode ("mov", "a,#0x%02x", -val);
5033         }
5034       else
5035         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5036     }
5037   else /* ! literal */
5038     {
5039       MOVA (aopGet (left, 0, FALSE, FALSE));
5040
5041       if (!lUnsigned)
5042         {
5043           runtimeSign = TRUE;
5044           emitcode ("clr", "F0"); /* clear sign flag */
5045
5046           lbl = newiTempLabel (NULL);
5047           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5048           emitcode ("setb", "F0"); /* set sign flag */
5049           emitcode ("cpl", "a");   /* 2's complement */
5050           emitcode ("inc", "a");
5051           emitcode ("", "%05d$:", (lbl->key + 100));
5052         }
5053     }
5054
5055   /* now the modulus */
5056   emitcode ("div", "ab");
5057
5058   if (runtimeSign || compiletimeSign)
5059     {
5060       emitcode ("mov", "a,b");
5061       lbl = newiTempLabel (NULL);
5062       if (runtimeSign)
5063         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5064       emitcode ("cpl", "a"); /* 2's complement */
5065       emitcode ("inc", "a");
5066       emitcode ("", "%05d$:", (lbl->key + 100));
5067
5068       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5069       if (size > 0)
5070         {
5071           /* msb is 0x00 or 0xff depending on the sign */
5072           if (runtimeSign)
5073             {
5074               emitcode ("mov", "c,F0");
5075               emitcode ("subb", "a,acc");
5076               while (size--)
5077                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5078             }
5079           else /* compiletimeSign */
5080             while (size--)
5081               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5082         }
5083     }
5084   else
5085     {
5086       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5087       while (size--)
5088         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5089     }
5090
5091   popB (pushedB);
5092 }
5093
5094 /*-----------------------------------------------------------------*/
5095 /* genMod - generates code for division                            */
5096 /*-----------------------------------------------------------------*/
5097 static void
5098 genMod (iCode * ic)
5099 {
5100   operand *left = IC_LEFT (ic);
5101   operand *right = IC_RIGHT (ic);
5102   operand *result = IC_RESULT (ic);
5103
5104   D(emitcode (";     genMod",""));
5105
5106   /* assign the asmops */
5107   aopOp (left, ic, FALSE);
5108   aopOp (right, ic, FALSE);
5109   aopOp (result, ic, TRUE);
5110
5111   /* special cases first */
5112   /* both are bits */
5113   if (AOP_TYPE (left) == AOP_CRY &&
5114       AOP_TYPE (right) == AOP_CRY)
5115     {
5116       genModbits (left, right, result);
5117       goto release;
5118     }
5119
5120   /* if both are of size == 1 */
5121   if (AOP_SIZE (left) == 1 &&
5122       AOP_SIZE (right) == 1)
5123     {
5124       genModOneByte (left, right, result);
5125       goto release;
5126     }
5127
5128   /* should have been converted to function call */
5129   assert (0);
5130
5131 release:
5132   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5133   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5134   freeAsmop (result, NULL, ic, TRUE);
5135 }
5136
5137 /*-----------------------------------------------------------------*/
5138 /* genIfxJump :- will create a jump depending on the ifx           */
5139 /*-----------------------------------------------------------------*/
5140 static void
5141 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5142 {
5143   symbol *jlbl;
5144   symbol *tlbl = newiTempLabel (NULL);
5145   char *inst;
5146
5147   D(emitcode (";     genIfxJump",""));
5148
5149   /* if true label then we jump if condition
5150      supplied is true */
5151   if (IC_TRUE (ic))
5152     {
5153       jlbl = IC_TRUE (ic);
5154       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5155                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5156     }
5157   else
5158     {
5159       /* false label is present */
5160       jlbl = IC_FALSE (ic);
5161       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5162                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5163     }
5164   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5165     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5166   else
5167     emitcode (inst, "%05d$", tlbl->key + 100);
5168   freeForBranchAsmop (result);
5169   freeForBranchAsmop (right);
5170   freeForBranchAsmop (left);
5171   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5172   emitcode ("", "%05d$:", tlbl->key + 100);
5173
5174   /* mark the icode as generated */
5175   ic->generated = 1;
5176 }
5177
5178 /*-----------------------------------------------------------------*/
5179 /* genCmp :- greater or less than comparison                       */
5180 /*-----------------------------------------------------------------*/
5181 static void
5182 genCmp (operand * left, operand * right,
5183         operand * result, iCode * ifx, int sign, iCode *ic)
5184 {
5185   int size, offset = 0;
5186   unsigned long lit = 0L;
5187   bool rightInB;
5188
5189   D(emitcode (";     genCmp",""));
5190
5191   /* if left & right are bit variables */
5192   if (AOP_TYPE (left) == AOP_CRY &&
5193       AOP_TYPE (right) == AOP_CRY)
5194     {
5195       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5196       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5197     }
5198   else
5199     {
5200       /* subtract right from left if at the
5201          end the carry flag is set then we know that
5202          left is greater than right */
5203       size = max (AOP_SIZE (left), AOP_SIZE (right));
5204
5205       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5206       if ((size == 1) && !sign &&
5207           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5208         {
5209           symbol *lbl = newiTempLabel (NULL);
5210           emitcode ("cjne", "%s,%s,%05d$",
5211                     aopGet (left, offset, FALSE, FALSE),
5212                     aopGet (right, offset, FALSE, FALSE),
5213                     lbl->key + 100);
5214           emitcode ("", "%05d$:", lbl->key + 100);
5215         }
5216       else
5217         {
5218           if (AOP_TYPE (right) == AOP_LIT)
5219             {
5220               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5221               /* optimize if(x < 0) or if(x >= 0) */
5222               if (lit == 0L)
5223                 {
5224                   if (!sign)
5225                     {
5226                       CLRC;
5227                     }
5228                   else
5229                     {
5230                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5231                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5232                         {
5233                           genIfxJump (ifx, "acc.7", left, right, result);
5234                           freeAsmop (right, NULL, ic, TRUE);
5235                           freeAsmop (left, NULL, ic, TRUE);
5236
5237                           return;
5238                         }
5239                       else
5240                         emitcode ("rlc", "a");
5241                     }
5242                   goto release;
5243                 }
5244             }
5245           CLRC;
5246           while (size--)
5247             {
5248               bool pushedB = FALSE;
5249               rightInB = aopGetUsesAcc(right, offset);
5250               if (rightInB)
5251                 {
5252                   pushedB = pushB ();
5253                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5254                 }
5255               MOVA (aopGet (left, offset, FALSE, FALSE));
5256               if (sign && size == 0)
5257                 {
5258                   emitcode ("xrl", "a,#0x80");
5259                   if (AOP_TYPE (right) == AOP_LIT)
5260                     {
5261                       unsigned long lit = (unsigned long)
5262                       floatFromVal (AOP (right)->aopu.aop_lit);
5263                       emitcode ("subb", "a,#0x%02x",
5264                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5265                     }
5266                   else
5267                     {
5268                       if (!rightInB)
5269                         {
5270                           pushedB = pushB ();
5271                           rightInB++;
5272                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5273                         }
5274                       emitcode ("xrl", "b,#0x80");
5275                       emitcode ("subb", "a,b");
5276                     }
5277                 }
5278               else
5279                 {
5280                   if (rightInB)
5281                     emitcode ("subb", "a,b");
5282                   else
5283                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5284                 }
5285               if (rightInB)
5286                 popB (pushedB);
5287               offset++;
5288             }
5289         }
5290     }
5291
5292 release:
5293   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5294   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5295   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5296     {
5297       outBitC (result);
5298     }
5299   else
5300     {
5301       /* if the result is used in the next
5302          ifx conditional branch then generate
5303          code a little differently */
5304       if (ifx)
5305         genIfxJump (ifx, "c", NULL, NULL, result);
5306       else
5307         outBitC (result);
5308       /* leave the result in acc */
5309     }
5310 }
5311
5312 /*-----------------------------------------------------------------*/
5313 /* genCmpGt :- greater than comparison                             */
5314 /*-----------------------------------------------------------------*/
5315 static void
5316 genCmpGt (iCode * ic, iCode * ifx)
5317 {
5318   operand *left, *right, *result;
5319   sym_link *letype, *retype;
5320   int sign;
5321
5322   D(emitcode (";     genCmpGt",""));
5323
5324   left = IC_LEFT (ic);
5325   right = IC_RIGHT (ic);
5326   result = IC_RESULT (ic);
5327
5328   letype = getSpec (operandType (left));
5329   retype = getSpec (operandType (right));
5330   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5331            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5332   /* assign the amsops */
5333   aopOp (left, ic, FALSE);
5334   aopOp (right, ic, FALSE);
5335   aopOp (result, ic, TRUE);
5336
5337   genCmp (right, left, result, ifx, sign, ic);
5338
5339   freeAsmop (result, NULL, ic, TRUE);
5340 }
5341
5342 /*-----------------------------------------------------------------*/
5343 /* genCmpLt - less than comparisons                                */
5344 /*-----------------------------------------------------------------*/
5345 static void
5346 genCmpLt (iCode * ic, iCode * ifx)
5347 {
5348   operand *left, *right, *result;
5349   sym_link *letype, *retype;
5350   int sign;
5351
5352   D(emitcode (";     genCmpLt",""));
5353
5354   left = IC_LEFT (ic);
5355   right = IC_RIGHT (ic);
5356   result = IC_RESULT (ic);
5357
5358   letype = getSpec (operandType (left));
5359   retype = getSpec (operandType (right));
5360   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5361            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5362   /* assign the amsops */
5363   aopOp (left, ic, FALSE);
5364   aopOp (right, ic, FALSE);
5365   aopOp (result, ic, TRUE);
5366
5367   genCmp (left, right, result, ifx, sign,ic);
5368
5369   freeAsmop (result, NULL, ic, TRUE);
5370 }
5371
5372 /*-----------------------------------------------------------------*/
5373 /* gencjneshort - compare and jump if not equal                    */
5374 /*-----------------------------------------------------------------*/
5375 static void
5376 gencjneshort (operand * left, operand * right, symbol * lbl)
5377 {
5378   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5379   int offset = 0;
5380   unsigned long lit = 0L;
5381
5382   /* if the left side is a literal or
5383      if the right is in a pointer register and left
5384      is not */
5385   if ((AOP_TYPE (left) == AOP_LIT) ||
5386       (AOP_TYPE (left) == AOP_IMMD) ||
5387       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5388     {
5389       operand *t = right;
5390       right = left;
5391       left = t;
5392     }
5393
5394   if (AOP_TYPE (right) == AOP_LIT)
5395     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5396
5397   /* if the right side is a literal then anything goes */
5398   if (AOP_TYPE (right) == AOP_LIT &&
5399       AOP_TYPE (left) != AOP_DIR  &&
5400       AOP_TYPE (left) != AOP_IMMD)
5401     {
5402       while (size--)
5403         {
5404           emitcode ("cjne", "%s,%s,%05d$",
5405                     aopGet (left, offset, FALSE, FALSE),
5406                     aopGet (right, offset, FALSE, FALSE),
5407                     lbl->key + 100);
5408           offset++;
5409         }
5410     }
5411
5412   /* if the right side is in a register or in direct space or
5413      if the left is a pointer register & right is not */
5414   else if (AOP_TYPE (right) == AOP_REG ||
5415            AOP_TYPE (right) == AOP_DIR ||
5416            AOP_TYPE (right) == AOP_LIT ||
5417            AOP_TYPE (right) == AOP_IMMD ||
5418            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5419            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5420     {
5421       while (size--)
5422         {
5423           MOVA (aopGet (left, offset, FALSE, FALSE));
5424           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5425               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5426             emitcode ("jnz", "%05d$", lbl->key + 100);
5427           else
5428             emitcode ("cjne", "a,%s,%05d$",
5429                       aopGet (right, offset, FALSE, TRUE),
5430                       lbl->key + 100);
5431           offset++;
5432         }
5433     }
5434   else
5435     {
5436       /* right is a pointer reg need both a & b */
5437       while (size--)
5438         {
5439           char *l;
5440           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5441           wassertl(!BINUSE, "B was in use");
5442           l = aopGet (left, offset, FALSE, FALSE);
5443           if (strcmp (l, "b"))
5444             emitcode ("mov", "b,%s", l);
5445           MOVA (aopGet (right, offset, FALSE, FALSE));
5446           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5447           offset++;
5448         }
5449     }
5450 }
5451
5452 /*-----------------------------------------------------------------*/
5453 /* gencjne - compare and jump if not equal                         */
5454 /*-----------------------------------------------------------------*/
5455 static void
5456 gencjne (operand * left, operand * right, symbol * lbl)
5457 {
5458   symbol *tlbl = newiTempLabel (NULL);
5459
5460   gencjneshort (left, right, lbl);
5461
5462   emitcode ("mov", "a,%s", one);
5463   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5464   emitcode ("", "%05d$:", lbl->key + 100);
5465   emitcode ("clr", "a");
5466   emitcode ("", "%05d$:", tlbl->key + 100);
5467 }
5468
5469 /*-----------------------------------------------------------------*/
5470 /* genCmpEq - generates code for equal to                          */
5471 /*-----------------------------------------------------------------*/
5472 static void
5473 genCmpEq (iCode * ic, iCode * ifx)
5474 {
5475   operand *left, *right, *result;
5476
5477   D(emitcode (";     genCmpEq",""));
5478
5479   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5480   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5481   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5482
5483   /* if literal, literal on the right or
5484      if the right is in a pointer register and left
5485      is not */
5486   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5487       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5488     {
5489       operand *t = IC_RIGHT (ic);
5490       IC_RIGHT (ic) = IC_LEFT (ic);
5491       IC_LEFT (ic) = t;
5492     }
5493
5494   if (ifx && !AOP_SIZE (result))
5495     {
5496       symbol *tlbl;
5497       /* if they are both bit variables */
5498       if (AOP_TYPE (left) == AOP_CRY &&
5499           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5500         {
5501           if (AOP_TYPE (right) == AOP_LIT)
5502             {
5503               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5504               if (lit == 0L)
5505                 {
5506                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5507                   emitcode ("cpl", "c");
5508                 }
5509               else if (lit == 1L)
5510                 {
5511                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5512                 }
5513               else
5514                 {
5515                   emitcode ("clr", "c");
5516                 }
5517               /* AOP_TYPE(right) == AOP_CRY */
5518             }
5519           else
5520             {
5521               symbol *lbl = newiTempLabel (NULL);
5522               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5523               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5524               emitcode ("cpl", "c");
5525               emitcode ("", "%05d$:", (lbl->key + 100));
5526             }
5527           /* if true label then we jump if condition
5528              supplied is true */
5529           tlbl = newiTempLabel (NULL);
5530           if (IC_TRUE (ifx))
5531             {
5532               emitcode ("jnc", "%05d$", tlbl->key + 100);
5533               freeForBranchAsmop (result);
5534               freeForBranchAsmop (right);
5535               freeForBranchAsmop (left);
5536               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5537             }
5538           else
5539             {
5540               emitcode ("jc", "%05d$", tlbl->key + 100);
5541               freeForBranchAsmop (result);
5542               freeForBranchAsmop (right);
5543               freeForBranchAsmop (left);
5544               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5545             }
5546           emitcode ("", "%05d$:", tlbl->key + 100);
5547         }
5548       else
5549         {
5550           tlbl = newiTempLabel (NULL);
5551           gencjneshort (left, right, tlbl);
5552           if (IC_TRUE (ifx))
5553             {
5554               freeForBranchAsmop (result);
5555               freeForBranchAsmop (right);
5556               freeForBranchAsmop (left);
5557               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5558               emitcode ("", "%05d$:", tlbl->key + 100);
5559             }
5560           else
5561             {
5562               symbol *lbl = newiTempLabel (NULL);
5563               emitcode ("sjmp", "%05d$", lbl->key + 100);
5564               emitcode ("", "%05d$:", tlbl->key + 100);
5565               freeForBranchAsmop (result);
5566               freeForBranchAsmop (right);
5567               freeForBranchAsmop (left);
5568               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5569               emitcode ("", "%05d$:", lbl->key + 100);
5570             }
5571         }
5572       /* mark the icode as generated */
5573       ifx->generated = 1;
5574       goto release;
5575     }
5576
5577   /* if they are both bit variables */
5578   if (AOP_TYPE (left) == AOP_CRY &&
5579       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5580     {
5581       if (AOP_TYPE (right) == AOP_LIT)
5582         {
5583           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5584           if (lit == 0L)
5585             {
5586               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5587               emitcode ("cpl", "c");
5588             }
5589           else if (lit == 1L)
5590             {
5591               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5592             }
5593           else
5594             {
5595               emitcode ("clr", "c");
5596             }
5597           /* AOP_TYPE(right) == AOP_CRY */
5598         }
5599       else
5600         {
5601           symbol *lbl = newiTempLabel (NULL);
5602           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5603           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5604           emitcode ("cpl", "c");
5605           emitcode ("", "%05d$:", (lbl->key + 100));
5606         }
5607       /* c = 1 if egal */
5608       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5609         {
5610           outBitC (result);
5611           goto release;
5612         }
5613       if (ifx)
5614         {
5615           genIfxJump (ifx, "c", left, right, result);
5616           goto release;
5617         }
5618       /* if the result is used in an arithmetic operation
5619          then put the result in place */
5620       outBitC (result);
5621     }
5622   else
5623     {
5624       gencjne (left, right, newiTempLabel (NULL));
5625       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5626         {
5627           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5628           goto release;
5629         }
5630       if (ifx)
5631         {
5632           genIfxJump (ifx, "a", left, right, result);
5633           goto release;
5634         }
5635       /* if the result is used in an arithmetic operation
5636          then put the result in place */
5637       if (AOP_TYPE (result) != AOP_CRY)
5638         outAcc (result);
5639       /* leave the result in acc */
5640     }
5641
5642 release:
5643   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5644   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5645   freeAsmop (result, NULL, ic, TRUE);
5646 }
5647
5648 /*-----------------------------------------------------------------*/
5649 /* ifxForOp - returns the icode containing the ifx for operand     */
5650 /*-----------------------------------------------------------------*/
5651 static iCode *
5652 ifxForOp (operand * op, iCode * ic)
5653 {
5654   /* if true symbol then needs to be assigned */
5655   if (IS_TRUE_SYMOP (op))
5656     return NULL;
5657
5658   /* if this has register type condition and
5659      the next instruction is ifx with the same operand
5660      and live to of the operand is upto the ifx only then */
5661   if (ic->next &&
5662       ic->next->op == IFX &&
5663       IC_COND (ic->next)->key == op->key &&
5664       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5665     return ic->next;
5666
5667   return NULL;
5668 }
5669
5670 /*-----------------------------------------------------------------*/
5671 /* hasInc - operand is incremented before any other use            */
5672 /*-----------------------------------------------------------------*/
5673 static iCode *
5674 hasInc (operand *op, iCode *ic,int osize)
5675 {
5676   sym_link *type = operandType(op);
5677   sym_link *retype = getSpec (type);
5678   iCode *lic = ic->next;
5679   int isize ;
5680
5681   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5682   if (!IS_SYMOP(op)) return NULL;
5683
5684   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5685   if (IS_AGGREGATE(type->next)) return NULL;
5686   if (osize != (isize = getSize(type->next))) return NULL;
5687
5688   while (lic) {
5689     /* if operand of the form op = op + <sizeof *op> */
5690     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5691         isOperandEqual(IC_RESULT(lic),op) &&
5692         isOperandLiteral(IC_RIGHT(lic)) &&
5693         operandLitValue(IC_RIGHT(lic)) == isize) {
5694       return lic;
5695     }
5696     /* if the operand used or deffed */
5697     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5698       return NULL;
5699     }
5700     /* if GOTO or IFX */
5701     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5702     lic = lic->next;
5703   }
5704   return NULL;
5705 }
5706
5707 /*-----------------------------------------------------------------*/
5708 /* genAndOp - for && operation                                     */
5709 /*-----------------------------------------------------------------*/
5710 static void
5711 genAndOp (iCode * ic)
5712 {
5713   operand *left, *right, *result;
5714   symbol *tlbl;
5715
5716   D(emitcode (";     genAndOp",""));
5717
5718   /* note here that && operations that are in an
5719      if statement are taken away by backPatchLabels
5720      only those used in arthmetic operations remain */
5721   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5722   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5723   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5724
5725   /* if both are bit variables */
5726   if (AOP_TYPE (left) == AOP_CRY &&
5727       AOP_TYPE (right) == AOP_CRY)
5728     {
5729       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5730       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5731       outBitC (result);
5732     }
5733   else
5734     {
5735       tlbl = newiTempLabel (NULL);
5736       toBoolean (left);
5737       emitcode ("jz", "%05d$", tlbl->key + 100);
5738       toBoolean (right);
5739       emitcode ("", "%05d$:", tlbl->key + 100);
5740       outBitAcc (result);
5741     }
5742
5743   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5744   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5745   freeAsmop (result, NULL, ic, TRUE);
5746 }
5747
5748
5749 /*-----------------------------------------------------------------*/
5750 /* genOrOp - for || operation                                      */
5751 /*-----------------------------------------------------------------*/
5752 static void
5753 genOrOp (iCode * ic)
5754 {
5755   operand *left, *right, *result;
5756   symbol *tlbl;
5757
5758   D(emitcode (";     genOrOp",""));
5759
5760   /* note here that || operations that are in an
5761      if statement are taken away by backPatchLabels
5762      only those used in arthmetic operations remain */
5763   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5764   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5765   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5766
5767   /* if both are bit variables */
5768   if (AOP_TYPE (left) == AOP_CRY &&
5769       AOP_TYPE (right) == AOP_CRY)
5770     {
5771       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5772       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5773       outBitC (result);
5774     }
5775   else
5776     {
5777       tlbl = newiTempLabel (NULL);
5778       toBoolean (left);
5779       emitcode ("jnz", "%05d$", tlbl->key + 100);
5780       toBoolean (right);
5781       emitcode ("", "%05d$:", tlbl->key + 100);
5782       outBitAcc (result);
5783     }
5784
5785   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5786   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5787   freeAsmop (result, NULL, ic, TRUE);
5788 }
5789
5790 /*-----------------------------------------------------------------*/
5791 /* isLiteralBit - test if lit == 2^n                               */
5792 /*-----------------------------------------------------------------*/
5793 static int
5794 isLiteralBit (unsigned long lit)
5795 {
5796   unsigned long pw[32] =
5797   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5798    0x100L, 0x200L, 0x400L, 0x800L,
5799    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5800    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5801    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5802    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5803    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5804   int idx;
5805
5806   for (idx = 0; idx < 32; idx++)
5807     if (lit == pw[idx])
5808       return idx + 1;
5809   return 0;
5810 }
5811
5812 /*-----------------------------------------------------------------*/
5813 /* continueIfTrue -                                                */
5814 /*-----------------------------------------------------------------*/
5815 static void
5816 continueIfTrue (iCode * ic)
5817 {
5818   if (IC_TRUE (ic))
5819     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5820   ic->generated = 1;
5821 }
5822
5823 /*-----------------------------------------------------------------*/
5824 /* jmpIfTrue -                                                     */
5825 /*-----------------------------------------------------------------*/
5826 static void
5827 jumpIfTrue (iCode * ic)
5828 {
5829   if (!IC_TRUE (ic))
5830     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5831   ic->generated = 1;
5832 }
5833
5834 /*-----------------------------------------------------------------*/
5835 /* jmpTrueOrFalse -                                                */
5836 /*-----------------------------------------------------------------*/
5837 static void
5838 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5839 {
5840   // ugly but optimized by peephole
5841   if (IC_TRUE (ic))
5842     {
5843       symbol *nlbl = newiTempLabel (NULL);
5844       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5845       emitcode ("", "%05d$:", tlbl->key + 100);
5846       freeForBranchAsmop (result);
5847       freeForBranchAsmop (right);
5848       freeForBranchAsmop (left);
5849       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5850       emitcode ("", "%05d$:", nlbl->key + 100);
5851     }
5852   else
5853     {
5854       freeForBranchAsmop (result);
5855       freeForBranchAsmop (right);
5856       freeForBranchAsmop (left);
5857       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5858       emitcode ("", "%05d$:", tlbl->key + 100);
5859     }
5860   ic->generated = 1;
5861 }
5862
5863 /*-----------------------------------------------------------------*/
5864 /* genAnd  - code for and                                          */
5865 /*-----------------------------------------------------------------*/
5866 static void
5867 genAnd (iCode * ic, iCode * ifx)
5868 {
5869   operand *left, *right, *result;
5870   int size, offset = 0;
5871   unsigned long lit = 0L;
5872   int bytelit = 0;
5873   char buffer[10];
5874
5875   D(emitcode (";     genAnd",""));
5876
5877   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5878   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5879   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5880
5881 #ifdef DEBUG_TYPE
5882   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5883             AOP_TYPE (result),
5884             AOP_TYPE (left), AOP_TYPE (right));
5885   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5886             AOP_SIZE (result),
5887             AOP_SIZE (left), AOP_SIZE (right));
5888 #endif
5889
5890   /* if left is a literal & right is not then exchange them */
5891   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5892       AOP_NEEDSACC (left))
5893     {
5894       operand *tmp = right;
5895       right = left;
5896       left = tmp;
5897     }
5898
5899   /* if result = right then exchange left and right */
5900   if (sameRegs (AOP (result), AOP (right)))
5901     {
5902       operand *tmp = right;
5903       right = left;
5904       left = tmp;
5905     }
5906
5907   /* if right is bit then exchange them */
5908   if (AOP_TYPE (right) == AOP_CRY &&
5909       AOP_TYPE (left) != AOP_CRY)
5910     {
5911       operand *tmp = right;
5912       right = left;
5913       left = tmp;
5914     }
5915   if (AOP_TYPE (right) == AOP_LIT)
5916     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5917
5918   size = AOP_SIZE (result);
5919
5920   // if(bit & yy)
5921   // result = bit & yy;
5922   if (AOP_TYPE (left) == AOP_CRY)
5923     {
5924       // c = bit & literal;
5925       if (AOP_TYPE (right) == AOP_LIT)
5926         {
5927           if (lit & 1)
5928             {
5929               if (size && sameRegs (AOP (result), AOP (left)))
5930                 // no change
5931                 goto release;
5932               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5933             }
5934           else
5935             {
5936               // bit(result) = 0;
5937               if (size && (AOP_TYPE (result) == AOP_CRY))
5938                 {
5939                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5940                   goto release;
5941                 }
5942               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5943                 {
5944                   jumpIfTrue (ifx);
5945                   goto release;
5946                 }
5947               emitcode ("clr", "c");
5948             }
5949         }
5950       else
5951         {
5952           if (AOP_TYPE (right) == AOP_CRY)
5953             {
5954               // c = bit & bit;
5955               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5956               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5957             }
5958           else
5959             {
5960               // c = bit & val;
5961               MOVA (aopGet (right, 0, FALSE, FALSE));
5962               // c = lsb
5963               emitcode ("rrc", "a");
5964               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5965             }
5966         }
5967       // bit = c
5968       // val = c
5969       if (size)
5970         outBitC (result);
5971       // if(bit & ...)
5972       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5973         genIfxJump (ifx, "c", left, right, result);
5974       goto release;
5975     }
5976
5977   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5978   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5979   if ((AOP_TYPE (right) == AOP_LIT) &&
5980       (AOP_TYPE (result) == AOP_CRY) &&
5981       (AOP_TYPE (left) != AOP_CRY))
5982     {
5983       int posbit = isLiteralBit (lit);
5984       /* left &  2^n */
5985       if (posbit)
5986         {
5987           posbit--;
5988           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
5989           // bit = left & 2^n
5990           if (size)
5991             {
5992               switch (posbit & 0x07)
5993                 {
5994                   case 0: emitcode ("rrc", "a");
5995                           break;
5996                   case 7: emitcode ("rlc", "a");
5997                           break;
5998                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5999                           break;
6000                 }
6001             }
6002           // if(left &  2^n)
6003           else
6004             {
6005               if (ifx)
6006                 {
6007                   SNPRINTF (buffer, sizeof(buffer),
6008                             "acc.%d", posbit & 0x07);
6009                   genIfxJump (ifx, buffer, left, right, result);
6010                 }
6011               else
6012                 {// what is this case? just found it in ds390/gen.c
6013                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6014                 }
6015               goto release;
6016             }
6017         }
6018       else
6019         {
6020           symbol *tlbl = newiTempLabel (NULL);
6021           int sizel = AOP_SIZE (left);
6022           if (size)
6023             emitcode ("setb", "c");
6024           while (sizel--)
6025             {
6026               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6027                 {
6028                   MOVA (aopGet (left, offset, FALSE, FALSE));
6029                   // byte ==  2^n ?
6030                   if ((posbit = isLiteralBit (bytelit)) != 0)
6031                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6032                   else
6033                     {
6034                       if (bytelit != 0x0FFL)
6035                         emitcode ("anl", "a,%s",
6036                                   aopGet (right, offset, FALSE, TRUE));
6037                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6038                     }
6039                 }
6040               offset++;
6041             }
6042           // bit = left & literal
6043           if (size)
6044             {
6045               emitcode ("clr", "c");
6046               emitcode ("", "%05d$:", tlbl->key + 100);
6047             }
6048           // if(left & literal)
6049           else
6050             {
6051               if (ifx)
6052                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6053               else
6054                 emitcode ("", "%05d$:", tlbl->key + 100);
6055               goto release;
6056             }
6057         }
6058       outBitC (result);
6059       goto release;
6060     }
6061
6062   /* if left is same as result */
6063   if (sameRegs (AOP (result), AOP (left)))
6064     {
6065       for (; size--; offset++)
6066         {
6067           if (AOP_TYPE (right) == AOP_LIT)
6068             {
6069               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6070               if (bytelit == 0x0FF)
6071                 {
6072                   /* dummy read of volatile operand */
6073                   if (isOperandVolatile (left, FALSE))
6074                     MOVA (aopGet (left, offset, FALSE, FALSE));
6075                   else
6076                     continue;
6077                 }
6078               else if (bytelit == 0)
6079                 {
6080                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6081                 }
6082               else if (IS_AOP_PREG (result))
6083                 {
6084                   MOVA (aopGet (left, offset, FALSE, TRUE));
6085                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6086                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6087                 }
6088               else
6089                 emitcode ("anl", "%s,%s",
6090                           aopGet (left, offset, FALSE, TRUE),
6091                           aopGet (right, offset, FALSE, FALSE));
6092             }
6093           else
6094             {
6095               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
6096                 {
6097                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6098                 }
6099               else
6100                 {
6101                   MOVA (aopGet (right, offset, FALSE, FALSE));
6102                   if (IS_AOP_PREG (result))
6103                     {
6104                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6105                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6106                     }
6107                   else
6108                     emitcode ("anl", "%s,a",
6109                               aopGet (left, offset, FALSE, TRUE));
6110                 }
6111             }
6112         }
6113     }
6114   else
6115     {
6116       // left & result in different registers
6117       if (AOP_TYPE (result) == AOP_CRY)
6118         {
6119           // result = bit
6120           // if(size), result in bit
6121           // if(!size && ifx), conditional oper: if(left & right)
6122           symbol *tlbl = newiTempLabel (NULL);
6123           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6124           if (size)
6125             emitcode ("setb", "c");
6126           while (sizer--)
6127             {
6128               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6129                   && AOP_TYPE(left)==AOP_ACC)
6130                 {
6131                   if (offset)
6132                     emitcode("mov", "a,b");
6133                   emitcode ("anl", "a,%s",
6134                             aopGet (right, offset, FALSE, FALSE));
6135                 } else {
6136                   if (AOP_TYPE(left)==AOP_ACC)
6137                     {
6138                       if (!offset)
6139                         {
6140                           bool pushedB = pushB ();
6141                           emitcode("mov", "b,a");
6142                           MOVA (aopGet (right, offset, FALSE, FALSE));
6143                           emitcode("anl", "a,b");
6144                           popB (pushedB);
6145                         }
6146                       else
6147                         {
6148                           MOVA (aopGet (right, offset, FALSE, FALSE));
6149                           emitcode("anl", "a,b");
6150                         }
6151                 } else {
6152                       MOVA (aopGet (right, offset, FALSE, FALSE));
6153                   emitcode ("anl", "a,%s",
6154                                 aopGet (left, offset, FALSE, FALSE));
6155                 }
6156               }
6157               emitcode ("jnz", "%05d$", tlbl->key + 100);
6158               offset++;
6159             }
6160           if (size)
6161             {
6162               CLRC;
6163               emitcode ("", "%05d$:", tlbl->key + 100);
6164               outBitC (result);
6165             }
6166           else if (ifx)
6167             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6168           else
6169             emitcode ("", "%05d$:", tlbl->key + 100);
6170         }
6171       else
6172         {
6173           for (; (size--); offset++)
6174             {
6175               // normal case
6176               // result = left & right
6177               if (AOP_TYPE (right) == AOP_LIT)
6178                 {
6179                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6180                   if (bytelit == 0x0FF)
6181                     {
6182                       aopPut (result,
6183                               aopGet (left, offset, FALSE, FALSE),
6184                               offset,
6185                               isOperandVolatile (result, FALSE));
6186                       continue;
6187                     }
6188                   else if (bytelit == 0)
6189                     {
6190                       /* dummy read of volatile operand */
6191                       if (isOperandVolatile (left, FALSE))
6192                         MOVA (aopGet (left, offset, FALSE, FALSE));
6193                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6194                       continue;
6195                     }
6196                   else if (AOP_TYPE (left) == AOP_ACC)
6197                     {
6198                       if (!offset)
6199                         {
6200                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6201                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6202                           continue;
6203                         }
6204                       else
6205                         {
6206                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6207                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6208                           continue;
6209                         }
6210                     }
6211                 }
6212               // faster than result <- left, anl result,right
6213               // and better if result is SFR
6214               if (AOP_TYPE (left) == AOP_ACC)
6215                 {
6216                   if (offset)
6217                     emitcode("mov", "a,b");
6218                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6219                 }
6220               else
6221                 {
6222                   MOVA (aopGet (right, offset, FALSE, FALSE));
6223                   emitcode ("anl", "a,%s",
6224                             aopGet (left, offset, FALSE, FALSE));
6225                 }
6226               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6227             }
6228         }
6229     }
6230
6231 release:
6232   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6233   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6234   freeAsmop (result, NULL, ic, TRUE);
6235 }
6236
6237 /*-----------------------------------------------------------------*/
6238 /* genOr  - code for or                                            */
6239 /*-----------------------------------------------------------------*/
6240 static void
6241 genOr (iCode * ic, iCode * ifx)
6242 {
6243   operand *left, *right, *result;
6244   int size, offset = 0;
6245   unsigned long lit = 0L;
6246   int bytelit = 0;
6247
6248   D(emitcode (";     genOr",""));
6249
6250   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6251   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6252   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6253
6254 #ifdef DEBUG_TYPE
6255   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6256             AOP_TYPE (result),
6257             AOP_TYPE (left), AOP_TYPE (right));
6258   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6259             AOP_SIZE (result),
6260             AOP_SIZE (left), AOP_SIZE (right));
6261 #endif
6262
6263   /* if left is a literal & right is not then exchange them */
6264   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6265       AOP_NEEDSACC (left))
6266     {
6267       operand *tmp = right;
6268       right = left;
6269       left = tmp;
6270     }
6271
6272   /* if result = right then exchange them */
6273   if (sameRegs (AOP (result), AOP (right)))
6274     {
6275       operand *tmp = right;
6276       right = left;
6277       left = tmp;
6278     }
6279
6280   /* if right is bit then exchange them */
6281   if (AOP_TYPE (right) == AOP_CRY &&
6282       AOP_TYPE (left) != AOP_CRY)
6283     {
6284       operand *tmp = right;
6285       right = left;
6286       left = tmp;
6287     }
6288   if (AOP_TYPE (right) == AOP_LIT)
6289     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6290
6291   size = AOP_SIZE (result);
6292
6293   // if(bit | yy)
6294   // xx = bit | yy;
6295   if (AOP_TYPE (left) == AOP_CRY)
6296     {
6297       if (AOP_TYPE (right) == AOP_LIT)
6298         {
6299           // c = bit | literal;
6300           if (lit)
6301             {
6302               // lit != 0 => result = 1
6303               if (AOP_TYPE (result) == AOP_CRY)
6304                 {
6305                   if (size)
6306                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6307                   else if (ifx)
6308                     continueIfTrue (ifx);
6309                   goto release;
6310                 }
6311               emitcode ("setb", "c");
6312             }
6313           else
6314             {
6315               // lit == 0 => result = left
6316               if (size && sameRegs (AOP (result), AOP (left)))
6317                 goto release;
6318               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6319             }
6320         }
6321       else
6322         {
6323           if (AOP_TYPE (right) == AOP_CRY)
6324             {
6325               // c = bit | bit;
6326               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6327               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6328             }
6329           else
6330             {
6331               // c = bit | val;
6332               symbol *tlbl = newiTempLabel (NULL);
6333               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6334                 emitcode ("setb", "c");
6335               emitcode ("jb", "%s,%05d$",
6336                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6337               toBoolean (right);
6338               emitcode ("jnz", "%05d$", tlbl->key + 100);
6339               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6340                 {
6341                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6342                   goto release;
6343                 }
6344               else
6345                 {
6346                   CLRC;
6347                   emitcode ("", "%05d$:", tlbl->key + 100);
6348                 }
6349             }
6350         }
6351       // bit = c
6352       // val = c
6353       if (size)
6354         outBitC (result);
6355       // if(bit | ...)
6356       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6357         genIfxJump (ifx, "c", left, right, result);
6358       goto release;
6359     }
6360
6361   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6362   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6363   if ((AOP_TYPE (right) == AOP_LIT) &&
6364       (AOP_TYPE (result) == AOP_CRY) &&
6365       (AOP_TYPE (left) != AOP_CRY))
6366     {
6367       if (lit)
6368         {
6369           // result = 1
6370           if (size)
6371             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6372           else
6373             continueIfTrue (ifx);
6374           goto release;
6375         }
6376       else
6377         {
6378           // lit = 0, result = boolean(left)
6379           if (size)
6380             emitcode ("setb", "c");
6381           toBoolean (right);
6382           if (size)
6383             {
6384               symbol *tlbl = newiTempLabel (NULL);
6385               emitcode ("jnz", "%05d$", tlbl->key + 100);
6386               CLRC;
6387               emitcode ("", "%05d$:", tlbl->key + 100);
6388             }
6389           else
6390             {
6391               genIfxJump (ifx, "a", left, right, result);
6392               goto release;
6393             }
6394         }
6395       outBitC (result);
6396       goto release;
6397     }
6398
6399   /* if left is same as result */
6400   if (sameRegs (AOP (result), AOP (left)))
6401     {
6402       for (; size--; offset++)
6403         {
6404           if (AOP_TYPE (right) == AOP_LIT)
6405             {
6406               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6407               if (bytelit == 0)
6408                 {
6409                   /* dummy read of volatile operand */
6410                   if (isOperandVolatile (left, FALSE))
6411                     MOVA (aopGet (left, offset, FALSE, FALSE));
6412                   else
6413                     continue;
6414                 }
6415               else if (bytelit == 0x0FF)
6416                 {
6417                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6418                 }
6419               else if (IS_AOP_PREG (left))
6420                 {
6421                   MOVA (aopGet (left, offset, FALSE, TRUE));
6422                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6423                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6424                 }
6425               else
6426                 {
6427                   emitcode ("orl", "%s,%s",
6428                             aopGet (left, offset, FALSE, TRUE),
6429                             aopGet (right, offset, FALSE, FALSE));
6430                 }
6431             }
6432           else
6433             {
6434               if (AOP_TYPE (left) == AOP_ACC)
6435                 {
6436                   if (offset)
6437                     emitcode("mov", "a,b");
6438                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6439                 }
6440               else
6441                 {
6442                   MOVA (aopGet (right, offset, FALSE, FALSE));
6443                   if (IS_AOP_PREG (left))
6444                     {
6445                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6446                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6447                     }
6448                   else
6449                     {
6450                       emitcode ("orl", "%s,a",
6451                                 aopGet (left, offset, FALSE, TRUE));
6452                     }
6453                 }
6454             }
6455         }
6456     }
6457   else
6458     {
6459       // left & result in different registers
6460       if (AOP_TYPE (result) == AOP_CRY)
6461         {
6462           // result = bit
6463           // if(size), result in bit
6464           // if(!size && ifx), conditional oper: if(left | right)
6465           symbol *tlbl = newiTempLabel (NULL);
6466           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6467           if (size)
6468             emitcode ("setb", "c");
6469           while (sizer--)
6470             {
6471               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6472                 if (offset)
6473                   emitcode("mov", "a,b");
6474                 emitcode ("orl", "a,%s",
6475                           aopGet (right, offset, FALSE, FALSE));
6476               } else {
6477                 MOVA (aopGet (right, offset, FALSE, FALSE));
6478                 emitcode ("orl", "a,%s",
6479                           aopGet (left, offset, FALSE, FALSE));
6480               }
6481               emitcode ("jnz", "%05d$", tlbl->key + 100);
6482               offset++;
6483             }
6484           if (size)
6485             {
6486               CLRC;
6487               emitcode ("", "%05d$:", tlbl->key + 100);
6488               outBitC (result);
6489             }
6490           else if (ifx)
6491             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6492           else
6493             emitcode ("", "%05d$:", tlbl->key + 100);
6494         }
6495       else
6496         {
6497           for (; (size--); offset++)
6498             {
6499               // normal case
6500               // result = left | right
6501               if (AOP_TYPE (right) == AOP_LIT)
6502                 {
6503                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6504                   if (bytelit == 0)
6505                     {
6506                       aopPut (result,
6507                               aopGet (left, offset, FALSE, FALSE),
6508                               offset,
6509                               isOperandVolatile (result, FALSE));
6510                       continue;
6511                     }
6512                   else if (bytelit == 0x0FF)
6513                     {
6514                       /* dummy read of volatile operand */
6515                       if (isOperandVolatile (left, FALSE))
6516                         MOVA (aopGet (left, offset, FALSE, FALSE));
6517                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6518                       continue;
6519                     }
6520                 }
6521               // faster than result <- left, anl result,right
6522               // and better if result is SFR
6523               if (AOP_TYPE (left) == AOP_ACC)
6524                 {
6525                   if (offset)
6526                     emitcode("mov", "a,b");
6527                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6528                 }
6529               else
6530                 {
6531                   MOVA (aopGet (right, offset, FALSE, FALSE));
6532                   emitcode ("orl", "a,%s",
6533                             aopGet (left, offset, FALSE, FALSE));
6534                 }
6535               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6536             }
6537         }
6538     }
6539
6540 release:
6541   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6542   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6543   freeAsmop (result, NULL, ic, TRUE);
6544 }
6545
6546 /*-----------------------------------------------------------------*/
6547 /* genXor - code for xclusive or                                   */
6548 /*-----------------------------------------------------------------*/
6549 static void
6550 genXor (iCode * ic, iCode * ifx)
6551 {
6552   operand *left, *right, *result;
6553   int size, offset = 0;
6554   unsigned long lit = 0L;
6555   int bytelit = 0;
6556
6557   D(emitcode (";     genXor",""));
6558
6559   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6560   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6561   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6562
6563 #ifdef DEBUG_TYPE
6564   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6565             AOP_TYPE (result),
6566             AOP_TYPE (left), AOP_TYPE (right));
6567   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6568             AOP_SIZE (result),
6569             AOP_SIZE (left), AOP_SIZE (right));
6570 #endif
6571
6572   /* if left is a literal & right is not ||
6573      if left needs acc & right does not */
6574   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6575       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6576     {
6577       operand *tmp = right;
6578       right = left;
6579       left = tmp;
6580     }
6581
6582   /* if result = right then exchange them */
6583   if (sameRegs (AOP (result), AOP (right)))
6584     {
6585       operand *tmp = right;
6586       right = left;
6587       left = tmp;
6588     }
6589
6590   /* if right is bit then exchange them */
6591   if (AOP_TYPE (right) == AOP_CRY &&
6592       AOP_TYPE (left) != AOP_CRY)
6593     {
6594       operand *tmp = right;
6595       right = left;
6596       left = tmp;
6597     }
6598   if (AOP_TYPE (right) == AOP_LIT)
6599     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6600
6601   size = AOP_SIZE (result);
6602
6603   // if(bit ^ yy)
6604   // xx = bit ^ yy;
6605   if (AOP_TYPE (left) == AOP_CRY)
6606     {
6607       if (AOP_TYPE (right) == AOP_LIT)
6608         {
6609           // c = bit & literal;
6610           if (lit >> 1)
6611             {
6612               // lit>>1  != 0 => result = 1
6613               if (AOP_TYPE (result) == AOP_CRY)
6614                 {
6615                   if (size)
6616                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6617                   else if (ifx)
6618                     continueIfTrue (ifx);
6619                   goto release;
6620                 }
6621               emitcode ("setb", "c");
6622             }
6623           else
6624             {
6625               // lit == (0 or 1)
6626               if (lit == 0)
6627                 {
6628                   // lit == 0, result = left
6629                   if (size && sameRegs (AOP (result), AOP (left)))
6630                     goto release;
6631                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6632                 }
6633               else
6634                 {
6635                   // lit == 1, result = not(left)
6636                   if (size && sameRegs (AOP (result), AOP (left)))
6637                     {
6638                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6639                       goto release;
6640                     }
6641                   else
6642                     {
6643                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6644                       emitcode ("cpl", "c");
6645                     }
6646                 }
6647             }
6648
6649         }
6650       else
6651         {
6652           // right != literal
6653           symbol *tlbl = newiTempLabel (NULL);
6654           if (AOP_TYPE (right) == AOP_CRY)
6655             {
6656               // c = bit ^ bit;
6657               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6658             }
6659           else
6660             {
6661               int sizer = AOP_SIZE (right);
6662               // c = bit ^ val
6663               // if val>>1 != 0, result = 1
6664               emitcode ("setb", "c");
6665               while (sizer)
6666                 {
6667                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6668                   if (sizer == 1)
6669                     // test the msb of the lsb
6670                     emitcode ("anl", "a,#0xfe");
6671                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6672                   sizer--;
6673                 }
6674               // val = (0,1)
6675               emitcode ("rrc", "a");
6676             }
6677           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6678           emitcode ("cpl", "c");
6679           emitcode ("", "%05d$:", (tlbl->key + 100));
6680         }
6681       // bit = c
6682       // val = c
6683       if (size)
6684         outBitC (result);
6685       // if(bit | ...)
6686       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6687         genIfxJump (ifx, "c", left, right, result);
6688       goto release;
6689     }
6690
6691   /* if left is same as result */
6692   if (sameRegs (AOP (result), AOP (left)))
6693     {
6694       for (; size--; offset++)
6695         {
6696           if (AOP_TYPE (right) == AOP_LIT)
6697             {
6698               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6699               if (bytelit == 0)
6700                 {
6701                   /* dummy read of volatile operand */
6702                   if (isOperandVolatile (left, FALSE))
6703                     MOVA (aopGet (left, offset, FALSE, FALSE));
6704                   else
6705                     continue;
6706                 }
6707               else if (IS_AOP_PREG (left))
6708                 {
6709                   MOVA (aopGet (left, offset, FALSE, TRUE));
6710                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6711                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6712                 }
6713               else
6714                 {
6715                   emitcode ("xrl", "%s,%s",
6716                             aopGet (left, offset, FALSE, TRUE),
6717                             aopGet (right, offset, FALSE, FALSE));
6718                 }
6719             }
6720           else
6721             {
6722               if (AOP_TYPE (left) == AOP_ACC)
6723                 {
6724                   if (offset)
6725                     emitcode("mov", "a,b");
6726                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6727                 }
6728               else
6729                 {
6730                   MOVA (aopGet (right, offset, FALSE, FALSE));
6731                   if (IS_AOP_PREG (left))
6732                     {
6733                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6734                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6735                     }
6736                   else
6737                     emitcode ("xrl", "%s,a",
6738                               aopGet (left, offset, FALSE, TRUE));
6739                 }
6740             }
6741         }
6742     }
6743   else
6744     {
6745       // left & result in different registers
6746       if (AOP_TYPE (result) == AOP_CRY)
6747         {
6748           // result = bit
6749           // if(size), result in bit
6750           // if(!size && ifx), conditional oper: if(left ^ right)
6751           symbol *tlbl = newiTempLabel (NULL);
6752           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6753           if (size)
6754             emitcode ("setb", "c");
6755           while (sizer--)
6756             {
6757               if ((AOP_TYPE (right) == AOP_LIT) &&
6758                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6759                 {
6760                   MOVA (aopGet (left, offset, FALSE, FALSE));
6761                 }
6762               else
6763                 {
6764                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6765                     if (offset)
6766                       emitcode("mov", "a,b");
6767                     emitcode ("xrl", "a,%s",
6768                               aopGet (right, offset, FALSE, FALSE));
6769                   } else {
6770                     MOVA (aopGet (right, offset, FALSE, FALSE));
6771                     emitcode ("xrl", "a,%s",
6772                               aopGet (left, offset, FALSE, FALSE));
6773                   }
6774                 }
6775               emitcode ("jnz", "%05d$", tlbl->key + 100);
6776               offset++;
6777             }
6778           if (size)
6779             {
6780               CLRC;
6781               emitcode ("", "%05d$:", tlbl->key + 100);
6782               outBitC (result);
6783             }
6784           else if (ifx)
6785             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6786         }
6787       else
6788         {
6789           for (; (size--); offset++)
6790             {
6791               // normal case
6792               // result = left & right
6793               if (AOP_TYPE (right) == AOP_LIT)
6794                 {
6795                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6796                   if (bytelit == 0)
6797                     {
6798                       aopPut (result,
6799                               aopGet (left, offset, FALSE, FALSE),
6800                               offset,
6801                               isOperandVolatile (result, FALSE));
6802                       continue;
6803                     }
6804                 }
6805               // faster than result <- left, anl result,right
6806               // and better if result is SFR
6807               if (AOP_TYPE (left) == AOP_ACC)
6808                 {
6809                   if (offset)
6810                     emitcode("mov", "a,b");
6811                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6812                 }
6813               else
6814                 {
6815                   MOVA (aopGet (right, offset, FALSE, FALSE));
6816                   emitcode ("xrl", "a,%s",
6817                             aopGet (left, offset, FALSE, TRUE));
6818                 }
6819               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6820             }
6821         }
6822     }
6823
6824 release:
6825   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6826   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6827   freeAsmop (result, NULL, ic, TRUE);
6828 }
6829
6830 /*-----------------------------------------------------------------*/
6831 /* genInline - write the inline code out                           */
6832 /*-----------------------------------------------------------------*/
6833 static void
6834 genInline (iCode * ic)
6835 {
6836   char *buffer, *bp, *bp1;
6837
6838   D(emitcode (";     genInline",""));
6839
6840   _G.inLine += (!options.asmpeep);
6841
6842   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6843   strcpy (buffer, IC_INLINE (ic));
6844
6845   /* emit each line as a code */
6846   while (*bp)
6847     {
6848       if (*bp == '\n')
6849         {
6850           *bp++ = '\0';
6851           emitcode (bp1, "");
6852           bp1 = bp;
6853         }
6854       else
6855         {
6856           /* Add \n for labels, not dirs such as c:\mydir */
6857           if ( (*bp == ':') && (isspace(bp[1])) )
6858             {
6859               bp++;
6860               *bp = '\0';
6861               bp++;
6862               emitcode (bp1, "");
6863               bp1 = bp;
6864             }
6865           else
6866             bp++;
6867         }
6868     }
6869   if (bp1 != bp)
6870     emitcode (bp1, "");
6871   /*     emitcode("",buffer); */
6872   _G.inLine -= (!options.asmpeep);
6873 }
6874
6875 /*-----------------------------------------------------------------*/
6876 /* genRRC - rotate right with carry                                */
6877 /*-----------------------------------------------------------------*/
6878 static void
6879 genRRC (iCode * ic)
6880 {
6881   operand *left, *result;
6882   int size, offset = 0;
6883   char *l;
6884
6885   D(emitcode (";     genRRC",""));
6886
6887   /* rotate right with carry */
6888   left = IC_LEFT (ic);
6889   result = IC_RESULT (ic);
6890   aopOp (left, ic, FALSE);
6891   aopOp (result, ic, FALSE);
6892
6893   /* move it to the result */
6894   size = AOP_SIZE (result);
6895   offset = size - 1;
6896   if (size == 1) { /* special case for 1 byte */
6897       l = aopGet (left, offset, FALSE, FALSE);
6898       MOVA (l);
6899       emitcode ("rr", "a");
6900       goto release;
6901   }
6902   /* no need to clear carry, bit7 will be written later */
6903   while (size--)
6904     {
6905       l = aopGet (left, offset, FALSE, FALSE);
6906       MOVA (l);
6907       emitcode ("rrc", "a");
6908       if (AOP_SIZE (result) > 1)
6909         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
6910     }
6911   /* now we need to put the carry into the
6912      highest order byte of the result */
6913   if (AOP_SIZE (result) > 1)
6914     {
6915       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
6916       MOVA (l);
6917     }
6918   emitcode ("mov", "acc.7,c");
6919  release:
6920   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6921   freeAsmop (left, NULL, ic, TRUE);
6922   freeAsmop (result, NULL, ic, TRUE);
6923 }
6924
6925 /*-----------------------------------------------------------------*/
6926 /* genRLC - generate code for rotate left with carry               */
6927 /*-----------------------------------------------------------------*/
6928 static void
6929 genRLC (iCode * ic)
6930 {
6931   operand *left, *result;
6932   int size, offset = 0;
6933   char *l;
6934
6935   D(emitcode (";     genRLC",""));
6936
6937   /* rotate right with carry */
6938   left = IC_LEFT (ic);
6939   result = IC_RESULT (ic);
6940   aopOp (left, ic, FALSE);
6941   aopOp (result, ic, FALSE);
6942
6943   /* move it to the result */
6944   size = AOP_SIZE (result);
6945   offset = 0;
6946   if (size--)
6947     {
6948       l = aopGet (left, offset, FALSE, FALSE);
6949       MOVA (l);
6950       if (size == 0) { /* special case for 1 byte */
6951               emitcode("rl","a");
6952               goto release;
6953       }
6954       emitcode("rlc","a"); /* bit0 will be written later */
6955       if (AOP_SIZE (result) > 1)
6956         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6957       while (size--)
6958         {
6959           l = aopGet (left, offset, FALSE, FALSE);
6960           MOVA (l);
6961           emitcode ("rlc", "a");
6962           if (AOP_SIZE (result) > 1)
6963             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
6964         }
6965     }
6966   /* now we need to put the carry into the
6967      highest order byte of the result */
6968   if (AOP_SIZE (result) > 1)
6969     {
6970       l = aopGet (result, 0, FALSE, FALSE);
6971       MOVA (l);
6972     }
6973   emitcode ("mov", "acc.0,c");
6974  release:
6975   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6976   freeAsmop (left, NULL, ic, TRUE);
6977   freeAsmop (result, NULL, ic, TRUE);
6978 }
6979
6980 /*-----------------------------------------------------------------*/
6981 /* genGetHbit - generates code get highest order bit               */
6982 /*-----------------------------------------------------------------*/
6983 static void
6984 genGetHbit (iCode * ic)
6985 {
6986   operand *left, *result;
6987
6988   D(emitcode (";     genGetHbit",""));
6989
6990   left = IC_LEFT (ic);
6991   result = IC_RESULT (ic);
6992   aopOp (left, ic, FALSE);
6993   aopOp (result, ic, FALSE);
6994
6995   /* get the highest order byte into a */
6996   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
6997   if (AOP_TYPE (result) == AOP_CRY)
6998     {
6999       emitcode ("rlc", "a");
7000       outBitC (result);
7001     }
7002   else
7003     {
7004       emitcode ("rl", "a");
7005       emitcode ("anl", "a,#0x01");
7006       outAcc (result);
7007     }
7008
7009
7010   freeAsmop (left, NULL, ic, TRUE);
7011   freeAsmop (result, NULL, ic, TRUE);
7012 }
7013
7014 /*-----------------------------------------------------------------*/
7015 /* genSwap - generates code to swap nibbles or bytes               */
7016 /*-----------------------------------------------------------------*/
7017 static void
7018 genSwap (iCode * ic)
7019 {
7020   operand *left, *result;
7021
7022   D(emitcode (";     genSwap",""));
7023
7024   left = IC_LEFT (ic);
7025   result = IC_RESULT (ic);
7026   aopOp (left, ic, FALSE);
7027   aopOp (result, ic, FALSE);
7028
7029   switch (AOP_SIZE (left))
7030     {
7031     case 1: /* swap nibbles in byte */
7032       MOVA (aopGet (left, 0, FALSE, FALSE));
7033       emitcode ("swap", "a");
7034       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7035       break;
7036     case 2: /* swap bytes in word */
7037       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7038         {
7039           MOVA (aopGet (left, 0, FALSE, FALSE));
7040           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7041                   0, isOperandVolatile (result, FALSE));
7042           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7043         }
7044       else if (operandsEqu (left, result))
7045         {
7046           char * reg = "a";
7047           bool pushedB = FALSE, leftInB = FALSE;
7048
7049           MOVA (aopGet (left, 0, FALSE, FALSE));
7050           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7051             {
7052               pushedB = pushB ();
7053               emitcode ("mov", "b,a");
7054               reg = "b";
7055               leftInB = TRUE;
7056             }
7057           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7058                   0, isOperandVolatile (result, FALSE));
7059           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7060
7061           if (leftInB)
7062             popB (pushedB);
7063         }
7064       else
7065         {
7066           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7067                   0, isOperandVolatile (result, FALSE));
7068           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7069                   1, isOperandVolatile (result, FALSE));
7070         }
7071       break;
7072     default:
7073       wassertl(FALSE, "unsupported SWAP operand size");
7074     }
7075
7076   freeAsmop (left, NULL, ic, TRUE);
7077   freeAsmop (result, NULL, ic, TRUE);
7078 }
7079
7080
7081 /*-----------------------------------------------------------------*/
7082 /* AccRol - rotate left accumulator by known count                 */
7083 /*-----------------------------------------------------------------*/
7084 static void
7085 AccRol (int shCount)
7086 {
7087   shCount &= 0x0007;            // shCount : 0..7
7088
7089   switch (shCount)
7090     {
7091     case 0:
7092       break;
7093     case 1:
7094       emitcode ("rl", "a");
7095       break;
7096     case 2:
7097       emitcode ("rl", "a");
7098       emitcode ("rl", "a");
7099       break;
7100     case 3:
7101       emitcode ("swap", "a");
7102       emitcode ("rr", "a");
7103       break;
7104     case 4:
7105       emitcode ("swap", "a");
7106       break;
7107     case 5:
7108       emitcode ("swap", "a");
7109       emitcode ("rl", "a");
7110       break;
7111     case 6:
7112       emitcode ("rr", "a");
7113       emitcode ("rr", "a");
7114       break;
7115     case 7:
7116       emitcode ("rr", "a");
7117       break;
7118     }
7119 }
7120
7121 /*-----------------------------------------------------------------*/
7122 /* AccLsh - left shift accumulator by known count                  */
7123 /*-----------------------------------------------------------------*/
7124 static void
7125 AccLsh (int shCount)
7126 {
7127   if (shCount != 0)
7128     {
7129       if (shCount == 1)
7130         emitcode ("add", "a,acc");
7131       else if (shCount == 2)
7132         {
7133           emitcode ("add", "a,acc");
7134           emitcode ("add", "a,acc");
7135         }
7136       else
7137         {
7138           /* rotate left accumulator */
7139           AccRol (shCount);
7140           /* and kill the lower order bits */
7141           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7142         }
7143     }
7144 }
7145
7146 /*-----------------------------------------------------------------*/
7147 /* AccRsh - right shift accumulator by known count                 */
7148 /*-----------------------------------------------------------------*/
7149 static void
7150 AccRsh (int shCount)
7151 {
7152   if (shCount != 0)
7153     {
7154       if (shCount == 1)
7155         {
7156           CLRC;
7157           emitcode ("rrc", "a");
7158         }
7159       else
7160         {
7161           /* rotate right accumulator */
7162           AccRol (8 - shCount);
7163           /* and kill the higher order bits */
7164           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7165         }
7166     }
7167 }
7168
7169 /*-----------------------------------------------------------------*/
7170 /* AccSRsh - signed right shift accumulator by known count                 */
7171 /*-----------------------------------------------------------------*/
7172 static void
7173 AccSRsh (int shCount)
7174 {
7175   symbol *tlbl;
7176   if (shCount != 0)
7177     {
7178       if (shCount == 1)
7179         {
7180           emitcode ("mov", "c,acc.7");
7181           emitcode ("rrc", "a");
7182         }
7183       else if (shCount == 2)
7184         {
7185           emitcode ("mov", "c,acc.7");
7186           emitcode ("rrc", "a");
7187           emitcode ("mov", "c,acc.7");
7188           emitcode ("rrc", "a");
7189         }
7190       else
7191         {
7192           tlbl = newiTempLabel (NULL);
7193           /* rotate right accumulator */
7194           AccRol (8 - shCount);
7195           /* and kill the higher order bits */
7196           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7197           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7198           emitcode ("orl", "a,#0x%02x",
7199                     (unsigned char) ~SRMask[shCount]);
7200           emitcode ("", "%05d$:", tlbl->key + 100);
7201         }
7202     }
7203 }
7204
7205 /*-----------------------------------------------------------------*/
7206 /* shiftR1Left2Result - shift right one byte from left to result   */
7207 /*-----------------------------------------------------------------*/
7208 static void
7209 shiftR1Left2Result (operand * left, int offl,
7210                     operand * result, int offr,
7211                     int shCount, int sign)
7212 {
7213   MOVA (aopGet (left, offl, FALSE, FALSE));
7214   /* shift right accumulator */
7215   if (sign)
7216     AccSRsh (shCount);
7217   else
7218     AccRsh (shCount);
7219   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7220 }
7221
7222 /*-----------------------------------------------------------------*/
7223 /* shiftL1Left2Result - shift left one byte from left to result    */
7224 /*-----------------------------------------------------------------*/
7225 static void
7226 shiftL1Left2Result (operand * left, int offl,
7227                     operand * result, int offr, int shCount)
7228 {
7229   char *l;
7230   l = aopGet (left, offl, FALSE, FALSE);
7231   MOVA (l);
7232   /* shift left accumulator */
7233   AccLsh (shCount);
7234   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7235 }
7236
7237 /*-----------------------------------------------------------------*/
7238 /* movLeft2Result - move byte from left to result                  */
7239 /*-----------------------------------------------------------------*/
7240 static void
7241 movLeft2Result (operand * left, int offl,
7242                 operand * result, int offr, int sign)
7243 {
7244   char *l;
7245   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7246     {
7247       l = aopGet (left, offl, FALSE, FALSE);
7248
7249       if (*l == '@' && (IS_AOP_PREG (result)))
7250         {
7251           emitcode ("mov", "a,%s", l);
7252           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7253         }
7254       else
7255         {
7256           if (!sign)
7257             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7258           else
7259             {
7260               /* MSB sign in acc.7 ! */
7261               if (getDataSize (left) == offl + 1)
7262                 {
7263                   emitcode ("mov", "a,%s", l);
7264                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7265                 }
7266             }
7267         }
7268     }
7269 }
7270
7271 /*-----------------------------------------------------------------*/
7272 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7273 /*-----------------------------------------------------------------*/
7274 static void
7275 AccAXRrl1 (char *x)
7276 {
7277   emitcode ("rrc", "a");
7278   emitcode ("xch", "a,%s", x);
7279   emitcode ("rrc", "a");
7280   emitcode ("xch", "a,%s", x);
7281 }
7282
7283 /*-----------------------------------------------------------------*/
7284 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7285 /*-----------------------------------------------------------------*/
7286 static void
7287 AccAXLrl1 (char *x)
7288 {
7289   emitcode ("xch", "a,%s", x);
7290   emitcode ("rlc", "a");
7291   emitcode ("xch", "a,%s", x);
7292   emitcode ("rlc", "a");
7293 }
7294
7295 /*-----------------------------------------------------------------*/
7296 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7297 /*-----------------------------------------------------------------*/
7298 static void
7299 AccAXLsh1 (char *x)
7300 {
7301   emitcode ("xch", "a,%s", x);
7302   emitcode ("add", "a,acc");
7303   emitcode ("xch", "a,%s", x);
7304   emitcode ("rlc", "a");
7305 }
7306
7307 /*-----------------------------------------------------------------*/
7308 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7309 /*-----------------------------------------------------------------*/
7310 static void
7311 AccAXLsh (char *x, int shCount)
7312 {
7313   switch (shCount)
7314     {
7315     case 0:
7316       break;
7317     case 1:
7318       AccAXLsh1 (x);
7319       break;
7320     case 2:
7321       AccAXLsh1 (x);
7322       AccAXLsh1 (x);
7323       break;
7324     case 3:
7325     case 4:
7326     case 5:                     // AAAAABBB:CCCCCDDD
7327
7328       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7329
7330       emitcode ("anl", "a,#0x%02x",
7331                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7332
7333       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7334
7335       AccRol (shCount);         // DDDCCCCC:BBB00000
7336
7337       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7338
7339       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7340
7341       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7342
7343       emitcode ("anl", "a,#0x%02x",
7344                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7345
7346       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7347
7348       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7349
7350       break;
7351     case 6:                     // AAAAAABB:CCCCCCDD
7352       emitcode ("anl", "a,#0x%02x",
7353                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7354       emitcode ("mov", "c,acc.0");      // c = B
7355       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7356 #if 0 // REMOVE ME
7357       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7358       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7359 #else
7360       emitcode("rrc","a");
7361       emitcode("xch","a,%s", x);
7362       emitcode("rrc","a");
7363       emitcode("mov","c,acc.0"); //<< get correct bit
7364       emitcode("xch","a,%s", x);
7365
7366       emitcode("rrc","a");
7367       emitcode("xch","a,%s", x);
7368       emitcode("rrc","a");
7369       emitcode("xch","a,%s", x);
7370 #endif
7371       break;
7372     case 7:                     // a:x <<= 7
7373
7374       emitcode ("anl", "a,#0x%02x",
7375                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7376
7377       emitcode ("mov", "c,acc.0");      // c = B
7378
7379       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7380
7381       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7382
7383       break;
7384     default:
7385       break;
7386     }
7387 }
7388
7389 /*-----------------------------------------------------------------*/
7390 /* AccAXRsh - right shift a:x known count (0..7)                   */
7391 /*-----------------------------------------------------------------*/
7392 static void
7393 AccAXRsh (char *x, int shCount)
7394 {
7395   switch (shCount)
7396     {
7397     case 0:
7398       break;
7399     case 1:
7400       CLRC;
7401       AccAXRrl1 (x);            // 0->a:x
7402
7403       break;
7404     case 2:
7405       CLRC;
7406       AccAXRrl1 (x);            // 0->a:x
7407
7408       CLRC;
7409       AccAXRrl1 (x);            // 0->a:x
7410
7411       break;
7412     case 3:
7413     case 4:
7414     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7415
7416       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7417
7418       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7419
7420       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7421
7422       emitcode ("anl", "a,#0x%02x",
7423                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7424
7425       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7426
7427       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7428
7429       emitcode ("anl", "a,#0x%02x",
7430                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7431
7432       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7433
7434       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7435
7436       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7437
7438       break;
7439     case 6:                     // AABBBBBB:CCDDDDDD
7440
7441       emitcode ("mov", "c,acc.7");
7442       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7443
7444       emitcode ("mov", "c,acc.7");
7445       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7446
7447       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7448
7449       emitcode ("anl", "a,#0x%02x",
7450                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7451
7452       break;
7453     case 7:                     // ABBBBBBB:CDDDDDDD
7454
7455       emitcode ("mov", "c,acc.7");      // c = A
7456
7457       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7458
7459       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7460
7461       emitcode ("anl", "a,#0x%02x",
7462                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7463
7464       break;
7465     default:
7466       break;
7467     }
7468 }
7469
7470 /*-----------------------------------------------------------------*/
7471 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7472 /*-----------------------------------------------------------------*/
7473 static void
7474 AccAXRshS (char *x, int shCount)
7475 {
7476   symbol *tlbl;
7477   switch (shCount)
7478     {
7479     case 0:
7480       break;
7481     case 1:
7482       emitcode ("mov", "c,acc.7");
7483       AccAXRrl1 (x);            // s->a:x
7484
7485       break;
7486     case 2:
7487       emitcode ("mov", "c,acc.7");
7488       AccAXRrl1 (x);            // s->a:x
7489
7490       emitcode ("mov", "c,acc.7");
7491       AccAXRrl1 (x);            // s->a:x
7492
7493       break;
7494     case 3:
7495     case 4:
7496     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7497
7498       tlbl = newiTempLabel (NULL);
7499       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7500
7501       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7502
7503       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7504
7505       emitcode ("anl", "a,#0x%02x",
7506                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7507
7508       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7509
7510       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7511
7512       emitcode ("anl", "a,#0x%02x",
7513                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7514
7515       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7516
7517       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7518
7519       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7520
7521       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7522       emitcode ("orl", "a,#0x%02x",
7523                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7524
7525       emitcode ("", "%05d$:", tlbl->key + 100);
7526       break;                    // SSSSAAAA:BBBCCCCC
7527
7528     case 6:                     // AABBBBBB:CCDDDDDD
7529
7530       tlbl = newiTempLabel (NULL);
7531       emitcode ("mov", "c,acc.7");
7532       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7533
7534       emitcode ("mov", "c,acc.7");
7535       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7536
7537       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7538
7539       emitcode ("anl", "a,#0x%02x",
7540                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7541
7542       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7543       emitcode ("orl", "a,#0x%02x",
7544                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7545
7546       emitcode ("", "%05d$:", tlbl->key + 100);
7547       break;
7548     case 7:                     // ABBBBBBB:CDDDDDDD
7549
7550       tlbl = newiTempLabel (NULL);
7551       emitcode ("mov", "c,acc.7");      // c = A
7552
7553       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7554
7555       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7556
7557       emitcode ("anl", "a,#0x%02x",
7558                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7559
7560       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7561       emitcode ("orl", "a,#0x%02x",
7562                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7563
7564       emitcode ("", "%05d$:", tlbl->key + 100);
7565       break;
7566     default:
7567       break;
7568     }
7569 }
7570
7571 /*-----------------------------------------------------------------*/
7572 /* shiftL2Left2Result - shift left two bytes from left to result   */
7573 /*-----------------------------------------------------------------*/
7574 static void
7575 shiftL2Left2Result (operand * left, int offl,
7576                     operand * result, int offr, int shCount)
7577 {
7578   if (sameRegs (AOP (result), AOP (left)) &&
7579       ((offl + MSB16) == offr))
7580     {
7581       /* don't crash result[offr] */
7582       MOVA (aopGet (left, offl, FALSE, FALSE));
7583       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7584     }
7585   else
7586     {
7587       movLeft2Result (left, offl, result, offr, 0);
7588       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7589     }
7590   /* ax << shCount (x = lsb(result)) */
7591   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
7592   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7593 }
7594
7595
7596 /*-----------------------------------------------------------------*/
7597 /* shiftR2Left2Result - shift right two bytes from left to result  */
7598 /*-----------------------------------------------------------------*/
7599 static void
7600 shiftR2Left2Result (operand * left, int offl,
7601                     operand * result, int offr,
7602                     int shCount, int sign)
7603 {
7604   if (sameRegs (AOP (result), AOP (left)) &&
7605       ((offl + MSB16) == offr))
7606     {
7607       /* don't crash result[offr] */
7608       MOVA (aopGet (left, offl, FALSE, FALSE));
7609       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7610     }
7611   else
7612     {
7613       movLeft2Result (left, offl, result, offr, 0);
7614       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7615     }
7616   /* a:x >> shCount (x = lsb(result)) */
7617   if (sign)
7618     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
7619   else
7620     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
7621   if (getDataSize (result) > 1)
7622     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7623 }
7624
7625 /*-----------------------------------------------------------------*/
7626 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7627 /*-----------------------------------------------------------------*/
7628 static void
7629 shiftLLeftOrResult (operand * left, int offl,
7630                     operand * result, int offr, int shCount)
7631 {
7632   MOVA (aopGet (left, offl, FALSE, FALSE));
7633   /* shift left accumulator */
7634   AccLsh (shCount);
7635   /* or with result */
7636   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7637   /* back to result */
7638   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7639 }
7640
7641 /*-----------------------------------------------------------------*/
7642 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7643 /*-----------------------------------------------------------------*/
7644 static void
7645 shiftRLeftOrResult (operand * left, int offl,
7646                     operand * result, int offr, int shCount)
7647 {
7648   MOVA (aopGet (left, offl, FALSE, FALSE));
7649   /* shift right accumulator */
7650   AccRsh (shCount);
7651   /* or with result */
7652   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7653   /* back to result */
7654   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7655 }
7656
7657 /*-----------------------------------------------------------------*/
7658 /* genlshOne - left shift a one byte quantity by known count       */
7659 /*-----------------------------------------------------------------*/
7660 static void
7661 genlshOne (operand * result, operand * left, int shCount)
7662 {
7663   D(emitcode (";     genlshOne",""));
7664
7665   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7666 }
7667
7668 /*-----------------------------------------------------------------*/
7669 /* genlshTwo - left shift two bytes by known amount != 0           */
7670 /*-----------------------------------------------------------------*/
7671 static void
7672 genlshTwo (operand * result, operand * left, int shCount)
7673 {
7674   int size;
7675
7676   D(emitcode (";     genlshTwo",""));
7677
7678   size = getDataSize (result);
7679
7680   /* if shCount >= 8 */
7681   if (shCount >= 8)
7682     {
7683       shCount -= 8;
7684
7685       if (size > 1)
7686         {
7687           if (shCount)
7688             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7689           else
7690             movLeft2Result (left, LSB, result, MSB16, 0);
7691         }
7692       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7693     }
7694
7695   /*  1 <= shCount <= 7 */
7696   else
7697     {
7698       if (size == 1)
7699         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7700       else
7701         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7702     }
7703 }
7704
7705 /*-----------------------------------------------------------------*/
7706 /* shiftLLong - shift left one long from left to result            */
7707 /* offl = LSB or MSB16                                             */
7708 /*-----------------------------------------------------------------*/
7709 static void
7710 shiftLLong (operand * left, operand * result, int offr)
7711 {
7712   char *l;
7713   int size = AOP_SIZE (result);
7714
7715   if (size >= LSB + offr)
7716     {
7717       l = aopGet (left, LSB, FALSE, FALSE);
7718       MOVA (l);
7719       emitcode ("add", "a,acc");
7720       if (sameRegs (AOP (left), AOP (result)) &&
7721           size >= MSB16 + offr && offr != LSB)
7722         emitcode ("xch", "a,%s",
7723                   aopGet (left, LSB + offr, FALSE, FALSE));
7724       else
7725         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
7726     }
7727
7728   if (size >= MSB16 + offr)
7729     {
7730       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7731         {
7732           l = aopGet (left, MSB16, FALSE, FALSE);
7733           MOVA (l);
7734         }
7735       emitcode ("rlc", "a");
7736       if (sameRegs (AOP (left), AOP (result)) &&
7737           size >= MSB24 + offr && offr != LSB)
7738         emitcode ("xch", "a,%s",
7739                   aopGet (left, MSB16 + offr, FALSE, FALSE));
7740       else
7741         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7742     }
7743
7744   if (size >= MSB24 + offr)
7745     {
7746       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7747         {
7748           l = aopGet (left, MSB24, FALSE, FALSE);
7749           MOVA (l);
7750         }
7751       emitcode ("rlc", "a");
7752       if (sameRegs (AOP (left), AOP (result)) &&
7753           size >= MSB32 + offr && offr != LSB)
7754         emitcode ("xch", "a,%s",
7755                   aopGet (left, MSB24 + offr, FALSE, FALSE));
7756       else
7757         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7758     }
7759
7760   if (size > MSB32 + offr)
7761     {
7762       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7763         {
7764           l = aopGet (left, MSB32, FALSE, FALSE);
7765           MOVA (l);
7766         }
7767       emitcode ("rlc", "a");
7768       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7769     }
7770   if (offr != LSB)
7771     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7772 }
7773
7774 /*-----------------------------------------------------------------*/
7775 /* genlshFour - shift four byte by a known amount != 0             */
7776 /*-----------------------------------------------------------------*/
7777 static void
7778 genlshFour (operand * result, operand * left, int shCount)
7779 {
7780   int size;
7781
7782   D(emitcode (";     genlshFour",""));
7783
7784   size = AOP_SIZE (result);
7785
7786   /* if shifting more that 3 bytes */
7787   if (shCount >= 24)
7788     {
7789       shCount -= 24;
7790       if (shCount)
7791         /* lowest order of left goes to the highest
7792            order of the destination */
7793         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7794       else
7795         movLeft2Result (left, LSB, result, MSB32, 0);
7796       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7797       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7798       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
7799       return;
7800     }
7801
7802   /* more than two bytes */
7803   else if (shCount >= 16)
7804     {
7805       /* lower order two bytes goes to higher order two bytes */
7806       shCount -= 16;
7807       /* if some more remaining */
7808       if (shCount)
7809         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7810       else
7811         {
7812           movLeft2Result (left, MSB16, result, MSB32, 0);
7813           movLeft2Result (left, LSB, result, MSB24, 0);
7814         }
7815       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
7816       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7817       return;
7818     }
7819
7820   /* if more than 1 byte */
7821   else if (shCount >= 8)
7822     {
7823       /* lower order three bytes goes to higher order  three bytes */
7824       shCount -= 8;
7825       if (size == 2)
7826         {
7827           if (shCount)
7828             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7829           else
7830             movLeft2Result (left, LSB, result, MSB16, 0);
7831         }
7832       else
7833         {                       /* size = 4 */
7834           if (shCount == 0)
7835             {
7836               movLeft2Result (left, MSB24, result, MSB32, 0);
7837               movLeft2Result (left, MSB16, result, MSB24, 0);
7838               movLeft2Result (left, LSB, result, MSB16, 0);
7839               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7840             }
7841           else if (shCount == 1)
7842             shiftLLong (left, result, MSB16);
7843           else
7844             {
7845               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7846               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7847               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7848               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7849             }
7850         }
7851     }
7852
7853   /* 1 <= shCount <= 7 */
7854   else if (shCount <= 2)
7855     {
7856       shiftLLong (left, result, LSB);
7857       if (shCount == 2)
7858         shiftLLong (result, result, LSB);
7859     }
7860   /* 3 <= shCount <= 7, optimize */
7861   else
7862     {
7863       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7864       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7865       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7866     }
7867 }
7868
7869 /*-----------------------------------------------------------------*/
7870 /* genLeftShiftLiteral - left shifting by known count              */
7871 /*-----------------------------------------------------------------*/
7872 static void
7873 genLeftShiftLiteral (operand * left,
7874                      operand * right,
7875                      operand * result,
7876                      iCode * ic)
7877 {
7878   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7879   int size;
7880
7881   D(emitcode (";     genLeftShiftLiteral",""));
7882
7883   freeAsmop (right, NULL, ic, TRUE);
7884
7885   aopOp (left, ic, FALSE);
7886   aopOp (result, ic, FALSE);
7887
7888   size = getSize (operandType (result));
7889
7890 #if VIEW_SIZE
7891   emitcode ("; shift left ", "result %d, left %d", size,
7892             AOP_SIZE (left));
7893 #endif
7894
7895   /* I suppose that the left size >= result size */
7896   if (shCount == 0)
7897     {
7898       while (size--)
7899         {
7900           movLeft2Result (left, size, result, size, 0);
7901         }
7902     }
7903
7904   else if (shCount >= (size * 8))
7905     while (size--)
7906       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
7907   else
7908     {
7909       switch (size)
7910         {
7911         case 1:
7912           genlshOne (result, left, shCount);
7913           break;
7914
7915         case 2:
7916           genlshTwo (result, left, shCount);
7917           break;
7918
7919         case 4:
7920           genlshFour (result, left, shCount);
7921           break;
7922         default:
7923           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7924                   "*** ack! mystery literal shift!\n");
7925           break;
7926         }
7927     }
7928   freeAsmop (left, NULL, ic, TRUE);
7929   freeAsmop (result, NULL, ic, TRUE);
7930 }
7931
7932 /*-----------------------------------------------------------------*/
7933 /* genLeftShift - generates code for left shifting                 */
7934 /*-----------------------------------------------------------------*/
7935 static void
7936 genLeftShift (iCode * ic)
7937 {
7938   operand *left, *right, *result;
7939   int size, offset;
7940   char *l;
7941   symbol *tlbl, *tlbl1;
7942   bool pushedB;
7943
7944   D(emitcode (";     genLeftShift",""));
7945
7946   right = IC_RIGHT (ic);
7947   left = IC_LEFT (ic);
7948   result = IC_RESULT (ic);
7949
7950   aopOp (right, ic, FALSE);
7951
7952   /* if the shift count is known then do it
7953      as efficiently as possible */
7954   if (AOP_TYPE (right) == AOP_LIT)
7955     {
7956       genLeftShiftLiteral (left, right, result, ic);
7957       return;
7958     }
7959
7960   /* shift count is unknown then we have to form
7961      a loop get the loop count in B : Note: we take
7962      only the lower order byte since shifting
7963      more that 32 bits make no sense anyway, ( the
7964      largest size of an object can be only 32 bits ) */
7965
7966   pushedB = pushB ();
7967   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
7968   emitcode ("inc", "b");
7969   freeAsmop (right, NULL, ic, TRUE);
7970   aopOp (left, ic, FALSE);
7971   aopOp (result, ic, FALSE);
7972
7973   /* now move the left to the result if they are not the same */
7974   if (!sameRegs (AOP (left), AOP (result)) &&
7975       AOP_SIZE (result) > 1)
7976     {
7977
7978       size = AOP_SIZE (result);
7979       offset = 0;
7980       while (size--)
7981         {
7982           l = aopGet (left, offset, FALSE, TRUE);
7983           if (*l == '@' && (IS_AOP_PREG (result)))
7984             {
7985
7986               emitcode ("mov", "a,%s", l);
7987               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7988             }
7989           else
7990             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
7991           offset++;
7992         }
7993     }
7994
7995   tlbl = newiTempLabel (NULL);
7996   size = AOP_SIZE (result);
7997   offset = 0;
7998   tlbl1 = newiTempLabel (NULL);
7999
8000   /* if it is only one byte then */
8001   if (size == 1)
8002     {
8003       symbol *tlbl1 = newiTempLabel (NULL);
8004
8005       l = aopGet (left, 0, FALSE, FALSE);
8006       MOVA (l);
8007       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8008       emitcode ("", "%05d$:", tlbl->key + 100);
8009       emitcode ("add", "a,acc");
8010       emitcode ("", "%05d$:", tlbl1->key + 100);
8011       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8012       popB (pushedB);
8013       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8014       goto release;
8015     }
8016
8017   reAdjustPreg (AOP (result));
8018
8019   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8020   emitcode ("", "%05d$:", tlbl->key + 100);
8021   l = aopGet (result, offset, FALSE, FALSE);
8022   MOVA (l);
8023   emitcode ("add", "a,acc");
8024   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8025   while (--size)
8026     {
8027       l = aopGet (result, offset, FALSE, FALSE);
8028       MOVA (l);
8029       emitcode ("rlc", "a");
8030       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8031     }
8032   reAdjustPreg (AOP (result));
8033
8034   emitcode ("", "%05d$:", tlbl1->key + 100);
8035   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8036   popB (pushedB);
8037 release:
8038   freeAsmop (left, NULL, ic, TRUE);
8039   freeAsmop (result, NULL, ic, TRUE);
8040 }
8041
8042 /*-----------------------------------------------------------------*/
8043 /* genrshOne - right shift a one byte quantity by known count      */
8044 /*-----------------------------------------------------------------*/
8045 static void
8046 genrshOne (operand * result, operand * left,
8047            int shCount, int sign)
8048 {
8049   D(emitcode (";     genrshOne",""));
8050
8051   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8052 }
8053
8054 /*-----------------------------------------------------------------*/
8055 /* genrshTwo - right shift two bytes by known amount != 0          */
8056 /*-----------------------------------------------------------------*/
8057 static void
8058 genrshTwo (operand * result, operand * left,
8059            int shCount, int sign)
8060 {
8061   D(emitcode (";     genrshTwo",""));
8062
8063   /* if shCount >= 8 */
8064   if (shCount >= 8)
8065     {
8066       shCount -= 8;
8067       if (shCount)
8068         shiftR1Left2Result (left, MSB16, result, LSB,
8069                             shCount, sign);
8070       else
8071         movLeft2Result (left, MSB16, result, LSB, sign);
8072       addSign (result, MSB16, sign);
8073     }
8074
8075   /*  1 <= shCount <= 7 */
8076   else
8077     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8078 }
8079
8080 /*-----------------------------------------------------------------*/
8081 /* shiftRLong - shift right one long from left to result           */
8082 /* offl = LSB or MSB16                                             */
8083 /*-----------------------------------------------------------------*/
8084 static void
8085 shiftRLong (operand * left, int offl,
8086             operand * result, int sign)
8087 {
8088   int isSameRegs=sameRegs(AOP(left),AOP(result));
8089
8090   if (isSameRegs && offl>1) {
8091     // we are in big trouble, but this shouldn't happen
8092     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8093   }
8094
8095   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8096
8097   if (offl==MSB16) {
8098     // shift is > 8
8099     if (sign) {
8100       emitcode ("rlc", "a");
8101       emitcode ("subb", "a,acc");
8102       if (isSameRegs)
8103         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8104       else {
8105         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8106         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8107       }
8108     } else {
8109       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8110     }
8111   }
8112
8113   if (!sign) {
8114     emitcode ("clr", "c");
8115   } else {
8116     emitcode ("mov", "c,acc.7");
8117   }
8118
8119   emitcode ("rrc", "a");
8120
8121   if (isSameRegs && offl==MSB16) {
8122     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8123   } else {
8124     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8125     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8126   }
8127
8128   emitcode ("rrc", "a");
8129   if (isSameRegs && offl==1) {
8130     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8131   } else {
8132     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8133     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8134   }
8135   emitcode ("rrc", "a");
8136   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8137
8138   if (offl == LSB)
8139     {
8140       MOVA (aopGet (left, LSB, FALSE, FALSE));
8141       emitcode ("rrc", "a");
8142       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8143     }
8144 }
8145
8146 /*-----------------------------------------------------------------*/
8147 /* genrshFour - shift four byte by a known amount != 0             */
8148 /*-----------------------------------------------------------------*/
8149 static void
8150 genrshFour (operand * result, operand * left,
8151             int shCount, int sign)
8152 {
8153   D(emitcode (";     genrshFour",""));
8154
8155   /* if shifting more that 3 bytes */
8156   if (shCount >= 24)
8157     {
8158       shCount -= 24;
8159       if (shCount)
8160         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8161       else
8162         movLeft2Result (left, MSB32, result, LSB, sign);
8163       addSign (result, MSB16, sign);
8164     }
8165   else if (shCount >= 16)
8166     {
8167       shCount -= 16;
8168       if (shCount)
8169         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8170       else
8171         {
8172           movLeft2Result (left, MSB24, result, LSB, 0);
8173           movLeft2Result (left, MSB32, result, MSB16, sign);
8174         }
8175       addSign (result, MSB24, sign);
8176     }
8177   else if (shCount >= 8)
8178     {
8179       shCount -= 8;
8180       if (shCount == 1)
8181         shiftRLong (left, MSB16, result, sign);
8182       else if (shCount == 0)
8183         {
8184           movLeft2Result (left, MSB16, result, LSB, 0);
8185           movLeft2Result (left, MSB24, result, MSB16, 0);
8186           movLeft2Result (left, MSB32, result, MSB24, sign);
8187           addSign (result, MSB32, sign);
8188         }
8189       else
8190         {
8191           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8192           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8193           /* the last shift is signed */
8194           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8195           addSign (result, MSB32, sign);
8196         }
8197     }
8198   else
8199     {                           /* 1 <= shCount <= 7 */
8200       if (shCount <= 2)
8201         {
8202           shiftRLong (left, LSB, result, sign);
8203           if (shCount == 2)
8204             shiftRLong (result, LSB, result, sign);
8205         }
8206       else
8207         {
8208           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8209           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8210           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8211         }
8212     }
8213 }
8214
8215 /*-----------------------------------------------------------------*/
8216 /* genRightShiftLiteral - right shifting by known count            */
8217 /*-----------------------------------------------------------------*/
8218 static void
8219 genRightShiftLiteral (operand * left,
8220                       operand * right,
8221                       operand * result,
8222                       iCode * ic,
8223                       int sign)
8224 {
8225   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8226   int size;
8227
8228   D(emitcode (";     genRightShiftLiteral",""));
8229
8230   freeAsmop (right, NULL, ic, TRUE);
8231
8232   aopOp (left, ic, FALSE);
8233   aopOp (result, ic, FALSE);
8234
8235 #if VIEW_SIZE
8236   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8237             AOP_SIZE (left));
8238 #endif
8239
8240   size = getDataSize (left);
8241   /* test the LEFT size !!! */
8242
8243   /* I suppose that the left size >= result size */
8244   if (shCount == 0)
8245     {
8246       size = getDataSize (result);
8247       while (size--)
8248         movLeft2Result (left, size, result, size, 0);
8249     }
8250
8251   else if (shCount >= (size * 8))
8252     {
8253       if (sign) {
8254         /* get sign in acc.7 */
8255         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8256       }
8257       addSign (result, LSB, sign);
8258     }
8259   else
8260     {
8261       switch (size)
8262         {
8263         case 1:
8264           genrshOne (result, left, shCount, sign);
8265           break;
8266
8267         case 2:
8268           genrshTwo (result, left, shCount, sign);
8269           break;
8270
8271         case 4:
8272           genrshFour (result, left, shCount, sign);
8273           break;
8274         default:
8275           break;
8276         }
8277     }
8278   freeAsmop (left, NULL, ic, TRUE);
8279   freeAsmop (result, NULL, ic, TRUE);
8280 }
8281
8282 /*-----------------------------------------------------------------*/
8283 /* genSignedRightShift - right shift of signed number              */
8284 /*-----------------------------------------------------------------*/
8285 static void
8286 genSignedRightShift (iCode * ic)
8287 {
8288   operand *right, *left, *result;
8289   int size, offset;
8290   char *l;
8291   symbol *tlbl, *tlbl1;
8292   bool pushedB;
8293
8294   D(emitcode (";     genSignedRightShift",""));
8295
8296   /* we do it the hard way put the shift count in b
8297      and loop thru preserving the sign */
8298
8299   right = IC_RIGHT (ic);
8300   left = IC_LEFT (ic);
8301   result = IC_RESULT (ic);
8302
8303   aopOp (right, ic, FALSE);
8304
8305
8306   if (AOP_TYPE (right) == AOP_LIT)
8307     {
8308       genRightShiftLiteral (left, right, result, ic, 1);
8309       return;
8310     }
8311   /* shift count is unknown then we have to form
8312      a loop get the loop count in B : Note: we take
8313      only the lower order byte since shifting
8314      more that 32 bits make no sense anyway, ( the
8315      largest size of an object can be only 32 bits ) */
8316
8317   pushedB = pushB ();
8318   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8319   emitcode ("inc", "b");
8320   freeAsmop (right, NULL, ic, TRUE);
8321   aopOp (left, ic, FALSE);
8322   aopOp (result, ic, FALSE);
8323
8324   /* now move the left to the result if they are not the
8325      same */
8326   if (!sameRegs (AOP (left), AOP (result)) &&
8327       AOP_SIZE (result) > 1)
8328     {
8329
8330       size = AOP_SIZE (result);
8331       offset = 0;
8332       while (size--)
8333         {
8334           l = aopGet (left, offset, FALSE, TRUE);
8335           if (*l == '@' && IS_AOP_PREG (result))
8336             {
8337
8338               emitcode ("mov", "a,%s", l);
8339               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8340             }
8341           else
8342             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8343           offset++;
8344         }
8345     }
8346
8347   /* mov the highest order bit to OVR */
8348   tlbl = newiTempLabel (NULL);
8349   tlbl1 = newiTempLabel (NULL);
8350
8351   size = AOP_SIZE (result);
8352   offset = size - 1;
8353   MOVA (aopGet (left, offset, FALSE, FALSE));
8354   emitcode ("rlc", "a");
8355   emitcode ("mov", "ov,c");
8356   /* if it is only one byte then */
8357   if (size == 1)
8358     {
8359       l = aopGet (left, 0, FALSE, FALSE);
8360       MOVA (l);
8361       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8362       emitcode ("", "%05d$:", tlbl->key + 100);
8363       emitcode ("mov", "c,ov");
8364       emitcode ("rrc", "a");
8365       emitcode ("", "%05d$:", tlbl1->key + 100);
8366       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8367       popB (pushedB);
8368       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8369       goto release;
8370     }
8371
8372   reAdjustPreg (AOP (result));
8373   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8374   emitcode ("", "%05d$:", tlbl->key + 100);
8375   emitcode ("mov", "c,ov");
8376   while (size--)
8377     {
8378       l = aopGet (result, offset, FALSE, FALSE);
8379       MOVA (l);
8380       emitcode ("rrc", "a");
8381       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8382     }
8383   reAdjustPreg (AOP (result));
8384   emitcode ("", "%05d$:", tlbl1->key + 100);
8385   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8386   popB (pushedB);
8387
8388 release:
8389   freeAsmop (left, NULL, ic, TRUE);
8390   freeAsmop (result, NULL, ic, TRUE);
8391 }
8392
8393 /*-----------------------------------------------------------------*/
8394 /* genRightShift - generate code for right shifting                */
8395 /*-----------------------------------------------------------------*/
8396 static void
8397 genRightShift (iCode * ic)
8398 {
8399   operand *right, *left, *result;
8400   sym_link *letype;
8401   int size, offset;
8402   char *l;
8403   symbol *tlbl, *tlbl1;
8404   bool pushedB;
8405
8406   D(emitcode (";     genRightShift",""));
8407
8408   /* if signed then we do it the hard way preserve the
8409      sign bit moving it inwards */
8410   letype = getSpec (operandType (IC_LEFT (ic)));
8411
8412   if (!SPEC_USIGN (letype))
8413     {
8414       genSignedRightShift (ic);
8415       return;
8416     }
8417
8418   /* signed & unsigned types are treated the same : i.e. the
8419      signed is NOT propagated inwards : quoting from the
8420      ANSI - standard : "for E1 >> E2, is equivalent to division
8421      by 2**E2 if unsigned or if it has a non-negative value,
8422      otherwise the result is implementation defined ", MY definition
8423      is that the sign does not get propagated */
8424
8425   right = IC_RIGHT (ic);
8426   left = IC_LEFT (ic);
8427   result = IC_RESULT (ic);
8428
8429   aopOp (right, ic, FALSE);
8430
8431   /* if the shift count is known then do it
8432      as efficiently as possible */
8433   if (AOP_TYPE (right) == AOP_LIT)
8434     {
8435       genRightShiftLiteral (left, right, result, ic, 0);
8436       return;
8437     }
8438
8439   /* shift count is unknown then we have to form
8440      a loop get the loop count in B : Note: we take
8441      only the lower order byte since shifting
8442      more that 32 bits make no sense anyway, ( the
8443      largest size of an object can be only 32 bits ) */
8444
8445   pushedB = pushB ();
8446   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8447   emitcode ("inc", "b");
8448   freeAsmop (right, NULL, ic, TRUE);
8449   aopOp (left, ic, FALSE);
8450   aopOp (result, ic, FALSE);
8451
8452   /* now move the left to the result if they are not the
8453      same */
8454   if (!sameRegs (AOP (left), AOP (result)) &&
8455       AOP_SIZE (result) > 1)
8456     {
8457
8458       size = AOP_SIZE (result);
8459       offset = 0;
8460       while (size--)
8461         {
8462           l = aopGet (left, offset, FALSE, TRUE);
8463           if (*l == '@' && IS_AOP_PREG (result))
8464             {
8465
8466               emitcode ("mov", "a,%s", l);
8467               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8468             }
8469           else
8470             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8471           offset++;
8472         }
8473     }
8474
8475   tlbl = newiTempLabel (NULL);
8476   tlbl1 = newiTempLabel (NULL);
8477   size = AOP_SIZE (result);
8478   offset = size - 1;
8479
8480   /* if it is only one byte then */
8481   if (size == 1)
8482     {
8483       l = aopGet (left, 0, FALSE, FALSE);
8484       MOVA (l);
8485       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8486       emitcode ("", "%05d$:", tlbl->key + 100);
8487       CLRC;
8488       emitcode ("rrc", "a");
8489       emitcode ("", "%05d$:", tlbl1->key + 100);
8490       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8491       popB (pushedB);
8492       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8493       goto release;
8494     }
8495
8496   reAdjustPreg (AOP (result));
8497   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8498   emitcode ("", "%05d$:", tlbl->key + 100);
8499   CLRC;
8500   while (size--)
8501     {
8502       l = aopGet (result, offset, FALSE, FALSE);
8503       MOVA (l);
8504       emitcode ("rrc", "a");
8505       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8506     }
8507   reAdjustPreg (AOP (result));
8508
8509   emitcode ("", "%05d$:", tlbl1->key + 100);
8510   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8511   popB (pushedB);
8512
8513 release:
8514   freeAsmop (left, NULL, ic, TRUE);
8515   freeAsmop (result, NULL, ic, TRUE);
8516 }
8517
8518 /*-----------------------------------------------------------------*/
8519 /* emitPtrByteGet - emits code to get a byte into A through a      */
8520 /*                  pointer register (R0, R1, or DPTR). The        */
8521 /*                  original value of A can be preserved in B.     */
8522 /*-----------------------------------------------------------------*/
8523 static void
8524 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8525 {
8526   switch (p_type)
8527     {
8528     case IPOINTER:
8529     case POINTER:
8530       if (preserveAinB)
8531         emitcode ("mov", "b,a");
8532       emitcode ("mov", "a,@%s", rname);
8533       break;
8534
8535     case PPOINTER:
8536       if (preserveAinB)
8537         emitcode ("mov", "b,a");
8538       emitcode ("movx", "a,@%s", rname);
8539       break;
8540
8541     case FPOINTER:
8542       if (preserveAinB)
8543         emitcode ("mov", "b,a");
8544       emitcode ("movx", "a,@dptr");
8545       break;
8546
8547     case CPOINTER:
8548       if (preserveAinB)
8549         emitcode ("mov", "b,a");
8550       emitcode ("clr", "a");
8551       emitcode ("movc", "a,@a+dptr");
8552       break;
8553
8554     case GPOINTER:
8555       if (preserveAinB)
8556         {
8557           emitcode ("push", "b");
8558           emitcode ("push", "acc");
8559         }
8560       emitcode ("lcall", "__gptrget");
8561       if (preserveAinB)
8562         emitcode ("pop", "b");
8563       break;
8564     }
8565 }
8566
8567 /*-----------------------------------------------------------------*/
8568 /* emitPtrByteSet - emits code to set a byte from src through a    */
8569 /*                  pointer register (R0, R1, or DPTR).            */
8570 /*-----------------------------------------------------------------*/
8571 static void
8572 emitPtrByteSet (char *rname, int p_type, char *src)
8573 {
8574   switch (p_type)
8575     {
8576     case IPOINTER:
8577     case POINTER:
8578       if (*src=='@')
8579         {
8580           MOVA (src);
8581           emitcode ("mov", "@%s,a", rname);
8582         }
8583       else
8584         emitcode ("mov", "@%s,%s", rname, src);
8585       break;
8586
8587     case PPOINTER:
8588       MOVA (src);
8589       emitcode ("movx", "@%s,a", rname);
8590       break;
8591
8592     case FPOINTER:
8593       MOVA (src);
8594       emitcode ("movx", "@dptr,a");
8595       break;
8596
8597     case GPOINTER:
8598       MOVA (src);
8599       emitcode ("lcall", "__gptrput");
8600       break;
8601     }
8602 }
8603
8604 /*-----------------------------------------------------------------*/
8605 /* genUnpackBits - generates code for unpacking bits               */
8606 /*-----------------------------------------------------------------*/
8607 static void
8608 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8609 {
8610   int offset = 0;       /* result byte offset */
8611   int rsize;            /* result size */
8612   int rlen = 0;         /* remaining bitfield length */
8613   sym_link *etype;      /* bitfield type information */
8614   int blen;             /* bitfield length */
8615   int bstr;             /* bitfield starting bit within byte */
8616   char buffer[10];
8617
8618   D(emitcode (";     genUnpackBits",""));
8619
8620   etype = getSpec (operandType (result));
8621   rsize = getSize (operandType (result));
8622   blen = SPEC_BLEN (etype);
8623   bstr = SPEC_BSTR (etype);
8624
8625   if (ifx && blen <= 8)
8626     {
8627       emitPtrByteGet (rname, ptype, FALSE);
8628       if (blen == 1)
8629         {
8630           SNPRINTF (buffer, sizeof(buffer),
8631                     "acc.%d", bstr);
8632           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8633         }
8634       else
8635         {
8636           if (blen < 8)
8637             emitcode ("anl", "a,#0x%02x",
8638                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8639           genIfxJump (ifx, "a", NULL, NULL, NULL);
8640         }
8641       return;
8642     }
8643   wassert (!ifx);
8644
8645   /* If the bitfield length is less than a byte */
8646   if (blen < 8)
8647     {
8648       emitPtrByteGet (rname, ptype, FALSE);
8649       AccRsh (bstr);
8650       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8651       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8652       goto finish;
8653     }
8654
8655   /* Bit field did not fit in a byte. Copy all
8656      but the partial byte at the end.  */
8657   for (rlen=blen;rlen>=8;rlen-=8)
8658     {
8659       emitPtrByteGet (rname, ptype, FALSE);
8660       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8661       if (rlen>8)
8662         emitcode ("inc", "%s", rname);
8663     }
8664
8665   /* Handle the partial byte at the end */
8666   if (rlen)
8667     {
8668       emitPtrByteGet (rname, ptype, FALSE);
8669       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8670       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8671     }
8672
8673 finish:
8674   if (offset < rsize)
8675     {
8676       rsize -= offset;
8677       while (rsize--)
8678         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
8679     }
8680 }
8681
8682
8683 /*-----------------------------------------------------------------*/
8684 /* genDataPointerGet - generates code when ptr offset is known     */
8685 /*-----------------------------------------------------------------*/
8686 static void
8687 genDataPointerGet (operand * left,
8688                    operand * result,
8689                    iCode * ic)
8690 {
8691   char *l;
8692   char buffer[256];
8693   int size, offset = 0;
8694
8695   D(emitcode (";     genDataPointerGet",""));
8696
8697   aopOp (result, ic, TRUE);
8698
8699   /* get the string representation of the name */
8700   l = aopGet (left, 0, FALSE, TRUE);
8701   size = AOP_SIZE (result);
8702   while (size--)
8703     {
8704       if (offset)
8705         sprintf (buffer, "(%s + %d)", l + 1, offset);
8706       else
8707         sprintf (buffer, "%s", l + 1);
8708       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
8709     }
8710
8711   freeAsmop (left, NULL, ic, TRUE);
8712   freeAsmop (result, NULL, ic, TRUE);
8713 }
8714
8715 /*-----------------------------------------------------------------*/
8716 /* genNearPointerGet - emitcode for near pointer fetch             */
8717 /*-----------------------------------------------------------------*/
8718 static void
8719 genNearPointerGet (operand * left,
8720                    operand * result,
8721                    iCode * ic,
8722                    iCode * pi,
8723                    iCode * ifx)
8724 {
8725   asmop *aop = NULL;
8726   regs *preg = NULL;
8727   char *rname;
8728   sym_link *rtype, *retype;
8729   sym_link *ltype = operandType (left);
8730   char buffer[80];
8731
8732   D(emitcode (";     genNearPointerGet",""));
8733
8734   rtype = operandType (result);
8735   retype = getSpec (rtype);
8736
8737   aopOp (left, ic, FALSE);
8738
8739   /* if left is rematerialisable and
8740      result is not bitfield variable type and
8741      the left is pointer to data space i.e
8742      lower 128 bytes of space */
8743   if (AOP_TYPE (left) == AOP_IMMD &&
8744       !IS_BITFIELD (retype) &&
8745       DCL_TYPE (ltype) == POINTER)
8746     {
8747       genDataPointerGet (left, result, ic);
8748       return;
8749     }
8750
8751  /* if the value is already in a pointer register
8752      then don't need anything more */
8753   if (!AOP_INPREG (AOP (left)))
8754     {
8755       if (IS_AOP_PREG (left))
8756         {
8757           // Aha, it is a pointer, just in disguise.
8758           rname = aopGet (left, 0, FALSE, FALSE);
8759           if (*rname != '@')
8760             {
8761               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8762                       __FILE__, __LINE__);
8763             }
8764           else
8765             {
8766               // Expected case.
8767               emitcode ("mov", "a%s,%s", rname + 1, rname);
8768               rname++;  // skip the '@'.
8769             }
8770         }
8771       else
8772         {
8773           /* otherwise get a free pointer register */
8774           aop = newAsmop (0);
8775           preg = getFreePtr (ic, &aop, FALSE);
8776           emitcode ("mov", "%s,%s",
8777                     preg->name,
8778                     aopGet (left, 0, FALSE, TRUE));
8779           rname = preg->name;
8780         }
8781     }
8782   else
8783     rname = aopGet (left, 0, FALSE, FALSE);
8784
8785   //aopOp (result, ic, FALSE);
8786   aopOp (result, ic, result?TRUE:FALSE);
8787
8788   /* if bitfield then unpack the bits */
8789   if (IS_BITFIELD (retype))
8790     genUnpackBits (result, rname, POINTER, ifx);
8791   else
8792     {
8793       /* we have can just get the values */
8794       int size = AOP_SIZE (result);
8795       int offset = 0;
8796
8797       while (size--)
8798         {
8799           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8800             {
8801
8802               emitcode ("mov", "a,@%s", rname);
8803               if (!ifx)
8804               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8805             }
8806           else
8807             {
8808               sprintf (buffer, "@%s", rname);
8809               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
8810             }
8811           offset++;
8812           if (size || pi)
8813             emitcode ("inc", "%s", rname);
8814         }
8815     }
8816
8817   /* now some housekeeping stuff */
8818   if (aop)       /* we had to allocate for this iCode */
8819     {
8820       if (pi) { /* post increment present */
8821         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8822       }
8823       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8824     }
8825   else
8826     {
8827       /* we did not allocate which means left
8828          already in a pointer register, then
8829          if size > 0 && this could be used again
8830          we have to point it back to where it
8831          belongs */
8832       if ((AOP_SIZE (result) > 1 &&
8833            !OP_SYMBOL (left)->remat &&
8834            (OP_SYMBOL (left)->liveTo > ic->seq ||
8835             ic->depth)) &&
8836           !pi)
8837         {
8838           int size = AOP_SIZE (result) - 1;
8839           while (size--)
8840             emitcode ("dec", "%s", rname);
8841         }
8842     }
8843
8844   if (ifx && !ifx->generated)
8845     {
8846       genIfxJump (ifx, "a", left, NULL, result);
8847     }
8848
8849   /* done */
8850   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8851   freeAsmop (left, NULL, ic, TRUE);
8852   if (pi) pi->generated = 1;
8853 }
8854
8855 /*-----------------------------------------------------------------*/
8856 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8857 /*-----------------------------------------------------------------*/
8858 static void
8859 genPagedPointerGet (operand * left,
8860                     operand * result,
8861                     iCode * ic,
8862                     iCode *pi,
8863                     iCode *ifx)
8864 {
8865   asmop *aop = NULL;
8866   regs *preg = NULL;
8867   char *rname;
8868   sym_link *rtype, *retype;
8869
8870   D(emitcode (";     genPagedPointerGet",""));
8871
8872   rtype = operandType (result);
8873   retype = getSpec (rtype);
8874
8875   aopOp (left, ic, FALSE);
8876
8877   /* if the value is already in a pointer register
8878      then don't need anything more */
8879   if (!AOP_INPREG (AOP (left)))
8880     {
8881       /* otherwise get a free pointer register */
8882       aop = newAsmop (0);
8883       preg = getFreePtr (ic, &aop, FALSE);
8884       emitcode ("mov", "%s,%s",
8885                 preg->name,
8886                 aopGet (left, 0, FALSE, TRUE));
8887       rname = preg->name;
8888     }
8889   else
8890     rname = aopGet (left, 0, FALSE, FALSE);
8891
8892   aopOp (result, ic, FALSE);
8893
8894   /* if bitfield then unpack the bits */
8895   if (IS_BITFIELD (retype))
8896     genUnpackBits (result, rname, PPOINTER, ifx);
8897   else
8898     {
8899       /* we have can just get the values */
8900       int size = AOP_SIZE (result);
8901       int offset = 0;
8902
8903       while (size--)
8904         {
8905
8906           emitcode ("movx", "a,@%s", rname);
8907           if (!ifx)
8908           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8909
8910           offset++;
8911
8912           if (size || pi)
8913             emitcode ("inc", "%s", rname);
8914         }
8915     }
8916
8917   /* now some housekeeping stuff */
8918   if (aop) /* we had to allocate for this iCode */
8919     {
8920       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
8921       freeAsmop (NULL, aop, ic, TRUE);
8922     }
8923   else
8924     {
8925       /* we did not allocate which means left
8926          already in a pointer register, then
8927          if size > 0 && this could be used again
8928          we have to point it back to where it
8929          belongs */
8930       if ((AOP_SIZE (result) > 1 &&
8931            !OP_SYMBOL (left)->remat &&
8932            (OP_SYMBOL (left)->liveTo > ic->seq ||
8933             ic->depth)) &&
8934           !pi)
8935         {
8936           int size = AOP_SIZE (result) - 1;
8937           while (size--)
8938             emitcode ("dec", "%s", rname);
8939         }
8940     }
8941
8942   if (ifx && !ifx->generated)
8943     {
8944       genIfxJump (ifx, "a", left, NULL, result);
8945     }
8946
8947   /* done */
8948   freeAsmop (left, NULL, ic, TRUE);
8949   freeAsmop (result, NULL, ic, TRUE);
8950   if (pi) pi->generated = 1;
8951
8952 }
8953
8954 /*--------------------------------------------------------------------*/
8955 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8956 /*--------------------------------------------------------------------*/
8957 static void
8958 loadDptrFromOperand (operand *op, bool loadBToo)
8959 {
8960   if (AOP_TYPE (op) != AOP_STR)
8961     {
8962       /* if this is rematerializable */
8963       if (AOP_TYPE (op) == AOP_IMMD)
8964         {
8965           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
8966           if (loadBToo)
8967             {
8968               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8969                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
8970               else
8971                 {
8972                   wassertl(FALSE, "need pointerCode");
8973                   emitcode ("", "; mov b,???");
8974                   /* genPointerGet and genPointerSet originally did different
8975                   ** things for this case. Both seem wrong.
8976                   ** from genPointerGet:
8977                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8978                   ** from genPointerSet:
8979                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
8980                   */
8981                 }
8982             }
8983         }
8984       else if (AOP_TYPE (op) == AOP_DPTR)
8985         {
8986           if (loadBToo)
8987             {
8988               MOVA (aopGet (op, 0, FALSE, FALSE));
8989               emitcode ("push", "acc");
8990               MOVA (aopGet (op, 1, FALSE, FALSE));
8991               emitcode ("push", "acc");
8992               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
8993               emitcode ("pop", "dph");
8994               emitcode ("pop", "dpl");
8995             }
8996           else
8997             {
8998               MOVA (aopGet (op, 0, FALSE, FALSE));
8999               emitcode ("push", "acc");
9000               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9001               emitcode ("pop", "dpl");
9002             }
9003         }
9004       else
9005         {                       /* we need to get it byte by byte */
9006           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9007           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9008           if (loadBToo)
9009             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9010         }
9011     }
9012 }
9013
9014 /*-----------------------------------------------------------------*/
9015 /* genFarPointerGet - gget value from far space                    */
9016 /*-----------------------------------------------------------------*/
9017 static void
9018 genFarPointerGet (operand * left,
9019                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9020 {
9021   int size, offset;
9022   sym_link *retype = getSpec (operandType (result));
9023
9024   D(emitcode (";     genFarPointerGet",""));
9025
9026   aopOp (left, ic, FALSE);
9027   loadDptrFromOperand (left, FALSE);
9028
9029   /* so dptr now contains the address */
9030   aopOp (result, ic, FALSE);
9031
9032   /* if bit then unpack */
9033   if (IS_BITFIELD (retype))
9034     genUnpackBits (result, "dptr", FPOINTER, ifx);
9035   else
9036     {
9037       size = AOP_SIZE (result);
9038       offset = 0;
9039
9040       while (size--)
9041         {
9042           emitcode ("movx", "a,@dptr");
9043           if (!ifx)
9044             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9045           if (size || pi)
9046             emitcode ("inc", "dptr");
9047         }
9048     }
9049
9050   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9051     {
9052     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9053     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9054     pi->generated = 1;
9055   }
9056
9057   if (ifx && !ifx->generated)
9058     {
9059       genIfxJump (ifx, "a", left, NULL, result);
9060     }
9061
9062   freeAsmop (left, NULL, ic, TRUE);
9063   freeAsmop (result, NULL, ic, TRUE);
9064 }
9065
9066 /*-----------------------------------------------------------------*/
9067 /* genCodePointerGet - gget value from code space                  */
9068 /*-----------------------------------------------------------------*/
9069 static void
9070 genCodePointerGet (operand * left,
9071                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9072 {
9073   int size, offset;
9074   sym_link *retype = getSpec (operandType (result));
9075
9076   D(emitcode (";     genCodePointerGet",""));
9077
9078   aopOp (left, ic, FALSE);
9079   loadDptrFromOperand (left, FALSE);
9080
9081   /* so dptr now contains the address */
9082   aopOp (result, ic, FALSE);
9083
9084   /* if bit then unpack */
9085   if (IS_BITFIELD (retype))
9086     genUnpackBits (result, "dptr", CPOINTER, ifx);
9087   else
9088     {
9089       size = AOP_SIZE (result);
9090       offset = 0;
9091
9092       while (size--)
9093         {
9094           if (pi)
9095             {
9096               emitcode ("clr", "a");
9097               emitcode ("movc", "a,@a+dptr");
9098               if (!ifx)
9099               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9100               emitcode ("inc", "dptr");
9101             }
9102           else
9103             {
9104               emitcode ("mov", "a,#0x%02x", offset);
9105               emitcode ("movc", "a,@a+dptr");
9106               if (!ifx)
9107               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9108             }
9109         }
9110     }
9111
9112   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9113     {
9114     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9115     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9116     pi->generated = 1;
9117   }
9118
9119   if (ifx && !ifx->generated)
9120     {
9121       genIfxJump (ifx, "a", left, NULL, result);
9122     }
9123
9124   freeAsmop (left, NULL, ic, TRUE);
9125   freeAsmop (result, NULL, ic, TRUE);
9126 }
9127
9128 /*-----------------------------------------------------------------*/
9129 /* genGenPointerGet - gget value from generic pointer space        */
9130 /*-----------------------------------------------------------------*/
9131 static void
9132 genGenPointerGet (operand * left,
9133                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9134 {
9135   int size, offset;
9136   sym_link *retype = getSpec (operandType (result));
9137
9138   D(emitcode (";     genGenPointerGet",""));
9139
9140   aopOp (left, ic, FALSE);
9141   loadDptrFromOperand (left, TRUE);
9142
9143   /* so dptr know contains the address */
9144   aopOp (result, ic, FALSE);
9145
9146   /* if bit then unpack */
9147   if (IS_BITFIELD (retype))
9148     genUnpackBits (result, "dptr", GPOINTER, ifx);
9149   else
9150     {
9151       size = AOP_SIZE (result);
9152       offset = 0;
9153
9154       while (size--)
9155         {
9156           emitcode ("lcall", "__gptrget");
9157           if (!ifx)
9158           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9159           if (size || pi)
9160             emitcode ("inc", "dptr");
9161         }
9162     }
9163
9164   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9165     {
9166     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9167     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9168     pi->generated = 1;
9169   }
9170
9171   if (ifx && !ifx->generated)
9172     {
9173       genIfxJump (ifx, "a", left, NULL, result);
9174     }
9175
9176
9177   freeAsmop (left, NULL, ic, TRUE);
9178   freeAsmop (result, NULL, ic, TRUE);
9179 }
9180
9181 /*-----------------------------------------------------------------*/
9182 /* genPointerGet - generate code for pointer get                   */
9183 /*-----------------------------------------------------------------*/
9184 static void
9185 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9186 {
9187   operand *left, *result;
9188   sym_link *type, *etype;
9189   int p_type;
9190
9191   D(emitcode (";     genPointerGet",""));
9192
9193   left = IC_LEFT (ic);
9194   result = IC_RESULT (ic);
9195
9196   if (getSize (operandType (result))>1)
9197     ifx = NULL;
9198
9199   /* depending on the type of pointer we need to
9200      move it to the correct pointer register */
9201   type = operandType (left);
9202   etype = getSpec (type);
9203   /* if left is of type of pointer then it is simple */
9204   if (IS_PTR (type) && !IS_FUNC (type->next))
9205     p_type = DCL_TYPE (type);
9206   else
9207     {
9208       /* we have to go by the storage class */
9209       p_type = PTR_TYPE (SPEC_OCLS (etype));
9210     }
9211
9212   /* special case when cast remat */
9213   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9214       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9215           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9216           type = operandType (left);
9217           p_type = DCL_TYPE (type);
9218   }
9219   /* now that we have the pointer type we assign
9220      the pointer values */
9221   switch (p_type)
9222     {
9223
9224     case POINTER:
9225     case IPOINTER:
9226       genNearPointerGet (left, result, ic, pi, ifx);
9227       break;
9228
9229     case PPOINTER:
9230       genPagedPointerGet (left, result, ic, pi, ifx);
9231       break;
9232
9233     case FPOINTER:
9234       genFarPointerGet (left, result, ic, pi, ifx);
9235       break;
9236
9237     case CPOINTER:
9238       genCodePointerGet (left, result, ic, pi, ifx);
9239       break;
9240
9241     case GPOINTER:
9242       genGenPointerGet (left, result, ic, pi, ifx);
9243       break;
9244     }
9245
9246 }
9247
9248
9249
9250 /*-----------------------------------------------------------------*/
9251 /* genPackBits - generates code for packed bit storage             */
9252 /*-----------------------------------------------------------------*/
9253 static void
9254 genPackBits (sym_link * etype,
9255              operand * right,
9256              char *rname, int p_type)
9257 {
9258   int offset = 0;       /* source byte offset */
9259   int rlen = 0;         /* remaining bitfield length */
9260   int blen;             /* bitfield length */
9261   int bstr;             /* bitfield starting bit within byte */
9262   int litval;           /* source literal value (if AOP_LIT) */
9263   unsigned char mask;   /* bitmask within current byte */
9264
9265   D(emitcode (";     genPackBits",""));
9266
9267   blen = SPEC_BLEN (etype);
9268   bstr = SPEC_BSTR (etype);
9269
9270   /* If the bitfield length is less than a byte */
9271   if (blen < 8)
9272     {
9273       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9274               (unsigned char) (0xFF >> (8 - bstr)));
9275
9276       if (AOP_TYPE (right) == AOP_LIT)
9277         {
9278           /* Case with a bitfield length <8 and literal source
9279           */
9280           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9281           litval <<= bstr;
9282           litval &= (~mask) & 0xff;
9283           emitPtrByteGet (rname, p_type, FALSE);
9284           if ((mask|litval)!=0xff)
9285             emitcode ("anl","a,#0x%02x", mask);
9286           if (litval)
9287             emitcode ("orl","a,#0x%02x", litval);
9288         }
9289       else
9290         {
9291           if ((blen==1) && (p_type!=GPOINTER))
9292             {
9293               /* Case with a bitfield length == 1 and no generic pointer
9294               */
9295               if (AOP_TYPE (right) == AOP_CRY)
9296                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9297               else
9298                 {
9299                   MOVA (aopGet (right, 0, FALSE, FALSE));
9300                   emitcode ("rrc","a");
9301                 }
9302               emitPtrByteGet (rname, p_type, FALSE);
9303               emitcode ("mov","acc.%d,c",bstr);
9304             }
9305           else
9306             {
9307               bool pushedB;
9308               /* Case with a bitfield length < 8 and arbitrary source
9309               */
9310               MOVA (aopGet (right, 0, FALSE, FALSE));
9311               /* shift and mask source value */
9312               AccLsh (bstr);
9313               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9314
9315               pushedB = pushB ();
9316               /* transfer A to B and get next byte */
9317               emitPtrByteGet (rname, p_type, TRUE);
9318
9319               emitcode ("anl", "a,#0x%02x", mask);
9320               emitcode ("orl", "a,b");
9321               if (p_type == GPOINTER)
9322                 emitcode ("pop", "b");
9323
9324               popB (pushedB);
9325            }
9326         }
9327
9328       emitPtrByteSet (rname, p_type, "a");
9329       return;
9330     }
9331
9332   /* Bit length is greater than 7 bits. In this case, copy  */
9333   /* all except the partial byte at the end                 */
9334   for (rlen=blen;rlen>=8;rlen-=8)
9335     {
9336       emitPtrByteSet (rname, p_type,
9337                       aopGet (right, offset++, FALSE, TRUE) );
9338       if (rlen>8)
9339         emitcode ("inc", "%s", rname);
9340     }
9341
9342   /* If there was a partial byte at the end */
9343   if (rlen)
9344     {
9345       mask = (((unsigned char) -1 << rlen) & 0xff);
9346
9347       if (AOP_TYPE (right) == AOP_LIT)
9348         {
9349           /* Case with partial byte and literal source
9350           */
9351           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9352           litval >>= (blen-rlen);
9353           litval &= (~mask) & 0xff;
9354           emitPtrByteGet (rname, p_type, FALSE);
9355           if ((mask|litval)!=0xff)
9356             emitcode ("anl","a,#0x%02x", mask);
9357           if (litval)
9358             emitcode ("orl","a,#0x%02x", litval);
9359         }
9360       else
9361         {
9362           bool pushedB;
9363           /* Case with partial byte and arbitrary source
9364           */
9365           MOVA (aopGet (right, offset++, FALSE, FALSE));
9366           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9367
9368           pushedB = pushB ();
9369           /* transfer A to B and get next byte */
9370           emitPtrByteGet (rname, p_type, TRUE);
9371
9372           emitcode ("anl", "a,#0x%02x", mask);
9373           emitcode ("orl", "a,b");
9374           if (p_type == GPOINTER)
9375             emitcode ("pop", "b");
9376
9377           popB (pushedB);
9378         }
9379       emitPtrByteSet (rname, p_type, "a");
9380     }
9381
9382 }
9383
9384
9385 /*-----------------------------------------------------------------*/
9386 /* genDataPointerSet - remat pointer to data space                 */
9387 /*-----------------------------------------------------------------*/
9388 static void
9389 genDataPointerSet (operand * right,
9390                    operand * result,
9391                    iCode * ic)
9392 {
9393   int size, offset = 0;
9394   char *l, buffer[256];
9395
9396   D(emitcode (";     genDataPointerSet",""));
9397
9398   aopOp (right, ic, FALSE);
9399
9400   l = aopGet (result, 0, FALSE, TRUE);
9401   size = AOP_SIZE (right);
9402   while (size--)
9403     {
9404       if (offset)
9405         sprintf (buffer, "(%s + %d)", l + 1, offset);
9406       else
9407         sprintf (buffer, "%s", l + 1);
9408       emitcode ("mov", "%s,%s", buffer,
9409                 aopGet (right, offset++, FALSE, FALSE));
9410     }
9411
9412   freeAsmop (right, NULL, ic, TRUE);
9413   freeAsmop (result, NULL, ic, TRUE);
9414 }
9415
9416 /*-----------------------------------------------------------------*/
9417 /* genNearPointerSet - emitcode for near pointer put                */
9418 /*-----------------------------------------------------------------*/
9419 static void
9420 genNearPointerSet (operand * right,
9421                    operand * result,
9422                    iCode * ic,
9423                    iCode * pi)
9424 {
9425   asmop *aop = NULL;
9426   regs *preg = NULL;
9427   char *rname, *l;
9428   sym_link *retype, *letype;
9429   sym_link *ptype = operandType (result);
9430
9431   D(emitcode (";     genNearPointerSet",""));
9432
9433   retype = getSpec (operandType (right));
9434   letype = getSpec (ptype);
9435   aopOp (result, ic, FALSE);
9436
9437   /* if the result is rematerializable &
9438      in data space & not a bit variable */
9439   if (AOP_TYPE (result) == AOP_IMMD &&
9440       DCL_TYPE (ptype) == POINTER &&
9441       !IS_BITVAR (retype) &&
9442       !IS_BITVAR (letype))
9443     {
9444       genDataPointerSet (right, result, ic);
9445       return;
9446     }
9447
9448   /* if the value is already in a pointer register
9449      then don't need anything more */
9450   if (!AOP_INPREG (AOP (result)))
9451     {
9452         if (
9453             //AOP_TYPE (result) == AOP_STK
9454             IS_AOP_PREG(result)
9455             )
9456         {
9457             // Aha, it is a pointer, just in disguise.
9458             rname = aopGet (result, 0, FALSE, FALSE);
9459             if (*rname != '@')
9460             {
9461                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9462                         __FILE__, __LINE__);
9463             }
9464             else
9465             {
9466                 // Expected case.
9467                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9468                 rname++;  // skip the '@'.
9469             }
9470         }
9471         else
9472         {
9473             /* otherwise get a free pointer register */
9474             aop = newAsmop (0);
9475             preg = getFreePtr (ic, &aop, FALSE);
9476             emitcode ("mov", "%s,%s",
9477                       preg->name,
9478                       aopGet (result, 0, FALSE, TRUE));
9479             rname = preg->name;
9480         }
9481     }
9482     else
9483     {
9484         rname = aopGet (result, 0, FALSE, FALSE);
9485     }
9486
9487   aopOp (right, ic, FALSE);
9488
9489   /* if bitfield then unpack the bits */
9490   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9491     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9492   else
9493     {
9494       /* we have can just get the values */
9495       int size = AOP_SIZE (right);
9496       int offset = 0;
9497
9498       while (size--)
9499         {
9500           l = aopGet (right, offset, FALSE, TRUE);
9501           if (*l == '@')
9502             {
9503               MOVA (l);
9504               emitcode ("mov", "@%s,a", rname);
9505             }
9506           else
9507             emitcode ("mov", "@%s,%s", rname, l);
9508           if (size || pi)
9509             emitcode ("inc", "%s", rname);
9510           offset++;
9511         }
9512     }
9513
9514   /* now some housekeeping stuff */
9515   if (aop) /* we had to allocate for this iCode */
9516     {
9517       if (pi)
9518         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9519       freeAsmop (NULL, aop, ic, TRUE);
9520     }
9521   else
9522     {
9523       /* we did not allocate which means left
9524          already in a pointer register, then
9525          if size > 0 && this could be used again
9526          we have to point it back to where it
9527          belongs */
9528       if ((AOP_SIZE (right) > 1 &&
9529            !OP_SYMBOL (result)->remat &&
9530            (OP_SYMBOL (result)->liveTo > ic->seq ||
9531             ic->depth)) &&
9532           !pi)
9533         {
9534           int size = AOP_SIZE (right) - 1;
9535           while (size--)
9536             emitcode ("dec", "%s", rname);
9537         }
9538     }
9539
9540   /* done */
9541   if (pi) pi->generated = 1;
9542   freeAsmop (result, NULL, ic, TRUE);
9543   freeAsmop (right, NULL, ic, TRUE);
9544 }
9545
9546 /*-----------------------------------------------------------------*/
9547 /* genPagedPointerSet - emitcode for Paged pointer put             */
9548 /*-----------------------------------------------------------------*/
9549 static void
9550 genPagedPointerSet (operand * right,
9551                     operand * result,
9552                     iCode * ic,
9553                     iCode * pi)
9554 {
9555   asmop *aop = NULL;
9556   regs *preg = NULL;
9557   char *rname, *l;
9558   sym_link *retype, *letype;
9559
9560   D(emitcode (";     genPagedPointerSet",""));
9561
9562   retype = getSpec (operandType (right));
9563   letype = getSpec (operandType (result));
9564
9565   aopOp (result, ic, FALSE);
9566
9567   /* if the value is already in a pointer register
9568      then don't need anything more */
9569   if (!AOP_INPREG (AOP (result)))
9570     {
9571       /* otherwise get a free pointer register */
9572       aop = newAsmop (0);
9573       preg = getFreePtr (ic, &aop, FALSE);
9574       emitcode ("mov", "%s,%s",
9575                 preg->name,
9576                 aopGet (result, 0, FALSE, TRUE));
9577       rname = preg->name;
9578     }
9579   else
9580     rname = aopGet (result, 0, FALSE, FALSE);
9581
9582   aopOp (right, ic, FALSE);
9583
9584   /* if bitfield then unpack the bits */
9585   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9586     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9587   else
9588     {
9589       /* we have can just get the values */
9590       int size = AOP_SIZE (right);
9591       int offset = 0;
9592
9593       while (size--)
9594         {
9595           l = aopGet (right, offset, FALSE, TRUE);
9596
9597           MOVA (l);
9598           emitcode ("movx", "@%s,a", rname);
9599
9600           if (size || pi)
9601             emitcode ("inc", "%s", rname);
9602
9603           offset++;
9604         }
9605     }
9606
9607   /* now some housekeeping stuff */
9608   if (aop) /* we had to allocate for this iCode */
9609     {
9610       if (pi)
9611         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9612       freeAsmop (NULL, aop, ic, TRUE);
9613     }
9614   else
9615     {
9616       /* we did not allocate which means left
9617          already in a pointer register, then
9618          if size > 0 && this could be used again
9619          we have to point it back to where it
9620          belongs */
9621       if (AOP_SIZE (right) > 1 &&
9622           !OP_SYMBOL (result)->remat &&
9623           (OP_SYMBOL (result)->liveTo > ic->seq ||
9624            ic->depth))
9625         {
9626           int size = AOP_SIZE (right) - 1;
9627           while (size--)
9628             emitcode ("dec", "%s", rname);
9629         }
9630     }
9631
9632   /* done */
9633   if (pi) pi->generated = 1;
9634   freeAsmop (result, NULL, ic, TRUE);
9635   freeAsmop (right, NULL, ic, TRUE);
9636
9637
9638 }
9639
9640 /*-----------------------------------------------------------------*/
9641 /* genFarPointerSet - set value from far space                     */
9642 /*-----------------------------------------------------------------*/
9643 static void
9644 genFarPointerSet (operand * right,
9645                   operand * result, iCode * ic, iCode * pi)
9646 {
9647   int size, offset;
9648   sym_link *retype = getSpec (operandType (right));
9649   sym_link *letype = getSpec (operandType (result));
9650
9651   D(emitcode (";     genFarPointerSet",""));
9652
9653   aopOp (result, ic, FALSE);
9654   loadDptrFromOperand (result, FALSE);
9655
9656   /* so dptr know contains the address */
9657   aopOp (right, ic, FALSE);
9658
9659   /* if bit then unpack */
9660   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9661     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9662   else
9663     {
9664       size = AOP_SIZE (right);
9665       offset = 0;
9666
9667       while (size--)
9668         {
9669           char *l = aopGet (right, offset++, FALSE, FALSE);
9670           MOVA (l);
9671           emitcode ("movx", "@dptr,a");
9672           if (size || pi)
9673             emitcode ("inc", "dptr");
9674         }
9675     }
9676   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9677     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9678     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9679     pi->generated=1;
9680   }
9681   freeAsmop (result, NULL, ic, TRUE);
9682   freeAsmop (right, NULL, ic, TRUE);
9683 }
9684
9685 /*-----------------------------------------------------------------*/
9686 /* genGenPointerSet - set value from generic pointer space         */
9687 /*-----------------------------------------------------------------*/
9688 static void
9689 genGenPointerSet (operand * right,
9690                   operand * result, iCode * ic, iCode * pi)
9691 {
9692   int size, offset;
9693   sym_link *retype = getSpec (operandType (right));
9694   sym_link *letype = getSpec (operandType (result));
9695
9696   D(emitcode (";     genGenPointerSet",""));
9697
9698   aopOp (result, ic, FALSE);
9699   loadDptrFromOperand (result, TRUE);
9700
9701   /* so dptr know contains the address */
9702   aopOp (right, ic, FALSE);
9703
9704   /* if bit then unpack */
9705   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9706     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9707   else
9708     {
9709       size = AOP_SIZE (right);
9710       offset = 0;
9711
9712       while (size--)
9713         {
9714           char *l = aopGet (right, offset++, FALSE, FALSE);
9715           MOVA (l);
9716           emitcode ("lcall", "__gptrput");
9717           if (size || pi)
9718             emitcode ("inc", "dptr");
9719         }
9720     }
9721
9722   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9723     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9724     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9725     pi->generated=1;
9726   }
9727   freeAsmop (result, NULL, ic, TRUE);
9728   freeAsmop (right, NULL, ic, TRUE);
9729 }
9730
9731 /*-----------------------------------------------------------------*/
9732 /* genPointerSet - stores the value into a pointer location        */
9733 /*-----------------------------------------------------------------*/
9734 static void
9735 genPointerSet (iCode * ic, iCode *pi)
9736 {
9737   operand *right, *result;
9738   sym_link *type, *etype;
9739   int p_type;
9740
9741   D(emitcode (";     genPointerSet",""));
9742
9743   right = IC_RIGHT (ic);
9744   result = IC_RESULT (ic);
9745
9746   /* depending on the type of pointer we need to
9747      move it to the correct pointer register */
9748   type = operandType (result);
9749   etype = getSpec (type);
9750   /* if left is of type of pointer then it is simple */
9751   if (IS_PTR (type) && !IS_FUNC (type->next))
9752     {
9753       p_type = DCL_TYPE (type);
9754     }
9755   else
9756     {
9757       /* we have to go by the storage class */
9758       p_type = PTR_TYPE (SPEC_OCLS (etype));
9759     }
9760
9761   /* special case when cast remat */
9762   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9763       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9764           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9765           type = operandType (result);
9766           p_type = DCL_TYPE (type);
9767   }
9768   /* now that we have the pointer type we assign
9769      the pointer values */
9770   switch (p_type)
9771     {
9772
9773     case POINTER:
9774     case IPOINTER:
9775       genNearPointerSet (right, result, ic, pi);
9776       break;
9777
9778     case PPOINTER:
9779       genPagedPointerSet (right, result, ic, pi);
9780       break;
9781
9782     case FPOINTER:
9783       genFarPointerSet (right, result, ic, pi);
9784       break;
9785
9786     case GPOINTER:
9787       genGenPointerSet (right, result, ic, pi);
9788       break;
9789
9790     default:
9791       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9792               "genPointerSet: illegal pointer type");
9793     }
9794
9795 }
9796
9797 /*-----------------------------------------------------------------*/
9798 /* genIfx - generate code for Ifx statement                        */
9799 /*-----------------------------------------------------------------*/
9800 static void
9801 genIfx (iCode * ic, iCode * popIc)
9802 {
9803   operand *cond = IC_COND (ic);
9804   int isbit = 0;
9805
9806   D(emitcode (";     genIfx",""));
9807
9808   aopOp (cond, ic, FALSE);
9809
9810   /* get the value into acc */
9811   if (AOP_TYPE (cond) != AOP_CRY)
9812     toBoolean (cond);
9813   else
9814     isbit = 1;
9815   /* the result is now in the accumulator */
9816   freeAsmop (cond, NULL, ic, TRUE);
9817
9818   /* if there was something to be popped then do it */
9819   if (popIc)
9820     genIpop (popIc);
9821
9822   /* if the condition is a bit variable */
9823   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9824     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9825   else if (isbit && !IS_ITEMP (cond))
9826     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9827   else
9828     genIfxJump (ic, "a", NULL, NULL, NULL);
9829
9830   ic->generated = 1;
9831 }
9832
9833 /*-----------------------------------------------------------------*/
9834 /* genAddrOf - generates code for address of                       */
9835 /*-----------------------------------------------------------------*/
9836 static void
9837 genAddrOf (iCode * ic)
9838 {
9839   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9840   int size, offset;
9841
9842   D(emitcode (";     genAddrOf",""));
9843
9844   aopOp (IC_RESULT (ic), ic, FALSE);
9845
9846   /* if the operand is on the stack then we
9847      need to get the stack offset of this
9848      variable */
9849   if (sym->onStack)
9850     {
9851       /* if it has an offset then we need to compute
9852          it */
9853       if (sym->stack)
9854         {
9855           emitcode ("mov", "a,%s", SYM_BP (sym));
9856           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9857                                          ((char) (sym->stack - _G.nRegsSaved)) :
9858                                          ((char) sym->stack)) & 0xff);
9859           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9860         }
9861       else
9862         {
9863           /* we can just move _bp */
9864           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9865         }
9866       /* fill the result with zero */
9867       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9868
9869       offset = 1;
9870       while (size--)
9871         {
9872           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9873         }
9874
9875       goto release;
9876     }
9877
9878   /* object not on stack then we need the name */
9879   size = AOP_SIZE (IC_RESULT (ic));
9880   offset = 0;
9881
9882   while (size--)
9883     {
9884       char s[SDCC_NAME_MAX];
9885       if (offset)
9886         sprintf (s, "#(%s >> %d)",
9887                  sym->rname,
9888                  offset * 8);
9889       else
9890         sprintf (s, "#%s", sym->rname);
9891       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9892     }
9893
9894 release:
9895   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9896
9897 }
9898
9899 /*-----------------------------------------------------------------*/
9900 /* genFarFarAssign - assignment when both are in far space         */
9901 /*-----------------------------------------------------------------*/
9902 static void
9903 genFarFarAssign (operand * result, operand * right, iCode * ic)
9904 {
9905   int size = AOP_SIZE (right);
9906   int offset = 0;
9907   char *l;
9908
9909   D(emitcode (";     genFarFarAssign",""));
9910
9911   /* first push the right side on to the stack */
9912   while (size--)
9913     {
9914       l = aopGet (right, offset++, FALSE, FALSE);
9915       MOVA (l);
9916       emitcode ("push", "acc");
9917     }
9918
9919   freeAsmop (right, NULL, ic, FALSE);
9920   /* now assign DPTR to result */
9921   aopOp (result, ic, FALSE);
9922   size = AOP_SIZE (result);
9923   while (size--)
9924     {
9925       emitcode ("pop", "acc");
9926       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
9927     }
9928   freeAsmop (result, NULL, ic, FALSE);
9929
9930 }
9931
9932 /*-----------------------------------------------------------------*/
9933 /* genAssign - generate code for assignment                        */
9934 /*-----------------------------------------------------------------*/
9935 static void
9936 genAssign (iCode * ic)
9937 {
9938   operand *result, *right;
9939   int size, offset;
9940   unsigned long lit = 0L;
9941
9942   D(emitcode(";     genAssign",""));
9943
9944   result = IC_RESULT (ic);
9945   right = IC_RIGHT (ic);
9946
9947   /* if they are the same */
9948   if (operandsEqu (result, right) &&
9949       !isOperandVolatile (result, FALSE) &&
9950       !isOperandVolatile (right, FALSE))
9951     return;
9952
9953   aopOp (right, ic, FALSE);
9954
9955   /* special case both in far space */
9956   if (AOP_TYPE (right) == AOP_DPTR &&
9957       IS_TRUE_SYMOP (result) &&
9958       isOperandInFarSpace (result))
9959     {
9960
9961       genFarFarAssign (result, right, ic);
9962       return;
9963     }
9964
9965   aopOp (result, ic, TRUE);
9966
9967   /* if they are the same registers */
9968   if (sameRegs (AOP (right), AOP (result)) &&
9969       !isOperandVolatile (result, FALSE) &&
9970       !isOperandVolatile (right, FALSE))
9971     goto release;
9972
9973   /* if the result is a bit */
9974   if (AOP_TYPE (result) == AOP_CRY)
9975     {
9976
9977       /* if the right size is a literal then
9978          we know what the value is */
9979       if (AOP_TYPE (right) == AOP_LIT)
9980         {
9981           if (((int) operandLitValue (right)))
9982             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
9983           else
9984             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
9985           goto release;
9986         }
9987
9988       /* the right is also a bit variable */
9989       if (AOP_TYPE (right) == AOP_CRY)
9990         {
9991           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9992           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
9993           goto release;
9994         }
9995
9996       /* we need to or */
9997       toBoolean (right);
9998       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9999       goto release;
10000     }
10001
10002   /* bit variables done */
10003   /* general case */
10004   size = AOP_SIZE (result);
10005   offset = 0;
10006   if (AOP_TYPE (right) == AOP_LIT)
10007     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10008   if ((size > 1) &&
10009       (AOP_TYPE (result) != AOP_REG) &&
10010       (AOP_TYPE (right) == AOP_LIT) &&
10011       !IS_FLOAT (operandType (right)) &&
10012       (lit < 256L))
10013     {
10014       while ((size) && (lit))
10015         {
10016           aopPut (result,
10017                   aopGet (right, offset, FALSE, FALSE),
10018                   offset,
10019                   isOperandVolatile (result, FALSE));
10020           lit >>= 8;
10021           offset++;
10022           size--;
10023         }
10024       emitcode ("clr", "a");
10025       while (size--)
10026         {
10027           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10028           offset++;
10029         }
10030     }
10031   else
10032     {
10033       while (size--)
10034         {
10035           aopPut (result,
10036                   aopGet (right, offset, FALSE, FALSE),
10037                   offset,
10038                   isOperandVolatile (result, FALSE));
10039           offset++;
10040         }
10041     }
10042
10043 release:
10044   freeAsmop (right, NULL, ic, TRUE);
10045   freeAsmop (result, NULL, ic, TRUE);
10046 }
10047
10048 /*-----------------------------------------------------------------*/
10049 /* genJumpTab - generates code for jump table                      */
10050 /*-----------------------------------------------------------------*/
10051 static void
10052 genJumpTab (iCode * ic)
10053 {
10054   symbol *jtab,*jtablo,*jtabhi;
10055   char *l;
10056   unsigned int count;
10057
10058   D(emitcode (";     genJumpTab",""));
10059
10060   count = elementsInSet( IC_JTLABELS (ic) );
10061
10062   if( count <= 16 )
10063     {
10064       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10065          if the switch argument is in a register.
10066          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10067       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10068          How will multiply by three be updated ???*/
10069       aopOp (IC_JTCOND (ic), ic, FALSE);
10070       /* get the condition into accumulator */
10071       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10072       MOVA (l);
10073       /* multiply by three */
10074       emitcode ("add", "a,acc");
10075       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10076       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10077
10078       jtab = newiTempLabel (NULL);
10079       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10080       emitcode ("jmp", "@a+dptr");
10081       emitcode ("", "%05d$:", jtab->key + 100);
10082       /* now generate the jump labels */
10083       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10084            jtab = setNextItem (IC_JTLABELS (ic)))
10085         emitcode ("ljmp", "%05d$", jtab->key + 100);
10086     }
10087   else
10088     {
10089       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10090          if the switch argument is in a register.
10091          For n>6 this algorithm may be more compact */
10092       jtablo = newiTempLabel (NULL);
10093       jtabhi = newiTempLabel (NULL);
10094
10095       /* get the condition into accumulator.
10096          Using b as temporary storage, if register push/pop is needed */
10097       aopOp (IC_JTCOND (ic), ic, FALSE);
10098       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10099       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10100           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10101         {
10102           // (MB) what if B is in use???
10103           wassertl(!BINUSE, "B was in use");
10104           emitcode ("mov", "b,%s", l);
10105           l = "b";
10106         }
10107       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10108       MOVA (l);
10109       if( count <= 112 )
10110         {
10111           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10112           emitcode ("movc", "a,@a+pc");
10113           emitcode ("push", "acc");
10114
10115           MOVA (l);
10116           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10117           emitcode ("movc", "a,@a+pc");
10118           emitcode ("push", "acc");
10119         }
10120       else
10121         {
10122           /* this scales up to n<=255, but needs two more bytes
10123              and changes dptr */
10124           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10125           emitcode ("movc", "a,@a+dptr");
10126           emitcode ("push", "acc");
10127
10128           MOVA (l);
10129           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10130           emitcode ("movc", "a,@a+dptr");
10131           emitcode ("push", "acc");
10132         }
10133
10134       emitcode ("ret", "");
10135
10136       /* now generate jump table, LSB */
10137       emitcode ("", "%05d$:", jtablo->key + 100);
10138       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10139            jtab = setNextItem (IC_JTLABELS (ic)))
10140         emitcode (".db", "%05d$", jtab->key + 100);
10141
10142       /* now generate jump table, MSB */
10143       emitcode ("", "%05d$:", jtabhi->key + 100);
10144       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10145            jtab = setNextItem (IC_JTLABELS (ic)))
10146          emitcode (".db", "%05d$>>8", jtab->key + 100);
10147     }
10148 }
10149
10150 /*-----------------------------------------------------------------*/
10151 /* genCast - gen code for casting                                  */
10152 /*-----------------------------------------------------------------*/
10153 static void
10154 genCast (iCode * ic)
10155 {
10156   operand *result = IC_RESULT (ic);
10157   sym_link *ctype = operandType (IC_LEFT (ic));
10158   sym_link *rtype = operandType (IC_RIGHT (ic));
10159   operand *right = IC_RIGHT (ic);
10160   int size, offset;
10161
10162   D(emitcode(";     genCast",""));
10163
10164   /* if they are equivalent then do nothing */
10165   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10166     return;
10167
10168   aopOp (right, ic, FALSE);
10169   aopOp (result, ic, FALSE);
10170
10171   /* if the result is a bit (and not a bitfield) */
10172   // if (AOP_TYPE (result) == AOP_CRY)
10173   if (IS_BITVAR (OP_SYMBOL (result)->type)
10174       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10175     {
10176       /* if the right size is a literal then
10177          we know what the value is */
10178       if (AOP_TYPE (right) == AOP_LIT)
10179         {
10180           if (((int) operandLitValue (right)))
10181             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10182           else
10183             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10184
10185           goto release;
10186         }
10187
10188       /* the right is also a bit variable */
10189       if (AOP_TYPE (right) == AOP_CRY)
10190         {
10191           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10192           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10193           goto release;
10194         }
10195
10196       /* we need to or */
10197       toBoolean (right);
10198       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10199       goto release;
10200     }
10201
10202
10203   /* if they are the same size : or less */
10204   if (AOP_SIZE (result) <= AOP_SIZE (right))
10205     {
10206
10207       /* if they are in the same place */
10208       if (sameRegs (AOP (right), AOP (result)))
10209         goto release;
10210
10211       /* if they in different places then copy */
10212       size = AOP_SIZE (result);
10213       offset = 0;
10214       while (size--)
10215         {
10216           aopPut (result,
10217                   aopGet (right, offset, FALSE, FALSE),
10218                   offset,
10219                   isOperandVolatile (result, FALSE));
10220           offset++;
10221         }
10222       goto release;
10223     }
10224
10225
10226   /* if the result is of type pointer */
10227   if (IS_PTR (ctype))
10228     {
10229
10230       int p_type;
10231       sym_link *type = operandType (right);
10232       sym_link *etype = getSpec (type);
10233
10234       /* pointer to generic pointer */
10235       if (IS_GENPTR (ctype))
10236         {
10237           if (IS_PTR (type))
10238             p_type = DCL_TYPE (type);
10239           else
10240             {
10241               if (SPEC_SCLS(etype)==S_REGISTER) {
10242                 // let's assume it is a generic pointer
10243                 p_type=GPOINTER;
10244               } else {
10245                 /* we have to go by the storage class */
10246                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10247               }
10248             }
10249
10250           /* the first two bytes are known */
10251           size = GPTRSIZE - 1;
10252           offset = 0;
10253           while (size--)
10254             {
10255               aopPut (result,
10256                       aopGet (right, offset, FALSE, FALSE),
10257                       offset,
10258                       isOperandVolatile (result, FALSE));
10259               offset++;
10260             }
10261           /* the last byte depending on type */
10262             {
10263                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10264                 char gpValStr[10];
10265
10266                 if (gpVal == -1)
10267                 {
10268                     // pointerTypeToGPByte will have bitched.
10269                     exit(1);
10270                 }
10271
10272                 sprintf(gpValStr, "#0x%x", gpVal);
10273                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10274             }
10275           goto release;
10276         }
10277
10278       /* just copy the pointers */
10279       size = AOP_SIZE (result);
10280       offset = 0;
10281       while (size--)
10282         {
10283           aopPut (result,
10284                   aopGet (right, offset, FALSE, FALSE),
10285                   offset,
10286                   isOperandVolatile (result, FALSE));
10287           offset++;
10288         }
10289       goto release;
10290     }
10291
10292   /* so we now know that the size of destination is greater
10293      than the size of the source */
10294   /* we move to result for the size of source */
10295   size = AOP_SIZE (right);
10296   offset = 0;
10297   while (size--)
10298     {
10299       aopPut (result,
10300               aopGet (right, offset, FALSE, FALSE),
10301               offset,
10302               isOperandVolatile (result, FALSE));
10303       offset++;
10304     }
10305
10306   /* now depending on the sign of the source && destination */
10307   size = AOP_SIZE (result) - AOP_SIZE (right);
10308   /* if unsigned or not an integral type */
10309   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10310     {
10311       while (size--)
10312         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10313     }
10314   else
10315     {
10316       /* we need to extend the sign :{ */
10317       char *l = aopGet (right, AOP_SIZE (right) - 1,
10318                         FALSE, FALSE);
10319       MOVA (l);
10320       emitcode ("rlc", "a");
10321       emitcode ("subb", "a,acc");
10322       while (size--)
10323         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10324     }
10325
10326   /* we are done hurray !!!! */
10327
10328 release:
10329   freeAsmop (right, NULL, ic, TRUE);
10330   freeAsmop (result, NULL, ic, TRUE);
10331
10332 }
10333
10334 /*-----------------------------------------------------------------*/
10335 /* genDjnz - generate decrement & jump if not zero instrucion      */
10336 /*-----------------------------------------------------------------*/
10337 static int
10338 genDjnz (iCode * ic, iCode * ifx)
10339 {
10340   symbol *lbl, *lbl1;
10341   if (!ifx)
10342     return 0;
10343
10344   D(emitcode (";     genDjnz",""));
10345
10346   /* if the if condition has a false label
10347      then we cannot save */
10348   if (IC_FALSE (ifx))
10349     return 0;
10350
10351   /* if the minus is not of the form
10352      a = a - 1 */
10353   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10354       !IS_OP_LITERAL (IC_RIGHT (ic)))
10355     return 0;
10356
10357   if (operandLitValue (IC_RIGHT (ic)) != 1)
10358     return 0;
10359
10360   /* if the size of this greater than one then no
10361      saving */
10362   if (getSize (operandType (IC_RESULT (ic))) > 1)
10363     return 0;
10364
10365   /* otherwise we can save BIG */
10366   lbl = newiTempLabel (NULL);
10367   lbl1 = newiTempLabel (NULL);
10368
10369   aopOp (IC_RESULT (ic), ic, FALSE);
10370
10371   if (AOP_NEEDSACC(IC_RESULT(ic)))
10372   {
10373       /* If the result is accessed indirectly via
10374        * the accumulator, we must explicitly write
10375        * it back after the decrement.
10376        */
10377       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10378
10379       if (strcmp(rByte, "a"))
10380       {
10381            /* Something is hopelessly wrong */
10382            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10383                    __FILE__, __LINE__);
10384            /* We can just give up; the generated code will be inefficient,
10385             * but what the hey.
10386             */
10387            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10388            return 0;
10389       }
10390       emitcode ("dec", "%s", rByte);
10391       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10392       emitcode ("jnz", "%05d$", lbl->key + 100);
10393   }
10394   else if (IS_AOP_PREG (IC_RESULT (ic)))
10395     {
10396       emitcode ("dec", "%s",
10397                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10398       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10399       emitcode ("jnz", "%05d$", lbl->key + 100);
10400     }
10401   else
10402     {
10403       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10404                 lbl->key + 100);
10405     }
10406   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10407   emitcode ("", "%05d$:", lbl->key + 100);
10408   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10409   emitcode ("", "%05d$:", lbl1->key + 100);
10410
10411   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10412   ifx->generated = 1;
10413   return 1;
10414 }
10415
10416 /*-----------------------------------------------------------------*/
10417 /* genReceive - generate code for a receive iCode                  */
10418 /*-----------------------------------------------------------------*/
10419 static void
10420 genReceive (iCode * ic)
10421 {
10422     int size = getSize (operandType (IC_RESULT (ic)));
10423     int offset = 0;
10424   D(emitcode (";     genReceive",""));
10425
10426   if (ic->argreg == 1) { /* first parameter */
10427       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10428           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10429            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10430
10431           regs *tempRegs[4];
10432           int receivingA = 0;
10433           int roffset = 0;
10434
10435           for (offset = 0; offset<size; offset++)
10436             if (!strcmp (fReturn[offset], "a"))
10437               receivingA = 1;
10438
10439           if (!receivingA)
10440             {
10441               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10442                 {
10443                   for (offset = size-1; offset>0; offset--)
10444                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10445                   emitcode("mov","a,%s", fReturn[0]);
10446                   _G.accInUse++;
10447                   aopOp (IC_RESULT (ic), ic, FALSE);
10448                   _G.accInUse--;
10449                   aopPut (IC_RESULT (ic), "a", offset,
10450                           isOperandVolatile (IC_RESULT (ic), FALSE));
10451                   for (offset = 1; offset<size; offset++)
10452                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10453                             isOperandVolatile (IC_RESULT (ic), FALSE));
10454                   goto release;
10455                 }
10456             }
10457           else
10458             {
10459               if (getTempRegs(tempRegs, size, ic))
10460                 {
10461                   for (offset = 0; offset<size; offset++)
10462                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10463                   aopOp (IC_RESULT (ic), ic, FALSE);
10464                   for (offset = 0; offset<size; offset++)
10465                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10466                             isOperandVolatile (IC_RESULT (ic), FALSE));
10467                   goto release;
10468                 }
10469             }
10470
10471           offset = fReturnSizeMCS51 - size;
10472           while (size--) {
10473               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10474                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10475               offset++;
10476           }
10477           aopOp (IC_RESULT (ic), ic, FALSE);
10478           size = AOP_SIZE (IC_RESULT (ic));
10479           offset = 0;
10480           while (size--) {
10481               emitcode ("pop", "acc");
10482               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10483           }
10484
10485       } else {
10486           _G.accInUse++;
10487           aopOp (IC_RESULT (ic), ic, FALSE);
10488           _G.accInUse--;
10489           assignResultValue (IC_RESULT (ic));
10490       }
10491   } else { /* second receive onwards */
10492       int rb1off ;
10493       aopOp (IC_RESULT (ic), ic, FALSE);
10494       rb1off = ic->argreg;
10495       while (size--) {
10496           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10497       }
10498   }
10499
10500 release:
10501   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10502 }
10503
10504 /*-----------------------------------------------------------------*/
10505 /* genDummyRead - generate code for dummy read of volatiles        */
10506 /*-----------------------------------------------------------------*/
10507 static void
10508 genDummyRead (iCode * ic)
10509 {
10510   operand *op;
10511   int size, offset;
10512
10513   D(emitcode(";     genDummyRead",""));
10514
10515   op = IC_RIGHT (ic);
10516   if (op && IS_SYMOP (op))
10517     {
10518       aopOp (op, ic, FALSE);
10519
10520       /* if the result is a bit */
10521       if (AOP_TYPE (op) == AOP_CRY)
10522         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10523       else
10524         {
10525           /* bit variables done */
10526           /* general case */
10527           size = AOP_SIZE (op);
10528           offset = 0;
10529           while (size--)
10530           {
10531             MOVA (aopGet (op, offset, FALSE, FALSE));
10532             offset++;
10533           }
10534         }
10535
10536       freeAsmop (op, NULL, ic, TRUE);
10537     }
10538
10539   op = IC_LEFT (ic);
10540   if (op && IS_SYMOP (op))
10541     {
10542       aopOp (op, ic, FALSE);
10543
10544       /* if the result is a bit */
10545       if (AOP_TYPE (op) == AOP_CRY)
10546         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10547       else
10548         {
10549           /* bit variables done */
10550           /* general case */
10551           size = AOP_SIZE (op);
10552           offset = 0;
10553           while (size--)
10554           {
10555             MOVA (aopGet (op, offset, FALSE, FALSE));
10556             offset++;
10557           }
10558         }
10559
10560       freeAsmop (op, NULL, ic, TRUE);
10561     }
10562 }
10563
10564 /*-----------------------------------------------------------------*/
10565 /* genCritical - generate code for start of a critical sequence    */
10566 /*-----------------------------------------------------------------*/
10567 static void
10568 genCritical (iCode *ic)
10569 {
10570   symbol *tlbl = newiTempLabel (NULL);
10571
10572   D(emitcode(";     genCritical",""));
10573
10574   if (IC_RESULT (ic))
10575     {
10576       aopOp (IC_RESULT (ic), ic, TRUE);
10577       aopPut (IC_RESULT (ic), one, 0, 0);
10578       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10579       aopPut (IC_RESULT (ic), zero, 0, 0);
10580       emitcode ("", "%05d$:", (tlbl->key + 100));
10581       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10582     }
10583   else
10584     {
10585       emitcode ("setb", "c");
10586       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10587       emitcode ("clr", "c");
10588       emitcode ("", "%05d$:", (tlbl->key + 100));
10589       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10590     }
10591 }
10592
10593 /*-----------------------------------------------------------------*/
10594 /* genEndCritical - generate code for end of a critical sequence   */
10595 /*-----------------------------------------------------------------*/
10596 static void
10597 genEndCritical (iCode *ic)
10598 {
10599   D(emitcode(";     genEndCritical",""));
10600
10601   if (IC_RIGHT (ic))
10602     {
10603       aopOp (IC_RIGHT (ic), ic, FALSE);
10604       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10605         {
10606           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10607           emitcode ("mov", "ea,c");
10608         }
10609       else
10610         {
10611           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10612             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
10613           emitcode ("rrc", "a");
10614           emitcode ("mov", "ea,c");
10615         }
10616       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10617     }
10618   else
10619     {
10620       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10621       emitcode ("mov", "ea,c");
10622     }
10623 }
10624
10625 /*-----------------------------------------------------------------*/
10626 /* gen51Code - generate code for 8051 based controllers            */
10627 /*-----------------------------------------------------------------*/
10628 void
10629 gen51Code (iCode * lic)
10630 {
10631   iCode *ic;
10632   int cln = 0;
10633   /* int cseq = 0; */
10634
10635   _G.currentFunc = NULL;
10636   lineHead = lineCurr = NULL;
10637
10638   /* print the allocation information */
10639   if (allocInfo && currFunc)
10640     printAllocInfo (currFunc, codeOutFile);
10641   /* if debug information required */
10642   if (options.debug && currFunc)
10643     {
10644       debugFile->writeFunction (currFunc, lic);
10645     }
10646   /* stack pointer name */
10647   if (options.useXstack)
10648     spname = "_spx";
10649   else
10650     spname = "sp";
10651
10652
10653   for (ic = lic; ic; ic = ic->next)
10654     {
10655       _G.current_iCode = ic;
10656
10657       if (ic->lineno && cln != ic->lineno)
10658         {
10659           if (options.debug)
10660             {
10661               debugFile->writeCLine (ic);
10662             }
10663           if (!options.noCcodeInAsm) {
10664             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10665                       printCLine(ic->filename, ic->lineno));
10666           }
10667           cln = ic->lineno;
10668         }
10669       #if 0
10670       if (ic->seqPoint && ic->seqPoint != cseq)
10671         {
10672           emitcode ("", "; sequence point %d", ic->seqPoint);
10673           cseq = ic->seqPoint;
10674         }
10675       #endif
10676       if (options.iCodeInAsm) {
10677         char regsInUse[80];
10678         int i;
10679
10680         for (i=0; i<8; i++) {
10681           sprintf (&regsInUse[i],
10682                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10683         }
10684         regsInUse[i]=0;
10685         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10686       }
10687       /* if the result is marked as
10688          spilt and rematerializable or code for
10689          this has already been generated then
10690          do nothing */
10691       if (resultRemat (ic) || ic->generated)
10692         continue;
10693
10694       /* depending on the operation */
10695       switch (ic->op)
10696         {
10697         case '!':
10698           genNot (ic);
10699           break;
10700
10701         case '~':
10702           genCpl (ic);
10703           break;
10704
10705         case UNARYMINUS:
10706           genUminus (ic);
10707           break;
10708
10709         case IPUSH:
10710           genIpush (ic);
10711           break;
10712
10713         case IPOP:
10714           /* IPOP happens only when trying to restore a
10715              spilt live range, if there is an ifx statement
10716              following this pop then the if statement might
10717              be using some of the registers being popped which
10718              would destory the contents of the register so
10719              we need to check for this condition and handle it */
10720           if (ic->next &&
10721               ic->next->op == IFX &&
10722               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10723             genIfx (ic->next, ic);
10724           else
10725             genIpop (ic);
10726           break;
10727
10728         case CALL:
10729           genCall (ic);
10730           break;
10731
10732         case PCALL:
10733           genPcall (ic);
10734           break;
10735
10736         case FUNCTION:
10737           genFunction (ic);
10738           break;
10739
10740         case ENDFUNCTION:
10741           genEndFunction (ic);
10742           break;
10743
10744         case RETURN:
10745           genRet (ic);
10746           break;
10747
10748         case LABEL:
10749           genLabel (ic);
10750           break;
10751
10752         case GOTO:
10753           genGoto (ic);
10754           break;
10755
10756         case '+':
10757           genPlus (ic);
10758           break;
10759
10760         case '-':
10761           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10762             genMinus (ic);
10763           break;
10764
10765         case '*':
10766           genMult (ic);
10767           break;
10768
10769         case '/':
10770           genDiv (ic);
10771           break;
10772
10773         case '%':
10774           genMod (ic);
10775           break;
10776
10777         case '>':
10778           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10779           break;
10780
10781         case '<':
10782           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10783           break;
10784
10785         case LE_OP:
10786         case GE_OP:
10787         case NE_OP:
10788
10789           /* note these two are xlated by algebraic equivalence
10790              during parsing SDCC.y */
10791           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10792                   "got '>=' or '<=' shouldn't have come here");
10793           break;
10794
10795         case EQ_OP:
10796           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10797           break;
10798
10799         case AND_OP:
10800           genAndOp (ic);
10801           break;
10802
10803         case OR_OP:
10804           genOrOp (ic);
10805           break;
10806
10807         case '^':
10808           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10809           break;
10810
10811         case '|':
10812           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10813           break;
10814
10815         case BITWISEAND:
10816           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10817           break;
10818
10819         case INLINEASM:
10820           genInline (ic);
10821           break;
10822
10823         case RRC:
10824           genRRC (ic);
10825           break;
10826
10827         case RLC:
10828           genRLC (ic);
10829           break;
10830
10831         case GETHBIT:
10832           genGetHbit (ic);
10833           break;
10834
10835         case LEFT_OP:
10836           genLeftShift (ic);
10837           break;
10838
10839         case RIGHT_OP:
10840           genRightShift (ic);
10841           break;
10842
10843         case GET_VALUE_AT_ADDRESS:
10844           genPointerGet (ic,
10845                          hasInc (IC_LEFT (ic), ic,
10846                                  getSize (operandType (IC_RESULT (ic)))),
10847                          ifxForOp (IC_RESULT (ic), ic) );
10848           break;
10849
10850         case '=':
10851           if (POINTER_SET (ic))
10852             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10853           else
10854             genAssign (ic);
10855           break;
10856
10857         case IFX:
10858           genIfx (ic, NULL);
10859           break;
10860
10861         case ADDRESS_OF:
10862           genAddrOf (ic);
10863           break;
10864
10865         case JUMPTABLE:
10866           genJumpTab (ic);
10867           break;
10868
10869         case CAST:
10870           genCast (ic);
10871           break;
10872
10873         case RECEIVE:
10874           genReceive (ic);
10875           break;
10876
10877         case SEND:
10878           addSet (&_G.sendSet, ic);
10879           break;
10880
10881         case DUMMY_READ_VOLATILE:
10882           genDummyRead (ic);
10883           break;
10884
10885         case CRITICAL:
10886           genCritical (ic);
10887           break;
10888
10889         case ENDCRITICAL:
10890           genEndCritical (ic);
10891           break;
10892
10893         case SWAP:
10894           genSwap (ic);
10895           break;
10896
10897         default:
10898           ic = ic;
10899         }
10900     }
10901
10902   _G.current_iCode = NULL;
10903
10904   /* now we are ready to call the
10905      peep hole optimizer */
10906   if (!options.nopeep)
10907     peepHole (&lineHead);
10908
10909   /* now do the actual printing */
10910   printLine (lineHead, codeOutFile);
10911   return;
10912 }