0fb8581b8f4e987ba01af7300448a49c6ade7d4b
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 //#define D(x)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0x00";
55 static char *one = "#0x01";
56 static char *spname;
57
58 char *fReturn8051[] =
59 {"dpl", "dph", "b", "a"};
60 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
61 char **fReturn = fReturn8051;
62 static char *accUse[] =
63 {"a", "b"};
64
65 static unsigned short rbank = -1;
66
67 static struct
68   {
69     short r0Pushed;
70     short r1Pushed;
71     short r0InB;
72     short r1InB;
73     short accInUse;
74     short inLine;
75     short debugLine;
76     short nRegsSaved;
77     set *sendSet;
78     iCode *current_iCode;
79     symbol *currentFunc;
80   }
81 _G;
82
83 static char *rb1regs[] = {
84     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
85 };
86
87 extern int mcs51_ptrRegReq;
88 extern int mcs51_nRegs;
89 extern FILE *codeOutFile;
90 static void saveRBank (int, iCode *, bool);
91 #define RESULTONSTACK(x) \
92                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
93                          IC_RESULT(x)->aop->type == AOP_STK )
94
95 #define MOVA(x) mova(x)  /* use function to avoid multiple eval */
96 #define CLRC    emitcode("clr","c")
97 #define SETC    emitcode("setb","c")
98
99 static lineNode *lineHead = NULL;
100 static lineNode *lineCurr = NULL;
101
102 static unsigned char SLMask[] =
103 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
104  0xE0, 0xC0, 0x80, 0x00};
105 static unsigned char SRMask[] =
106 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
107  0x07, 0x03, 0x01, 0x00};
108
109 #define LSB     0
110 #define MSB16   1
111 #define MSB24   2
112 #define MSB32   3
113
114 /*-----------------------------------------------------------------*/
115 /* emitcode - writes the code into a file : for now it is simple    */
116 /*-----------------------------------------------------------------*/
117 static void
118 emitcode (char *inst, const char *fmt,...)
119 {
120   va_list ap;
121   char lb[INITIAL_INLINEASM];
122   char *lbp = lb;
123
124   va_start (ap, fmt);
125
126   if (inst && *inst)
127     {
128       if (fmt && *fmt)
129         sprintf (lb, "%s\t", inst);
130       else
131         sprintf (lb, "%s", inst);
132       vsprintf (lb + (strlen (lb)), fmt, ap);
133     }
134   else
135     vsprintf (lb, fmt, ap);
136
137   while (isspace (*lbp))
138     lbp++;
139
140   //printf ("%s\n", lb);
141   
142   if (lbp && *lbp)
143     lineCurr = (lineCurr ?
144                 connectLine (lineCurr, newLineNode (lb)) :
145                 (lineHead = newLineNode (lb)));
146   lineCurr->isInline = _G.inLine;
147   lineCurr->isDebug = _G.debugLine;
148   lineCurr->ic = _G.current_iCode;
149   lineCurr->isComment = (*lbp==';');
150   va_end (ap);
151 }
152
153 /*-----------------------------------------------------------------*/
154 /* mova - moves specified value into accumulator                   */
155 /*-----------------------------------------------------------------*/
156 static void
157 mova (const char *x)
158 {
159   /* do some early peephole optimization */
160   if (!strcmp(x, "a") || !strcmp(x, "acc"))
161     return;
162
163   emitcode("mov","a,%s", x);
164 }
165
166 /*-----------------------------------------------------------------*/
167 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
168 /*-----------------------------------------------------------------*/
169 static regs *
170 getFreePtr (iCode * ic, asmop ** aopp, bool result)
171 {
172   bool r0iu = FALSE, r1iu = FALSE;
173   bool r0ou = FALSE, r1ou = FALSE;
174
175   /* the logic: if r0 & r1 used in the instruction
176      then we are in trouble otherwise */
177
178   /* first check if r0 & r1 are used by this
179      instruction, in which case we are in trouble */
180   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
181   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
182   if (r0iu && r1iu) {
183       goto endOfWorld;
184     }
185
186   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
187   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
188
189   /* if no usage of r0 then return it */
190   if (!r0iu && !r0ou)
191     {
192       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
193       (*aopp)->type = AOP_R0;
194
195       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
196     }
197
198   /* if no usage of r1 then return it */
199   if (!r1iu && !r1ou)
200     {
201       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
202       (*aopp)->type = AOP_R1;
203
204       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
205     }
206
207   /* now we know they both have usage */
208   /* if r0 not used in this instruction */
209   if (!r0iu)
210     {
211       /* push it if not already pushed */
212       if (ic->op == IPUSH)
213         {
214           emitcode ("mov", "b,%s",
215                     mcs51_regWithIdx (R0_IDX)->dname);
216           _G.r0InB++;
217         }
218       else if (!_G.r0Pushed)
219         {
220           emitcode ("push", "%s",
221                     mcs51_regWithIdx (R0_IDX)->dname);
222           _G.r0Pushed++;
223         }
224
225       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
226       (*aopp)->type = AOP_R0;
227
228       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
229     }
230
231   /* if r1 not used then */
232
233   if (!r1iu)
234     {
235       /* push it if not already pushed */
236       if (ic->op == IPUSH)
237         {
238           emitcode ("mov", "b,%s",
239                     mcs51_regWithIdx (R1_IDX)->dname);
240           _G.r1InB++;
241         }
242       else if (!_G.r1Pushed)
243         {
244           emitcode ("push", "%s",
245                     mcs51_regWithIdx (R1_IDX)->dname);
246           _G.r1Pushed++;
247         }
248
249       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
250       (*aopp)->type = AOP_R1;
251       return mcs51_regWithIdx (R1_IDX);
252     }
253 endOfWorld:
254   /* I said end of world, but not quite end of world yet */
255   if (result) {
256     /* we can push it on the stack */
257     (*aopp)->type = AOP_STK;
258     return NULL;
259   } else {
260     /* in the case that result AND left AND right needs a pointer reg
261        we can safely use the result's */
262     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
263       (*aopp)->type = AOP_R0;
264       return mcs51_regWithIdx (R0_IDX);
265     }
266     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
267       (*aopp)->type = AOP_R1;
268       return mcs51_regWithIdx (R1_IDX);
269     }
270   }
271
272   /* now this is REALLY the end of the world */
273   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
274           "getFreePtr should never reach here");
275   exit (1);
276 }
277
278
279 /*-----------------------------------------------------------------*/
280 /* getTempRegs - initialize an array of pointers to GPR registers */
281 /*               that are not in use. Returns 1 if the requested   */
282 /*               number of registers were available, 0 otherwise.  */
283 /*-----------------------------------------------------------------*/
284 int
285 getTempRegs(regs **tempRegs, int size, iCode *ic)
286 {
287   bitVect * freeRegs;
288   int i;
289   int offset;
290
291   if (!ic)
292     ic = _G.current_iCode;
293   if (!ic)
294     return 0;
295   if (!_G.currentFunc)
296     return 0;
297
298   freeRegs = newBitVect(8);
299   bitVectSetBit (freeRegs, R2_IDX);
300   bitVectSetBit (freeRegs, R3_IDX);
301   bitVectSetBit (freeRegs, R4_IDX);
302   bitVectSetBit (freeRegs, R5_IDX);
303   bitVectSetBit (freeRegs, R6_IDX);
304   bitVectSetBit (freeRegs, R7_IDX);
305
306   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
307     {
308       bitVect * newfreeRegs;
309       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
310       freeBitVect(freeRegs);
311       freeRegs = newfreeRegs;
312     }
313   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
314
315   offset = 0;
316   for (i=0; i<freeRegs->size; i++)
317     {
318       if (bitVectBitValue(freeRegs,i))
319         tempRegs[offset++] = mcs51_regWithIdx(i);
320       if (offset>=size)
321         {
322           freeBitVect(freeRegs);
323           return 1;
324         }
325     }
326
327   freeBitVect(freeRegs);
328   return 1;
329 }
330
331
332 /*-----------------------------------------------------------------*/
333 /* newAsmop - creates a new asmOp                                  */
334 /*-----------------------------------------------------------------*/
335 static asmop *
336 newAsmop (short type)
337 {
338   asmop *aop;
339
340   aop = Safe_calloc (1, sizeof (asmop));
341   aop->type = type;
342   return aop;
343 }
344
345 /*-----------------------------------------------------------------*/
346 /* pointerCode - returns the code for a pointer type               */
347 /*-----------------------------------------------------------------*/
348 static int
349 pointerCode (sym_link * etype)
350 {
351
352   return PTR_TYPE (SPEC_OCLS (etype));
353
354 }
355
356
357 /*-----------------------------------------------------------------*/
358 /* leftRightUseAcc - returns size of accumulator use by operands   */
359 /*-----------------------------------------------------------------*/
360 static int
361 leftRightUseAcc(iCode *ic)
362 {
363   operand *op;
364   int size;
365   int accuseSize = 0;
366   int accuse = 0;
367
368   if (!ic)
369     {
370       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
371               "null iCode pointer");
372       return 0;
373     }
374
375   if (ic->op == IFX)
376     {
377       op = IC_COND (ic);
378       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
379         {
380           accuse = 1;
381           size = getSize (OP_SYMBOL (op)->type);
382           if (size>accuseSize)
383             accuseSize = size;
384         }
385     }
386   else if (ic->op == JUMPTABLE)
387     {
388       op = IC_JTCOND (ic);
389       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
390         {
391           accuse = 1;
392           size = getSize (OP_SYMBOL (op)->type);
393           if (size>accuseSize)
394             accuseSize = size;
395         }
396     }
397   else
398     {
399       op = IC_LEFT (ic);
400       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
401         {
402           accuse = 1;
403           size = getSize (OP_SYMBOL (op)->type);
404           if (size>accuseSize)
405             accuseSize = size;
406         }
407       op = IC_RIGHT (ic);
408       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
409         {
410           accuse = 1;
411           size = getSize (OP_SYMBOL (op)->type);
412           if (size>accuseSize)
413             accuseSize = size;
414         }
415     }
416
417   if (accuseSize)
418     return accuseSize;
419   else
420     return accuse;
421 }
422
423
424 /*-----------------------------------------------------------------*/
425 /* aopForSym - for a true symbol                                   */
426 /*-----------------------------------------------------------------*/
427 static asmop *
428 aopForSym (iCode * ic, symbol * sym, bool result)
429 {
430   asmop *aop;
431   memmap *space;
432
433   wassertl (ic != NULL, "Got a null iCode");
434   wassertl (sym != NULL, "Got a null symbol");
435
436   space = SPEC_OCLS (sym->etype);
437
438   /* if already has one */
439   if (sym->aop)
440     return sym->aop;
441
442   /* assign depending on the storage class */
443   /* if it is on the stack or indirectly addressable */
444   /* space we need to assign either r0 or r1 to it   */
445   if (sym->onStack || sym->iaccess)
446     {
447       sym->aop = aop = newAsmop (0);
448       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
449       aop->size = getSize (sym->type);
450
451       /* now assign the address of the variable to
452          the pointer register */
453       if (aop->type != AOP_STK)
454         {
455
456           if (sym->onStack)
457             {
458               if (_G.accInUse || leftRightUseAcc (ic))
459                 emitcode ("push", "acc");
460
461               emitcode ("mov", "a,_bp");
462               emitcode ("add", "a,#0x%02x",
463                         ((sym->stack < 0) ?
464                          ((char) (sym->stack - _G.nRegsSaved)) :
465                          ((char) sym->stack)) & 0xff);
466               emitcode ("mov", "%s,a",
467                         aop->aopu.aop_ptr->name);
468
469               if (_G.accInUse || leftRightUseAcc (ic))
470                 emitcode ("pop", "acc");
471             }
472           else
473             emitcode ("mov", "%s,#%s",
474                       aop->aopu.aop_ptr->name,
475                       sym->rname);
476           aop->paged = space->paged;
477         }
478       else
479         aop->aopu.aop_stk = sym->stack;
480       return aop;
481     }
482
483   /* if in bit space */
484   if (IN_BITSPACE (space))
485     {
486       sym->aop = aop = newAsmop (AOP_CRY);
487       aop->aopu.aop_dir = sym->rname;
488       aop->size = getSize (sym->type);
489       return aop;
490     }
491   /* if it is in direct space */
492   if (IN_DIRSPACE (space))
493     {
494       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
495       //printTypeChainRaw(sym->type, NULL);
496       //printf("space = %s\n", space ? space->sname : "NULL");
497       sym->aop = aop = newAsmop (AOP_DIR);
498       aop->aopu.aop_dir = sym->rname;
499       aop->size = getSize (sym->type);
500       return aop;
501     }
502
503   /* special case for a function */
504   if (IS_FUNC (sym->type))
505     {
506       sym->aop = aop = newAsmop (AOP_IMMD);
507       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
508       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
509       aop->size = FPTRSIZE;
510       return aop;
511     }
512
513   /* only remaining is far space */
514   /* in which case DPTR gets the address */
515   sym->aop = aop = newAsmop (AOP_DPTR);
516   emitcode ("mov", "dptr,#%s", sym->rname);
517   aop->size = getSize (sym->type);
518
519   /* if it is in code space */
520   if (IN_CODESPACE (space))
521     aop->code = 1;
522
523   return aop;
524 }
525
526 /*-----------------------------------------------------------------*/
527 /* aopForRemat - rematerialzes an object                           */
528 /*-----------------------------------------------------------------*/
529 static asmop *
530 aopForRemat (symbol * sym)
531 {
532   iCode *ic = sym->rematiCode;
533   asmop *aop = newAsmop (AOP_IMMD);
534   int ptr_type=0;
535   int val = 0;
536
537   for (;;)
538     {
539       if (ic->op == '+')
540         val += (int) operandLitValue (IC_RIGHT (ic));
541       else if (ic->op == '-')
542         val -= (int) operandLitValue (IC_RIGHT (ic));
543       else if (IS_CAST_ICODE(ic)) {
544               sym_link *from_type = operandType(IC_RIGHT(ic));
545               aop->aopu.aop_immd.from_cast_remat = 1;
546               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
547               ptr_type = DCL_TYPE(from_type);
548               if (ptr_type == IPOINTER) {
549                 // bug #481053
550                 ptr_type = POINTER;
551               }
552               continue ;
553       } else break;
554
555       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
556     }
557
558   if (val)
559     sprintf (buffer, "(%s %c 0x%04x)",
560              OP_SYMBOL (IC_LEFT (ic))->rname,
561              val >= 0 ? '+' : '-',
562              abs (val) & 0xffff);
563   else
564     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
565
566   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
567   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
568   /* set immd2 field if required */
569   if (aop->aopu.aop_immd.from_cast_remat) {
570           sprintf(buffer,"#0x%02x",ptr_type);
571           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
572           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
573   }
574
575   return aop;
576 }
577
578 /*-----------------------------------------------------------------*/
579 /* regsInCommon - two operands have some registers in common       */
580 /*-----------------------------------------------------------------*/
581 static bool
582 regsInCommon (operand * op1, operand * op2)
583 {
584   symbol *sym1, *sym2;
585   int i;
586
587   /* if they have registers in common */
588   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
589     return FALSE;
590
591   sym1 = OP_SYMBOL (op1);
592   sym2 = OP_SYMBOL (op2);
593
594   if (sym1->nRegs == 0 || sym2->nRegs == 0)
595     return FALSE;
596
597   for (i = 0; i < sym1->nRegs; i++)
598     {
599       int j;
600       if (!sym1->regs[i])
601         continue;
602
603       for (j = 0; j < sym2->nRegs; j++)
604         {
605           if (!sym2->regs[j])
606             continue;
607
608           if (sym2->regs[j] == sym1->regs[i])
609             return TRUE;
610         }
611     }
612
613   return FALSE;
614 }
615
616 /*-----------------------------------------------------------------*/
617 /* operandsEqu - equivalent                                        */
618 /*-----------------------------------------------------------------*/
619 static bool
620 operandsEqu (operand * op1, operand * op2)
621 {
622   symbol *sym1, *sym2;
623
624   /* if they not symbols */
625   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
626     return FALSE;
627
628   sym1 = OP_SYMBOL (op1);
629   sym2 = OP_SYMBOL (op2);
630
631   /* if both are itemps & one is spilt
632      and the other is not then false */
633   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
634       sym1->isspilt != sym2->isspilt)
635     return FALSE;
636
637   /* if they are the same */
638   if (sym1 == sym2)
639     return TRUE;
640
641   if (strcmp (sym1->rname, sym2->rname) == 0)
642     return TRUE;
643
644
645   /* if left is a tmp & right is not */
646   if (IS_ITEMP (op1) &&
647       !IS_ITEMP (op2) &&
648       sym1->isspilt &&
649       (sym1->usl.spillLoc == sym2))
650     return TRUE;
651
652   if (IS_ITEMP (op2) &&
653       !IS_ITEMP (op1) &&
654       sym2->isspilt &&
655       sym1->level > 0 &&
656       (sym2->usl.spillLoc == sym1))
657     return TRUE;
658
659   return FALSE;
660 }
661
662 /*-----------------------------------------------------------------*/
663 /* sameRegs - two asmops have the same registers                   */
664 /*-----------------------------------------------------------------*/
665 static bool
666 sameRegs (asmop * aop1, asmop * aop2)
667 {
668   int i;
669
670   if (aop1 == aop2)
671     return TRUE;
672
673   if (aop1->type != AOP_REG ||
674       aop2->type != AOP_REG)
675     return FALSE;
676
677   if (aop1->size != aop2->size)
678     return FALSE;
679
680   for (i = 0; i < aop1->size; i++)
681     if (aop1->aopu.aop_reg[i] !=
682         aop2->aopu.aop_reg[i])
683       return FALSE;
684
685   return TRUE;
686 }
687
688 /*-----------------------------------------------------------------*/
689 /* aopOp - allocates an asmop for an operand  :                    */
690 /*-----------------------------------------------------------------*/
691 static void
692 aopOp (operand * op, iCode * ic, bool result)
693 {
694   asmop *aop;
695   symbol *sym;
696   int i;
697
698   if (!op)
699     return;
700
701   /* if this a literal */
702   if (IS_OP_LITERAL (op))
703     {
704       op->aop = aop = newAsmop (AOP_LIT);
705       aop->aopu.aop_lit = op->operand.valOperand;
706       aop->size = getSize (operandType (op));
707       return;
708     }
709
710   /* if already has a asmop then continue */
711   if (op->aop )
712     return;
713
714   /* if the underlying symbol has a aop */
715   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
716     {
717       op->aop = OP_SYMBOL (op)->aop;
718       return;
719     }
720
721   /* if this is a true symbol */
722   if (IS_TRUE_SYMOP (op))
723     {
724       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
725       return;
726     }
727
728   /* this is a temporary : this has
729      only four choices :
730      a) register
731      b) spillocation
732      c) rematerialize
733      d) conditional
734      e) can be a return use only */
735
736   sym = OP_SYMBOL (op);
737
738   /* if the type is a conditional */
739   if (sym->regType == REG_CND)
740     {
741       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
742       aop->size = 0;
743       return;
744     }
745
746   /* if it is spilt then two situations
747      a) is rematerialize
748      b) has a spill location */
749   if (sym->isspilt || sym->nRegs == 0)
750     {
751
752       /* rematerialize it NOW */
753       if (sym->remat)
754         {
755           sym->aop = op->aop = aop =
756             aopForRemat (sym);
757           aop->size = getSize (sym->type);
758           return;
759         }
760
761       if (sym->accuse)
762         {
763           int i;
764           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
765           aop->size = getSize (sym->type);
766           for (i = 0; i < 2; i++)
767             aop->aopu.aop_str[i] = accUse[i];
768           return;
769         }
770
771       if (sym->ruonly)
772         {
773           unsigned i;
774
775           aop = op->aop = sym->aop = newAsmop (AOP_STR);
776           aop->size = getSize (sym->type);
777           for (i = 0; i < fReturnSizeMCS51; i++)
778             aop->aopu.aop_str[i] = fReturn[i];
779           return;
780         }
781
782       if (sym->usl.spillLoc)
783         {
784           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
785             {
786               /* force a new aop if sizes differ */
787               sym->usl.spillLoc->aop = NULL;
788             }
789           sym->aop = op->aop = aop =
790                      aopForSym (ic, sym->usl.spillLoc, result);
791           aop->size = getSize (sym->type);
792           return;
793         }
794
795       /* else must be a dummy iTemp */
796       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
797       aop->size = getSize (sym->type);
798       return;
799     }
800
801   /* must be in a register */
802   sym->aop = op->aop = aop = newAsmop (AOP_REG);
803   aop->size = sym->nRegs;
804   for (i = 0; i < sym->nRegs; i++)
805     aop->aopu.aop_reg[i] = sym->regs[i];
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* freeAsmop - free up the asmop given to an operand               */
810 /*----------------------------------------------------------------*/
811 static void
812 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
813 {
814   asmop *aop;
815
816   if (!op)
817     aop = aaop;
818   else
819     aop = op->aop;
820
821   if (!aop)
822     return;
823
824   if (aop->freed)
825     goto dealloc;
826
827   aop->freed = 1;
828
829   /* depending on the asmop type only three cases need work AOP_RO
830      , AOP_R1 && AOP_STK */
831   switch (aop->type)
832     {
833     case AOP_R0:
834       if (_G.r0InB)
835         {
836           emitcode ("mov", "r0,b");
837           _G.r0InB--;
838         }
839       else if (_G.r0Pushed)
840         {
841           if (pop)
842             {
843               emitcode ("pop", "ar0");
844               _G.r0Pushed--;
845             }
846         }
847       bitVectUnSetBit (ic->rUsed, R0_IDX);
848       break;
849
850     case AOP_R1:
851       if (_G.r1InB)
852         {
853           emitcode ("mov", "r1,b");
854           _G.r1InB--;
855         }
856       if (_G.r1Pushed)
857         {
858           if (pop)
859             {
860               emitcode ("pop", "ar1");
861               _G.r1Pushed--;
862             }
863         }
864       bitVectUnSetBit (ic->rUsed, R1_IDX);
865       break;
866
867     case AOP_STK:
868       {
869         int sz = aop->size;
870         int stk = aop->aopu.aop_stk + aop->size - 1;
871         bitVectUnSetBit (ic->rUsed, R0_IDX);
872         bitVectUnSetBit (ic->rUsed, R1_IDX);
873
874         getFreePtr (ic, &aop, FALSE);
875
876         if (stk)
877           {
878             emitcode ("mov", "a,_bp");
879             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
880             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
881           }
882         else
883           {
884             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
885           }
886
887         while (sz--)
888           {
889             emitcode ("pop", "acc");
890             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
891             if (!sz)
892               break;
893             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
894           }
895         op->aop = aop;
896         freeAsmop (op, NULL, ic, TRUE);
897         if (_G.r1Pushed)
898           {
899             emitcode ("pop", "ar1");
900             _G.r1Pushed--;
901           }
902
903         if (_G.r0Pushed)
904           {
905             emitcode ("pop", "ar0");
906             _G.r0Pushed--;
907           }
908       }
909     }
910
911 dealloc:
912   /* all other cases just dealloc */
913   if (op)
914     {
915       op->aop = NULL;
916       if (IS_SYMOP (op))
917         {
918           OP_SYMBOL (op)->aop = NULL;
919           /* if the symbol has a spill */
920           if (SPIL_LOC (op))
921             SPIL_LOC (op)->aop = NULL;
922         }
923     }
924 }
925
926 /*------------------------------------------------------------------*/
927 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
928 /*                      pop r0 or r1 off stack if pushed            */
929 /*------------------------------------------------------------------*/
930 static void
931 freeForBranchAsmop (operand * op)
932 {
933   asmop *aop;
934
935   if (!op)
936     return;
937     
938   aop = op->aop;
939
940   if (!aop)
941     return;
942
943   if (aop->freed)
944     return;
945
946   switch (aop->type)
947     {
948     case AOP_R0:
949       if (_G.r0InB)
950         {
951           emitcode ("mov", "r0,b");
952         }
953       else if (_G.r0Pushed)
954         {
955           emitcode ("pop", "ar0");
956         }
957       break;
958
959     case AOP_R1:
960       if (_G.r1InB)
961         {
962           emitcode ("mov", "r1,b");
963         }
964       else if (_G.r1Pushed)
965         {
966           emitcode ("pop", "ar1");
967         }
968       break;
969
970     case AOP_STK:
971       {
972         int sz = aop->size;
973         int stk = aop->aopu.aop_stk + aop->size - 1;
974
975         emitcode ("mov", "b,r0");
976         if (stk)
977           {
978             emitcode ("mov", "a,_bp");
979             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
980             emitcode ("mov", "r0,a");
981           }
982         else
983           {
984             emitcode ("mov", "r0,_bp");
985           }
986
987         while (sz--)
988           {
989             emitcode ("pop", "acc");
990             emitcode ("mov", "@r0,a");
991             if (!sz)
992               break;
993             emitcode ("dec", "r0");
994           }
995         emitcode ("mov", "r0,b");
996       }
997     }
998
999 }
1000
1001 /*-----------------------------------------------------------------*/
1002 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1003 /*                 clobber the accumulator                         */
1004 /*-----------------------------------------------------------------*/
1005 static bool
1006 aopGetUsesAcc (asmop *aop, int offset)
1007 {
1008   if (offset > (aop->size - 1))
1009     return FALSE;
1010
1011   switch (aop->type)
1012     {
1013
1014     case AOP_R0:
1015     case AOP_R1:
1016       if (aop->paged)
1017         return TRUE;
1018       return FALSE;
1019     case AOP_DPTR:
1020       return TRUE;
1021     case AOP_IMMD:
1022       return FALSE;
1023     case AOP_DIR:
1024       return FALSE;
1025     case AOP_REG:
1026       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1027       return FALSE;
1028     case AOP_CRY:
1029       return TRUE;
1030     case AOP_ACC:
1031       return TRUE;
1032     case AOP_LIT:
1033       return FALSE;
1034     case AOP_STR:
1035       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1036         return TRUE;
1037       return FALSE;
1038     case AOP_DUMMY:
1039       return FALSE;
1040     default:
1041       /* Error case --- will have been caught already */
1042       wassert(0);
1043       return FALSE;
1044     }
1045 }
1046
1047 /*-----------------------------------------------------------------*/
1048 /* aopGet - for fetching value of the aop                          */
1049 /*-----------------------------------------------------------------*/
1050 static char *
1051 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1052 {
1053   char *s = buffer;
1054   char *rs;
1055
1056   /* offset is greater than
1057      size then zero */
1058   if (offset > (aop->size - 1) &&
1059       aop->type != AOP_LIT)
1060     return zero;
1061
1062   /* depending on type */
1063   switch (aop->type)
1064     {
1065     case AOP_DUMMY:
1066       return zero;
1067
1068     case AOP_R0:
1069     case AOP_R1:
1070       /* if we need to increment it */
1071       while (offset > aop->coff)
1072         {
1073           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1074           aop->coff++;
1075         }
1076
1077       while (offset < aop->coff)
1078         {
1079           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1080           aop->coff--;
1081         }
1082
1083       aop->coff = offset;
1084       if (aop->paged)
1085         {
1086           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1087           return (dname ? "acc" : "a");
1088         }
1089       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1090       rs = Safe_calloc (1, strlen (s) + 1);
1091       strcpy (rs, s);
1092       return rs;
1093
1094     case AOP_DPTR:
1095       if (aop->code && aop->coff==0 && offset>=1) {
1096         emitcode ("mov", "a,#0x%02x", offset);
1097         emitcode ("movc", "a,@a+dptr");
1098         return (dname ? "acc" : "a");
1099       }
1100
1101       while (offset > aop->coff)
1102         {
1103           emitcode ("inc", "dptr");
1104           aop->coff++;
1105         }
1106
1107       while (offset < aop->coff)
1108         {
1109           emitcode ("lcall", "__decdptr");
1110           aop->coff--;
1111         }
1112
1113       aop->coff = offset;
1114       if (aop->code)
1115         {
1116           emitcode ("clr", "a");
1117           emitcode ("movc", "a,@a+dptr");
1118         }
1119       else
1120         {
1121           emitcode ("movx", "a,@dptr");
1122         }
1123       return (dname ? "acc" : "a");
1124
1125
1126     case AOP_IMMD:
1127       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1128               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1129       } else if (bit16)
1130         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1131       else if (offset)
1132         sprintf (s, "#(%s >> %d)",
1133                  aop->aopu.aop_immd.aop_immd1,
1134                  offset * 8);
1135       else
1136         sprintf (s, "#%s",
1137                  aop->aopu.aop_immd.aop_immd1);
1138       rs = Safe_calloc (1, strlen (s) + 1);
1139       strcpy (rs, s);
1140       return rs;
1141
1142     case AOP_DIR:
1143       if (offset)
1144         sprintf (s, "(%s + %d)",
1145                  aop->aopu.aop_dir,
1146                  offset);
1147       else
1148         sprintf (s, "%s", aop->aopu.aop_dir);
1149       rs = Safe_calloc (1, strlen (s) + 1);
1150       strcpy (rs, s);
1151       return rs;
1152
1153     case AOP_REG:
1154       if (dname)
1155         return aop->aopu.aop_reg[offset]->dname;
1156       else
1157         return aop->aopu.aop_reg[offset]->name;
1158
1159     case AOP_CRY:
1160       emitcode ("clr", "a");
1161       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1162       emitcode ("rlc", "a");
1163       return (dname ? "acc" : "a");
1164
1165     case AOP_ACC:
1166       if (!offset && dname)
1167         return "acc";
1168       return aop->aopu.aop_str[offset];
1169
1170     case AOP_LIT:
1171       return aopLiteral (aop->aopu.aop_lit, offset);
1172
1173     case AOP_STR:
1174       aop->coff = offset;
1175       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1176           dname)
1177         return "acc";
1178
1179       return aop->aopu.aop_str[offset];
1180
1181     }
1182
1183   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1184           "aopget got unsupported aop->type");
1185   exit (1);
1186 }
1187 /*-----------------------------------------------------------------*/
1188 /* aopPut - puts a string for a aop                                */
1189 /*-----------------------------------------------------------------*/
1190 static void
1191 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1192 {
1193   char *d = buffer;
1194
1195   if (aop->size && offset > (aop->size - 1))
1196     {
1197       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1198               "aopPut got offset > aop->size");
1199       exit (1);
1200     }
1201
1202   /* will assign value to value */
1203   /* depending on where it is ofcourse */
1204   switch (aop->type)
1205     {
1206     case AOP_DUMMY:
1207       MOVA (s);         /* read s in case it was volatile */
1208       break;
1209
1210     case AOP_DIR:
1211       if (offset)
1212         sprintf (d, "(%s + %d)",
1213                  aop->aopu.aop_dir, offset);
1214       else
1215         sprintf (d, "%s", aop->aopu.aop_dir);
1216
1217       if (strcmp (d, s) ||
1218           bvolatile)
1219         emitcode ("mov", "%s,%s", d, s);
1220
1221       break;
1222
1223     case AOP_REG:
1224       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1225           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1226         {
1227           if (*s == '@' ||
1228               strcmp (s, "r0") == 0 ||
1229               strcmp (s, "r1") == 0 ||
1230               strcmp (s, "r2") == 0 ||
1231               strcmp (s, "r3") == 0 ||
1232               strcmp (s, "r4") == 0 ||
1233               strcmp (s, "r5") == 0 ||
1234               strcmp (s, "r6") == 0 ||
1235               strcmp (s, "r7") == 0)
1236             emitcode ("mov", "%s,%s",
1237                       aop->aopu.aop_reg[offset]->dname, s);
1238           else
1239             emitcode ("mov", "%s,%s",
1240                       aop->aopu.aop_reg[offset]->name, s);
1241         }
1242       break;
1243
1244     case AOP_DPTR:
1245       if (aop->code)
1246         {
1247           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1248                   "aopPut writing to code space");
1249           exit (1);
1250         }
1251
1252       while (offset > aop->coff)
1253         {
1254           aop->coff++;
1255           emitcode ("inc", "dptr");
1256         }
1257
1258       while (offset < aop->coff)
1259         {
1260           aop->coff--;
1261           emitcode ("lcall", "__decdptr");
1262         }
1263
1264       aop->coff = offset;
1265
1266       /* if not in accumulater */
1267       MOVA (s);
1268
1269       emitcode ("movx", "@dptr,a");
1270       break;
1271
1272     case AOP_R0:
1273     case AOP_R1:
1274       while (offset > aop->coff)
1275         {
1276           aop->coff++;
1277           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1278         }
1279       while (offset < aop->coff)
1280         {
1281           aop->coff--;
1282           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1283         }
1284       aop->coff = offset;
1285
1286       if (aop->paged)
1287         {
1288           MOVA (s);
1289           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1290
1291         }
1292       else if (*s == '@')
1293         {
1294           MOVA (s);
1295           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1296         }
1297       else if (strcmp (s, "r0") == 0 ||
1298                strcmp (s, "r1") == 0 ||
1299                strcmp (s, "r2") == 0 ||
1300                strcmp (s, "r3") == 0 ||
1301                strcmp (s, "r4") == 0 ||
1302                strcmp (s, "r5") == 0 ||
1303                strcmp (s, "r6") == 0 ||
1304                strcmp (s, "r7") == 0)
1305         {
1306           char buffer[10];
1307           sprintf (buffer, "a%s", s);
1308           emitcode ("mov", "@%s,%s",
1309                     aop->aopu.aop_ptr->name, buffer);
1310         }
1311       else
1312         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1313
1314       break;
1315
1316     case AOP_STK:
1317       if (strcmp (s, "a") == 0)
1318         emitcode ("push", "acc");
1319       else
1320         if (*s=='@') {
1321           MOVA(s);
1322           emitcode ("push", "acc");
1323         } else {
1324           emitcode ("push", s);
1325         }
1326
1327       break;
1328
1329     case AOP_CRY:
1330       /* if bit variable */
1331       if (!aop->aopu.aop_dir)
1332         {
1333           emitcode ("clr", "a");
1334           emitcode ("rlc", "a");
1335         }
1336       else
1337         {
1338           if (s == zero)
1339             emitcode ("clr", "%s", aop->aopu.aop_dir);
1340           else if (s == one)
1341             emitcode ("setb", "%s", aop->aopu.aop_dir);
1342           else if (!strcmp (s, "c"))
1343             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1344           else
1345             {
1346               if (strcmp (s, "a"))
1347                 {
1348                   MOVA (s);
1349                 }
1350               {
1351                 /* set C, if a >= 1 */
1352                 emitcode ("add", "a,#0xff");
1353                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1354               }
1355             }
1356         }
1357       break;
1358
1359     case AOP_STR:
1360       aop->coff = offset;
1361       if (strcmp (aop->aopu.aop_str[offset], s) ||
1362           bvolatile)
1363         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1364       break;
1365
1366     case AOP_ACC:
1367       aop->coff = offset;
1368       if (!offset && (strcmp (s, "acc") == 0) &&
1369           !bvolatile)
1370         break;
1371
1372       if (strcmp (aop->aopu.aop_str[offset], s) &&
1373           !bvolatile)
1374         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1375       break;
1376
1377     default:
1378       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1379               "aopPut got unsupported aop->type");
1380       exit (1);
1381     }
1382
1383 }
1384
1385
1386 #if 0
1387 /*-----------------------------------------------------------------*/
1388 /* pointToEnd :- points to the last byte of the operand            */
1389 /*-----------------------------------------------------------------*/
1390 static void
1391 pointToEnd (asmop * aop)
1392 {
1393   int count;
1394   if (!aop)
1395     return;
1396
1397   aop->coff = count = (aop->size - 1);
1398   switch (aop->type)
1399     {
1400     case AOP_R0:
1401     case AOP_R1:
1402       while (count--)
1403         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1404       break;
1405     case AOP_DPTR:
1406       while (count--)
1407         emitcode ("inc", "dptr");
1408       break;
1409     }
1410
1411 }
1412 #endif
1413
1414 /*-----------------------------------------------------------------*/
1415 /* reAdjustPreg - points a register back to where it should        */
1416 /*-----------------------------------------------------------------*/
1417 static void
1418 reAdjustPreg (asmop * aop)
1419 {
1420   if ((aop->coff==0) || aop->size <= 1)
1421     return;
1422
1423   switch (aop->type)
1424     {
1425     case AOP_R0:
1426     case AOP_R1:
1427       while (aop->coff--)
1428         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1429       break;
1430     case AOP_DPTR:
1431       while (aop->coff--)
1432         {
1433           emitcode ("lcall", "__decdptr");
1434         }
1435       break;
1436     }
1437   aop->coff = 0;
1438 }
1439
1440 #define AOP(op) op->aop
1441 #define AOP_TYPE(op) AOP(op)->type
1442 #define AOP_SIZE(op) AOP(op)->size
1443 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1444                        AOP_TYPE(x) == AOP_R0))
1445
1446 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1447                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1448
1449 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1450                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1451                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1452
1453
1454 /*-----------------------------------------------------------------*/
1455 /* opIsGptr: returns non-zero if the passed operand is       */
1456 /* a generic pointer type.             */
1457 /*-----------------------------------------------------------------*/
1458 static int
1459 opIsGptr (operand * op)
1460 {
1461   sym_link *type = operandType (op);
1462
1463   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1464     {
1465       return 1;
1466     }
1467   return 0;
1468 }
1469
1470 /*-----------------------------------------------------------------*/
1471 /* getDataSize - get the operand data size                         */
1472 /*-----------------------------------------------------------------*/
1473 static int
1474 getDataSize (operand * op)
1475 {
1476   int size;
1477   size = AOP_SIZE (op);
1478   if (size == GPTRSIZE)
1479     {
1480       sym_link *type = operandType (op);
1481       if (IS_GENPTR (type))
1482         {
1483           /* generic pointer; arithmetic operations
1484            * should ignore the high byte (pointer type).
1485            */
1486           size--;
1487         }
1488     }
1489   return size;
1490 }
1491
1492 /*-----------------------------------------------------------------*/
1493 /* outAcc - output Acc                                             */
1494 /*-----------------------------------------------------------------*/
1495 static void
1496 outAcc (operand * result)
1497 {
1498   int size, offset;
1499   size = getDataSize (result);
1500   if (size)
1501     {
1502       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1503       size--;
1504       offset = 1;
1505       /* unsigned or positive */
1506       while (size--)
1507         {
1508           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1509         }
1510     }
1511 }
1512
1513 /*-----------------------------------------------------------------*/
1514 /* outBitC - output a bit C                                        */
1515 /*-----------------------------------------------------------------*/
1516 static void
1517 outBitC (operand * result)
1518 {
1519   /* if the result is bit */
1520   if (AOP_TYPE (result) == AOP_CRY)
1521     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1522   else
1523     {
1524       emitcode ("clr", "a");
1525       emitcode ("rlc", "a");
1526       outAcc (result);
1527     }
1528 }
1529
1530 /*-----------------------------------------------------------------*/
1531 /* toBoolean - emit code for orl a,operator(sizeop)                */
1532 /*-----------------------------------------------------------------*/
1533 static void
1534 toBoolean (operand * oper)
1535 {
1536   int size = AOP_SIZE (oper) - 1;
1537   int offset = 1;
1538   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1539   while (size--)
1540     emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1541 }
1542
1543
1544 /*-----------------------------------------------------------------*/
1545 /* genNot - generate code for ! operation                          */
1546 /*-----------------------------------------------------------------*/
1547 static void
1548 genNot (iCode * ic)
1549 {
1550   symbol *tlbl;
1551
1552   D(emitcode (";     genNot",""));
1553
1554   /* assign asmOps to operand & result */
1555   aopOp (IC_LEFT (ic), ic, FALSE);
1556   aopOp (IC_RESULT (ic), ic, TRUE);
1557
1558   /* if in bit space then a special case */
1559   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1560     {
1561       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1562       emitcode ("cpl", "c");
1563       outBitC (IC_RESULT (ic));
1564       goto release;
1565     }
1566
1567   toBoolean (IC_LEFT (ic));
1568
1569   tlbl = newiTempLabel (NULL);
1570   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1571   emitcode ("", "%05d$:", tlbl->key + 100);
1572   outBitC (IC_RESULT (ic));
1573
1574 release:
1575   /* release the aops */
1576   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1577   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1578 }
1579
1580
1581 /*-----------------------------------------------------------------*/
1582 /* genCpl - generate code for complement                           */
1583 /*-----------------------------------------------------------------*/
1584 static void
1585 genCpl (iCode * ic)
1586 {
1587   int offset = 0;
1588   int size;
1589   symbol *tlbl;
1590
1591   D(emitcode (";     genCpl",""));
1592
1593   /* assign asmOps to operand & result */
1594   aopOp (IC_LEFT (ic), ic, FALSE);
1595   aopOp (IC_RESULT (ic), ic, TRUE);
1596
1597   /* special case if in bit space */
1598   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1599     {
1600       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1601         {
1602           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1603           emitcode ("cpl", "c");
1604           emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1605           goto release;
1606         }
1607
1608       tlbl=newiTempLabel(NULL);
1609       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1610           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1611           IS_AOP_PREG (IC_LEFT (ic)))
1612         {
1613           emitcode ("cjne", "%s,#0x01,%05d$",
1614                     aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
1615                     tlbl->key + 100);
1616         }
1617       else
1618         {
1619           char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
1620           MOVA (l);
1621           emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1622         }
1623       emitcode ("", "%05d$:", tlbl->key + 100);
1624       outBitC (IC_RESULT(ic));
1625       goto release;
1626     }
1627
1628   size = AOP_SIZE (IC_RESULT (ic));
1629   while (size--)
1630     {
1631       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1632       MOVA (l);
1633       emitcode ("cpl", "a");
1634       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1635     }
1636
1637
1638 release:
1639   /* release the aops */
1640   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1641   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1642 }
1643
1644 /*-----------------------------------------------------------------*/
1645 /* genUminusFloat - unary minus for floating points                */
1646 /*-----------------------------------------------------------------*/
1647 static void
1648 genUminusFloat (operand * op, operand * result)
1649 {
1650   int size, offset = 0;
1651   char *l;
1652
1653   D(emitcode (";     genUminusFloat",""));
1654
1655   /* for this we just copy and then flip the bit */
1656
1657   size = AOP_SIZE (op) - 1;
1658
1659   while (size--)
1660     {
1661       aopPut (AOP (result),
1662               aopGet (AOP (op), offset, FALSE, FALSE),
1663               offset,
1664               isOperandVolatile (result, FALSE));
1665       offset++;
1666     }
1667
1668   l = aopGet (AOP (op), offset, FALSE, FALSE);
1669
1670   MOVA (l);
1671
1672   emitcode ("cpl", "acc.7");
1673   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1674 }
1675
1676 /*-----------------------------------------------------------------*/
1677 /* genUminus - unary minus code generation                         */
1678 /*-----------------------------------------------------------------*/
1679 static void
1680 genUminus (iCode * ic)
1681 {
1682   int offset, size;
1683   sym_link *optype, *rtype;
1684
1685
1686   D(emitcode (";     genUminus",""));
1687
1688   /* assign asmops */
1689   aopOp (IC_LEFT (ic), ic, FALSE);
1690   aopOp (IC_RESULT (ic), ic, TRUE);
1691
1692   /* if both in bit space then special
1693      case */
1694   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1695       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1696     {
1697
1698       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1699       emitcode ("cpl", "c");
1700       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1701       goto release;
1702     }
1703
1704   optype = operandType (IC_LEFT (ic));
1705   rtype = operandType (IC_RESULT (ic));
1706
1707   /* if float then do float stuff */
1708   if (IS_FLOAT (optype))
1709     {
1710       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1711       goto release;
1712     }
1713
1714   /* otherwise subtract from zero */
1715   size = AOP_SIZE (IC_LEFT (ic));
1716   offset = 0;
1717   //CLRC ;
1718   while (size--)
1719     {
1720       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1721       if (!strcmp (l, "a"))
1722         {
1723           if (offset == 0)
1724             SETC;
1725           emitcode ("cpl", "a");
1726           emitcode ("addc", "a,#0");
1727         }
1728       else
1729         {
1730           if (offset == 0)
1731             CLRC;
1732           emitcode ("clr", "a");
1733           emitcode ("subb", "a,%s", l);
1734         }
1735       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1736     }
1737
1738   /* if any remaining bytes in the result */
1739   /* we just need to propagate the sign   */
1740   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1741     {
1742       emitcode ("rlc", "a");
1743       emitcode ("subb", "a,acc");
1744       while (size--)
1745         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1746     }
1747
1748 release:
1749   /* release the aops */
1750   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1751   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1752 }
1753
1754 /*-----------------------------------------------------------------*/
1755 /* saveRegisters - will look for a call and save the registers     */
1756 /*-----------------------------------------------------------------*/
1757 static void
1758 saveRegisters (iCode * lic)
1759 {
1760   int i;
1761   iCode *ic;
1762   bitVect *rsave;
1763
1764   /* look for call */
1765   for (ic = lic; ic; ic = ic->next)
1766     if (ic->op == CALL || ic->op == PCALL)
1767       break;
1768
1769   if (!ic)
1770     {
1771       fprintf (stderr, "found parameter push with no function call\n");
1772       return;
1773     }
1774
1775   /* if the registers have been saved already or don't need to be then
1776      do nothing */
1777   if (ic->regsSaved)
1778     return;
1779   if (IS_SYMOP(IC_LEFT(ic)) &&
1780       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1781        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1782     return;
1783
1784   /* safe the registers in use at this time but skip the
1785      ones for the result */
1786   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1787                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1788
1789   ic->regsSaved = 1;
1790   if (options.useXstack)
1791     {
1792       if (bitVectBitValue (rsave, R0_IDX))
1793         emitcode ("mov", "b,r0");
1794       emitcode ("mov", "r0,%s", spname);
1795       for (i = 0; i < mcs51_nRegs; i++)
1796         {
1797           if (bitVectBitValue (rsave, i))
1798             {
1799               if (i == R0_IDX)
1800                 emitcode ("mov", "a,b");
1801               else
1802                 emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1803               emitcode ("movx", "@r0,a");
1804               emitcode ("inc", "r0");
1805             }
1806         }
1807       emitcode ("mov", "%s,r0", spname);
1808       if (bitVectBitValue (rsave, R0_IDX))
1809         emitcode ("mov", "r0,b");
1810     }
1811   else
1812     for (i = 0; i < mcs51_nRegs; i++)
1813       {
1814         if (bitVectBitValue (rsave, i))
1815           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1816       }
1817 }
1818
1819 /*-----------------------------------------------------------------*/
1820 /* unsaveRegisters - pop the pushed registers                      */
1821 /*-----------------------------------------------------------------*/
1822 static void
1823 unsaveRegisters (iCode * ic)
1824 {
1825   int i;
1826   bitVect *rsave;
1827
1828   /* restore the registers in use at this time but skip the
1829      ones for the result */
1830   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1831                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1832
1833   if (options.useXstack)
1834     {
1835       emitcode ("mov", "r0,%s", spname);
1836       for (i = mcs51_nRegs; i >= 0; i--)
1837         {
1838           if (bitVectBitValue (rsave, i))
1839             {
1840               emitcode ("dec", "r0");
1841               emitcode ("movx", "a,@r0");
1842               if (i == R0_IDX)
1843                 emitcode ("mov", "b,a");
1844               else
1845                 emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1846             }
1847
1848         }
1849       emitcode ("mov", "%s,r0", spname);
1850       if (bitVectBitValue (rsave, R0_IDX))
1851         emitcode ("mov", "r0,b");
1852     }
1853   else
1854     for (i = mcs51_nRegs; i >= 0; i--)
1855       {
1856         if (bitVectBitValue (rsave, i))
1857           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
1858       }
1859
1860 }
1861
1862
1863 /*-----------------------------------------------------------------*/
1864 /* pushSide -                */
1865 /*-----------------------------------------------------------------*/
1866 static void
1867 pushSide (operand * oper, int size)
1868 {
1869   int offset = 0;
1870   while (size--)
1871     {
1872       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
1873       if (AOP_TYPE (oper) != AOP_REG &&
1874           AOP_TYPE (oper) != AOP_DIR &&
1875           strcmp (l, "a"))
1876         {
1877           MOVA (l);
1878           emitcode ("push", "acc");
1879         }
1880       else
1881         emitcode ("push", "%s", l);
1882     }
1883 }
1884
1885 /*-----------------------------------------------------------------*/
1886 /* assignResultValue -               */
1887 /*-----------------------------------------------------------------*/
1888 static void
1889 assignResultValue (operand * oper)
1890 {
1891   int offset = 0;
1892   int size = AOP_SIZE (oper);
1893   while (size--)
1894     {
1895       aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
1896       offset++;
1897     }
1898 }
1899
1900
1901 /*-----------------------------------------------------------------*/
1902 /* genXpush - pushes onto the external stack                       */
1903 /*-----------------------------------------------------------------*/
1904 static void
1905 genXpush (iCode * ic)
1906 {
1907   asmop *aop = newAsmop (0);
1908   regs *r;
1909   int size, offset = 0;
1910
1911   D(emitcode (";     genXpush",""));
1912
1913   aopOp (IC_LEFT (ic), ic, FALSE);
1914   r = getFreePtr (ic, &aop, FALSE);
1915
1916
1917   emitcode ("mov", "%s,_spx", r->name);
1918
1919   size = AOP_SIZE (IC_LEFT (ic));
1920   while (size--)
1921     {
1922
1923       char *l = aopGet (AOP (IC_LEFT (ic)),
1924                         offset++, FALSE, FALSE);
1925       MOVA (l);
1926       emitcode ("movx", "@%s,a", r->name);
1927       emitcode ("inc", "%s", r->name);
1928
1929     }
1930
1931
1932   emitcode ("mov", "_spx,%s", r->name);
1933
1934   freeAsmop (NULL, aop, ic, TRUE);
1935   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* genIpush - genrate code for pushing this gets a little complex  */
1940 /*-----------------------------------------------------------------*/
1941 static void
1942 genIpush (iCode * ic)
1943 {
1944   int size, offset = 0;
1945   char *l;
1946
1947   D(emitcode (";     genIpush",""));
1948
1949   /* if this is not a parm push : ie. it is spill push
1950      and spill push is always done on the local stack */
1951   if (!ic->parmPush)
1952     {
1953
1954       /* and the item is spilt then do nothing */
1955       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1956         return;
1957
1958       aopOp (IC_LEFT (ic), ic, FALSE);
1959       size = AOP_SIZE (IC_LEFT (ic));
1960       /* push it on the stack */
1961       while (size--)
1962         {
1963           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
1964           if (*l == '#')
1965             {
1966               MOVA (l);
1967               l = "acc";
1968             }
1969           emitcode ("push", "%s", l);
1970         }
1971       return;
1972     }
1973
1974   /* this is a paramter push: in this case we call
1975      the routine to find the call and save those
1976      registers that need to be saved */
1977   saveRegisters (ic);
1978
1979   /* if use external stack then call the external
1980      stack pushing routine */
1981   if (options.useXstack)
1982     {
1983       genXpush (ic);
1984       return;
1985     }
1986
1987   /* then do the push */
1988   aopOp (IC_LEFT (ic), ic, FALSE);
1989
1990
1991   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
1992   size = AOP_SIZE (IC_LEFT (ic));
1993
1994   while (size--)
1995     {
1996       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
1997       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
1998           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
1999           strcmp (l, "a"))
2000         {
2001           MOVA (l);
2002           emitcode ("push", "acc");
2003         }
2004       else
2005         emitcode ("push", "%s", l);
2006     }
2007
2008   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2009 }
2010
2011 /*-----------------------------------------------------------------*/
2012 /* genIpop - recover the registers: can happen only for spilling   */
2013 /*-----------------------------------------------------------------*/
2014 static void
2015 genIpop (iCode * ic)
2016 {
2017   int size, offset;
2018
2019   D(emitcode (";     genIpop",""));
2020
2021   /* if the temp was not pushed then */
2022   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2023     return;
2024
2025   aopOp (IC_LEFT (ic), ic, FALSE);
2026   size = AOP_SIZE (IC_LEFT (ic));
2027   offset = (size - 1);
2028   while (size--)
2029     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2030                                    FALSE, TRUE));
2031
2032   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2033 }
2034
2035 /*-----------------------------------------------------------------*/
2036 /* unsaveRBank - restores the resgister bank from stack            */
2037 /*-----------------------------------------------------------------*/
2038 static void
2039 unsaveRBank (int bank, iCode * ic, bool popPsw)
2040 {
2041   int i;
2042   asmop *aop = NULL;
2043   regs *r = NULL;
2044
2045   if (options.useXstack)
2046   {
2047       if (!ic)
2048       {
2049           /* Assume r0 is available for use. */
2050           r = mcs51_regWithIdx (R0_IDX);;
2051       }
2052       else
2053       {
2054           aop = newAsmop (0);
2055           r = getFreePtr (ic, &aop, FALSE);
2056       }
2057       emitcode ("mov", "%s,_spx", r->name);
2058   }
2059
2060   if (popPsw)
2061     {
2062       if (options.useXstack)
2063       {
2064           emitcode ("movx", "a,@%s", r->name);
2065           emitcode ("mov", "psw,a");
2066           emitcode ("dec", "%s", r->name);
2067         }
2068       else
2069       {
2070         emitcode ("pop", "psw");
2071       }
2072     }
2073
2074   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2075     {
2076       if (options.useXstack)
2077         {
2078           emitcode ("movx", "a,@%s", r->name);
2079           emitcode ("mov", "(%s+%d),a",
2080                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2081           emitcode ("dec", "%s", r->name);
2082
2083         }
2084       else
2085         emitcode ("pop", "(%s+%d)",
2086                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2087     }
2088
2089   if (options.useXstack)
2090     {
2091       emitcode ("mov", "_spx,%s", r->name);
2092     }
2093
2094   if (aop)
2095   {
2096       freeAsmop (NULL, aop, ic, TRUE);
2097   }
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* saveRBank - saves an entire register bank on the stack          */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 saveRBank (int bank, iCode * ic, bool pushPsw)
2105 {
2106   int i;
2107   asmop *aop = NULL;
2108   regs *r = NULL;
2109
2110   if (options.useXstack)
2111     {
2112       if (!ic)
2113       {
2114           /* Assume r0 is available for use. */
2115           r = mcs51_regWithIdx (R0_IDX);;
2116       }
2117       else
2118       {
2119           aop = newAsmop (0);
2120           r = getFreePtr (ic, &aop, FALSE);
2121       }
2122       emitcode ("mov", "%s,_spx", r->name);
2123     }
2124
2125   for (i = 0; i < mcs51_nRegs; i++)
2126     {
2127       if (options.useXstack)
2128         {
2129           emitcode ("inc", "%s", r->name);
2130           emitcode ("mov", "a,(%s+%d)",
2131                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2132           emitcode ("movx", "@%s,a", r->name);
2133         }
2134       else
2135         emitcode ("push", "(%s+%d)",
2136                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2137     }
2138
2139   if (pushPsw)
2140     {
2141       if (options.useXstack)
2142         {
2143           emitcode ("mov", "a,psw");
2144           emitcode ("movx", "@%s,a", r->name);
2145           emitcode ("inc", "%s", r->name);
2146           emitcode ("mov", "_spx,%s", r->name);
2147
2148         }
2149       else
2150       {
2151         emitcode ("push", "psw");
2152       }
2153
2154       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2155     }
2156
2157     if (aop)
2158     {
2159         freeAsmop (NULL, aop, ic, TRUE);
2160     }
2161
2162   if (ic)
2163   {
2164       ic->bankSaved = 1;
2165   }
2166 }
2167
2168 /*-----------------------------------------------------------------*/
2169 /* genSend - gen code for SEND                                     */
2170 /*-----------------------------------------------------------------*/
2171 static void genSend(set *sendSet)
2172 {
2173     iCode *sic;
2174     int rb1_count = 0 ;
2175
2176     for (sic = setFirstItem (_G.sendSet); sic;
2177          sic = setNextItem (_G.sendSet)) {
2178           int size, offset = 0;
2179           aopOp (IC_LEFT (sic), sic, FALSE);
2180           size = AOP_SIZE (IC_LEFT (sic));
2181
2182           if (sic->argreg == 1) {
2183               while (size--) {
2184                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2185                                     FALSE, FALSE);
2186                   if (strcmp (l, fReturn[offset]))
2187                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2188                   offset++;
2189               }
2190               rb1_count = 0;
2191           } else {
2192               while (size--) {
2193                   emitcode ("mov","b1_%d,%s",rb1_count++,
2194                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2195               }
2196           }
2197           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2198     }
2199 }
2200
2201 /*-----------------------------------------------------------------*/
2202 /* genCall - generates a call statement                            */
2203 /*-----------------------------------------------------------------*/
2204 static void
2205 genCall (iCode * ic)
2206 {
2207   sym_link *dtype;
2208 //  bool restoreBank = FALSE;
2209   bool swapBanks = FALSE;
2210
2211   D(emitcode(";     genCall",""));
2212
2213   dtype = operandType (IC_LEFT (ic));
2214   /* if send set is not empty the assign */
2215   if (_G.sendSet)
2216     {
2217         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2218             genSend(reverseSet(_G.sendSet));
2219         } else {
2220             genSend(_G.sendSet);
2221         }
2222
2223       _G.sendSet = NULL;
2224     }
2225
2226   /* if we are calling a not _naked function that is not using
2227      the same register bank then we need to save the
2228      destination registers on the stack */
2229   dtype = operandType (IC_LEFT (ic));
2230   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2231       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2232        !IFFUNC_ISISR (dtype))
2233   {
2234       swapBanks = TRUE;
2235   }
2236
2237   /* if caller saves & we have not saved then */
2238   if (!ic->regsSaved)
2239       saveRegisters (ic);
2240
2241   if (swapBanks)
2242   {
2243         emitcode ("mov", "psw,#0x%02x",
2244            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2245   }
2246
2247   /* make the call */
2248   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2249                             OP_SYMBOL (IC_LEFT (ic))->rname :
2250                             OP_SYMBOL (IC_LEFT (ic))->name));
2251
2252   if (swapBanks)
2253   {
2254        emitcode ("mov", "psw,#0x%02x",
2255           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2256   }
2257
2258   /* if we need assign a result value */
2259   if ((IS_ITEMP (IC_RESULT (ic)) &&
2260        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2261         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2262         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2263       IS_TRUE_SYMOP (IC_RESULT (ic)))
2264     {
2265
2266       _G.accInUse++;
2267       aopOp (IC_RESULT (ic), ic, FALSE);
2268       _G.accInUse--;
2269
2270       assignResultValue (IC_RESULT (ic));
2271
2272       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2273     }
2274
2275   /* adjust the stack for parameters if
2276      required */
2277   if (ic->parmBytes)
2278     {
2279       int i;
2280       if (ic->parmBytes > 3)
2281         {
2282           emitcode ("mov", "a,%s", spname);
2283           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2284           emitcode ("mov", "%s,a", spname);
2285         }
2286       else
2287         for (i = 0; i < ic->parmBytes; i++)
2288           emitcode ("dec", "%s", spname);
2289     }
2290
2291   /* if we hade saved some registers then unsave them */
2292   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2293     unsaveRegisters (ic);
2294
2295 //  /* if register bank was saved then pop them */
2296 //  if (restoreBank)
2297 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2298 }
2299
2300 /*-----------------------------------------------------------------*/
2301 /* -10l - generates a call by pointer statement                */
2302 /*-----------------------------------------------------------------*/
2303 static void
2304 genPcall (iCode * ic)
2305 {
2306   sym_link *dtype;
2307   symbol *rlbl = newiTempLabel (NULL);
2308 //  bool restoreBank=FALSE;
2309   bool swapBanks = FALSE;
2310
2311   D(emitcode(";     genPCall",""));
2312
2313   /* if caller saves & we have not saved then */
2314   if (!ic->regsSaved)
2315     saveRegisters (ic);
2316
2317   /* if we are calling a not _naked function that is not using
2318      the same register bank then we need to save the
2319      destination registers on the stack */
2320   dtype = operandType (IC_LEFT (ic))->next;
2321   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2322       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2323       !IFFUNC_ISISR (dtype))
2324   {
2325 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2326 //    restoreBank=TRUE;
2327       swapBanks = TRUE;
2328       // need caution message to user here
2329   }
2330
2331   /* push the return address on to the stack */
2332   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2333   emitcode ("push", "acc");
2334   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2335   emitcode ("push", "acc");
2336
2337   /* now push the calling address */
2338   aopOp (IC_LEFT (ic), ic, FALSE);
2339
2340   pushSide (IC_LEFT (ic), FPTRSIZE);
2341
2342   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2343
2344   /* if send set is not empty the assign */
2345   if (_G.sendSet)
2346     {
2347         genSend(reverseSet(_G.sendSet));
2348         _G.sendSet = NULL;
2349     }
2350
2351   if (swapBanks)
2352   {
2353         emitcode ("mov", "psw,#0x%02x",
2354            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2355   }
2356
2357   /* make the call */
2358   emitcode ("ret", "");
2359   emitcode ("", "%05d$:", (rlbl->key + 100));
2360
2361
2362   if (swapBanks)
2363   {
2364        emitcode ("mov", "psw,#0x%02x",
2365           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2366   }
2367
2368   /* if we need assign a result value */
2369   if ((IS_ITEMP (IC_RESULT (ic)) &&
2370        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2371         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2372       IS_TRUE_SYMOP (IC_RESULT (ic)))
2373     {
2374
2375       _G.accInUse++;
2376       aopOp (IC_RESULT (ic), ic, FALSE);
2377       _G.accInUse--;
2378
2379       assignResultValue (IC_RESULT (ic));
2380
2381       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2382     }
2383
2384   /* adjust the stack for parameters if
2385      required */
2386   if (ic->parmBytes)
2387     {
2388       int i;
2389       if (ic->parmBytes > 3)
2390         {
2391           emitcode ("mov", "a,%s", spname);
2392           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2393           emitcode ("mov", "%s,a", spname);
2394         }
2395       else
2396         for (i = 0; i < ic->parmBytes; i++)
2397           emitcode ("dec", "%s", spname);
2398
2399     }
2400
2401 //  /* if register bank was saved then unsave them */
2402 //  if (restoreBank)
2403 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2404
2405   /* if we hade saved some registers then
2406      unsave them */
2407   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2408     unsaveRegisters (ic);
2409 }
2410
2411 /*-----------------------------------------------------------------*/
2412 /* resultRemat - result  is rematerializable                       */
2413 /*-----------------------------------------------------------------*/
2414 static int
2415 resultRemat (iCode * ic)
2416 {
2417   if (SKIP_IC (ic) || ic->op == IFX)
2418     return 0;
2419
2420   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2421     {
2422       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2423       if (sym->remat && !POINTER_SET (ic))
2424         return 1;
2425     }
2426
2427   return 0;
2428 }
2429
2430 #if defined(__BORLANDC__) || defined(_MSC_VER)
2431 #define STRCASECMP stricmp
2432 #else
2433 #define STRCASECMP strcasecmp
2434 #endif
2435
2436 /*-----------------------------------------------------------------*/
2437 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2438 /*-----------------------------------------------------------------*/
2439 static int
2440 regsCmp(void *p1, void *p2)
2441 {
2442   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2443 }
2444
2445 static bool
2446 inExcludeList (char *s)
2447 {
2448   const char *p = setFirstItem(options.excludeRegsSet);
2449
2450   if (p == NULL || STRCASECMP(p, "none") == 0)
2451     return FALSE;
2452
2453
2454   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2455 }
2456
2457 /*-----------------------------------------------------------------*/
2458 /* genFunction - generated code for function entry                 */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 genFunction (iCode * ic)
2462 {
2463   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2464   sym_link *ftype;
2465   bool   switchedPSW = FALSE;
2466   int calleesaves_saved_register = -1;
2467   int stackAdjust = sym->stack;
2468   int accIsFree = sym->recvSize < 4;
2469   iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2470
2471   _G.nRegsSaved = 0;
2472   /* create the function header */
2473   emitcode (";", "-----------------------------------------");
2474   emitcode (";", " function %s", sym->name);
2475   emitcode (";", "-----------------------------------------");
2476
2477   emitcode ("", "%s:", sym->rname);
2478   ftype = operandType (IC_LEFT (ic));
2479   _G.currentFunc = sym;
2480
2481   if (IFFUNC_ISNAKED(ftype))
2482   {
2483       emitcode(";", "naked function: no prologue.");
2484       return;
2485   }
2486   
2487   /* here we need to generate the equates for the
2488      register bank if required */
2489   if (FUNC_REGBANK (ftype) != rbank)
2490     {
2491       int i;
2492
2493       rbank = FUNC_REGBANK (ftype);
2494       for (i = 0; i < mcs51_nRegs; i++)
2495         {
2496           if (strcmp (regs8051[i].base, "0") == 0)
2497             emitcode ("", "%s = 0x%02x",
2498                       regs8051[i].dname,
2499                       8 * rbank + regs8051[i].offset);
2500           else
2501             emitcode ("", "%s = %s + 0x%02x",
2502                       regs8051[i].dname,
2503                       regs8051[i].base,
2504                       8 * rbank + regs8051[i].offset);
2505         }
2506     }
2507
2508   /* if this is an interrupt service routine then
2509      save acc, b, dpl, dph  */
2510   if (IFFUNC_ISISR (sym->type))
2511     {
2512
2513       if (!inExcludeList ("acc"))
2514         emitcode ("push", "acc");
2515       if (!inExcludeList ("b"))
2516         emitcode ("push", "b");
2517       if (!inExcludeList ("dpl"))
2518         emitcode ("push", "dpl");
2519       if (!inExcludeList ("dph"))
2520         emitcode ("push", "dph");
2521       /* if this isr has no bank i.e. is going to
2522          run with bank 0 , then we need to save more
2523          registers :-) */
2524       if (!FUNC_REGBANK (sym->type))
2525         {
2526
2527           /* if this function does not call any other
2528              function then we can be economical and
2529              save only those registers that are used */
2530           if (!IFFUNC_HASFCALL(sym->type))
2531             {
2532               int i;
2533
2534               /* if any registers used */
2535               if (sym->regsUsed)
2536                 {
2537                   /* save the registers used */
2538                   for (i = 0; i < sym->regsUsed->size; i++)
2539                     {
2540                       if (bitVectBitValue (sym->regsUsed, i))
2541                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2542                     }
2543                 }
2544             }
2545           else
2546             {
2547
2548               /* this function has a function call. We cannot
2549                  determines register usage so we will have to push the
2550                  entire bank */
2551                 saveRBank (0, ic, FALSE);
2552                 if (options.parms_in_bank1) {
2553                     int i;
2554                     for (i=0; i < 8 ; i++ ) {
2555                         emitcode ("push","%s",rb1regs[i]);
2556                     }
2557                 }
2558             }
2559         }
2560         else
2561         {
2562             /* This ISR uses a non-zero bank.
2563              *
2564              * We assume that the bank is available for our
2565              * exclusive use.
2566              *
2567              * However, if this ISR calls a function which uses some
2568              * other bank, we must save that bank entirely.
2569              */
2570             unsigned long banksToSave = 0;
2571
2572             if (IFFUNC_HASFCALL(sym->type))
2573             {
2574
2575 #define MAX_REGISTER_BANKS 4
2576
2577                 iCode *i;
2578                 int ix;
2579
2580                 for (i = ic; i; i = i->next)
2581                 {
2582                     if (i->op == ENDFUNCTION)
2583                     {
2584                         /* we got to the end OK. */
2585                         break;
2586                     }
2587
2588                     if (i->op == CALL)
2589                     {
2590                         sym_link *dtype;
2591
2592                         dtype = operandType (IC_LEFT(i));
2593                         if (dtype
2594                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2595                         {
2596                              /* Mark this bank for saving. */
2597                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2598                              {
2599                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2600                              }
2601                              else
2602                              {
2603                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2604                              }
2605
2606                              /* And note that we don't need to do it in
2607                               * genCall.
2608                               */
2609                              i->bankSaved = 1;
2610                         }
2611                     }
2612                     if (i->op == PCALL)
2613                     {
2614                         /* This is a mess; we have no idea what
2615                          * register bank the called function might
2616                          * use.
2617                          *
2618                          * The only thing I can think of to do is
2619                          * throw a warning and hope.
2620                          */
2621                         werror(W_FUNCPTR_IN_USING_ISR);
2622                     }
2623                 }
2624
2625                 if (banksToSave && options.useXstack)
2626                 {
2627                     /* Since we aren't passing it an ic,
2628                      * saveRBank will assume r0 is available to abuse.
2629                      *
2630                      * So switch to our (trashable) bank now, so
2631                      * the caller's R0 isn't trashed.
2632                      */
2633                     emitcode ("push", "psw");
2634                     emitcode ("mov", "psw,#0x%02x",
2635                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2636                     switchedPSW = TRUE;
2637                 }
2638
2639                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2640                 {
2641                      if (banksToSave & (1 << ix))
2642                      {
2643                          saveRBank(ix, NULL, FALSE);
2644                      }
2645                 }
2646             }
2647             // TODO: this needs a closer look
2648             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2649         }
2650       
2651       /* Set the register bank to the desired value if nothing else */
2652       /* has done so yet. */
2653       if (!switchedPSW)
2654         {
2655           emitcode ("push", "psw");
2656           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2657         }
2658     }
2659   else
2660     {
2661       /* This is a non-ISR function. The caller has already switched register */
2662       /* banks, if necessary, so just handle the callee-saves option. */
2663       
2664       /* if callee-save to be used for this function
2665          then save the registers being used in this function */
2666       if (IFFUNC_CALLEESAVES(sym->type))
2667         {
2668           int i;
2669
2670           /* if any registers used */
2671           if (sym->regsUsed)
2672             {
2673               /* save the registers used */
2674               for (i = 0; i < sym->regsUsed->size; i++)
2675                 {
2676                   if (bitVectBitValue (sym->regsUsed, i))
2677                     {
2678                       /* remember one saved register for later usage */
2679                       if (calleesaves_saved_register < 0)
2680                         calleesaves_saved_register = i;
2681                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2682                       _G.nRegsSaved++;
2683                     }
2684                 }
2685             }
2686         }
2687     }
2688
2689
2690   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2691     {
2692
2693       if (options.useXstack)
2694         {
2695           if (!accIsFree)
2696             emitcode ("push", "acc");
2697           emitcode ("mov", "r0,%s", spname);
2698           emitcode ("mov", "a,_bp");
2699           emitcode ("movx", "@r0,a");
2700           emitcode ("inc", "%s", spname);
2701           if (!accIsFree)
2702             emitcode ("pop", "acc");
2703         }
2704       else
2705         {
2706           /* set up the stack */
2707           emitcode ("push", "_bp");     /* save the callers stack  */
2708         }
2709       emitcode ("mov", "_bp,%s", spname);
2710     }
2711   
2712   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2713   /* before setting up the stack frame completely. */
2714   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2715     {
2716       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2717       
2718       if (rsym->isitmp)
2719         {
2720           if (rsym && rsym->regType == REG_CND)
2721             rsym = NULL;
2722           if (rsym && (rsym->accuse || rsym->ruonly))
2723             rsym = NULL;
2724           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2725             rsym = rsym->usl.spillLoc;
2726         }
2727       
2728       /* If the RECEIVE operand immediately spills to the first entry on the */
2729       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2730       /* rather than the usual @r0/r1 machinations. */
2731       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2732         {
2733           int ofs;
2734           
2735           _G.current_iCode = ric;
2736           D(emitcode (";     genReceive",""));
2737           for (ofs=0; ofs < sym->recvSize; ofs++)
2738             {
2739               if (!strcmp (fReturn[ofs], "a"))
2740                 emitcode ("push", "acc");
2741               else
2742                 emitcode ("push", fReturn[ofs]);
2743             }
2744           stackAdjust -= sym->recvSize;
2745           if (stackAdjust<0)
2746             {
2747               assert (stackAdjust>=0);
2748               stackAdjust = 0;
2749             }
2750           _G.current_iCode = ic;
2751           ric->generated = 1;
2752           accIsFree = 1;
2753         }
2754       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2755       /* to free up the accumulator. */
2756       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2757         {
2758           int ofs;
2759           
2760           _G.current_iCode = ric;
2761           D(emitcode (";     genReceive",""));
2762           for (ofs=0; ofs < sym->recvSize; ofs++)
2763             {
2764               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2765             }
2766           _G.current_iCode = ic;
2767           ric->generated = 1;
2768           accIsFree = 1;
2769         }
2770     }
2771   
2772   /* adjust the stack for the function */
2773   if (stackAdjust)
2774     {
2775
2776       int i = stackAdjust;
2777       if (i > 256)
2778         werror (W_STACK_OVERFLOW, sym->name);
2779
2780       if (i > 3 && accIsFree)
2781         {
2782
2783           emitcode ("mov", "a,sp");
2784           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2785           emitcode ("mov", "sp,a");
2786
2787         }
2788       else if (i > 5)
2789         {
2790           /* The accumulator is not free, so we will need another register */
2791           /* to clobber. No need to worry about a possible conflict with */
2792           /* the above early RECEIVE optimizations since they would have */
2793           /* freed the accumulator if they were generated. */
2794           
2795           if (IFFUNC_CALLEESAVES(sym->type))
2796             {
2797               /* if it's a callee-saves function we need a saved register */
2798               if (calleesaves_saved_register >= 0)
2799                 {
2800                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2801                   emitcode ("mov", "a,sp");
2802                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2803                   emitcode ("mov", "sp,a");
2804                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2805                 }
2806               else
2807                 /* do it the hard way */
2808                 while (i--)
2809                   emitcode ("inc", "sp");
2810             }
2811           else
2812             {
2813               /* not callee-saves, we can clobber r0 */
2814               emitcode ("mov", "r0,a");
2815               emitcode ("mov", "a,sp");
2816               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2817               emitcode ("mov", "sp,a");
2818               emitcode ("mov", "a,r0");
2819             }
2820         }
2821       else
2822         while (i--)
2823           emitcode ("inc", "sp");
2824     }
2825
2826   if (sym->xstack)
2827     {
2828
2829       if (!accIsFree)
2830         emitcode ("push", "acc");
2831       emitcode ("mov", "a,_spx");
2832       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
2833       emitcode ("mov", "_spx,a");
2834       if (!accIsFree)
2835         emitcode ("pop", "acc");
2836     }
2837
2838   /* if critical function then turn interrupts off */
2839   if (IFFUNC_ISCRITICAL (ftype))
2840     {
2841       symbol *tlbl = newiTempLabel (NULL);
2842       emitcode ("setb", "c");
2843       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2844       emitcode ("clr", "c");
2845       emitcode ("", "%05d$:", (tlbl->key + 100));
2846       emitcode ("push", "psw"); /* save old ea via c in psw */
2847     }
2848 }
2849
2850 /*-----------------------------------------------------------------*/
2851 /* genEndFunction - generates epilogue for functions               */
2852 /*-----------------------------------------------------------------*/
2853 static void
2854 genEndFunction (iCode * ic)
2855 {
2856   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2857   lineNode *lnp = lineCurr;
2858   bitVect *regsUsed;
2859   bitVect *regsUsedPrologue;
2860   bitVect *regsUnneeded;
2861   int idx;
2862   
2863   _G.currentFunc = NULL;
2864   if (IFFUNC_ISNAKED(sym->type))
2865   {
2866       emitcode(";", "naked function: no epilogue.");
2867       return;
2868   }
2869
2870   if (IFFUNC_ISCRITICAL (sym->type))
2871     {
2872       emitcode ("pop", "psw"); /* restore ea via c in psw */
2873       emitcode ("mov", "ea,c");
2874     }
2875
2876   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2877     {
2878       emitcode ("mov", "%s,_bp", spname);
2879     }
2880
2881   /* if use external stack but some variables were
2882      added to the local stack then decrement the
2883      local stack */
2884   if (options.useXstack && sym->stack)
2885     {
2886       emitcode ("mov", "a,sp");
2887       emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
2888       emitcode ("mov", "sp,a");
2889     }
2890
2891
2892   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
2893     {
2894       if (options.useXstack)
2895         {
2896           emitcode ("mov", "r0,%s", spname);
2897           emitcode ("movx", "a,@r0");
2898           emitcode ("mov", "_bp,a");
2899           emitcode ("dec", "%s", spname);
2900         }
2901       else
2902         {
2903           emitcode ("pop", "_bp");
2904         }
2905     }
2906
2907   /* restore the register bank  */
2908   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
2909   {
2910     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
2911      || !options.useXstack)
2912     {
2913         /* Special case of ISR using non-zero bank with useXstack
2914          * is handled below.
2915          */
2916         emitcode ("pop", "psw");
2917     }
2918   }
2919
2920   if (IFFUNC_ISISR (sym->type))
2921     {
2922
2923       /* now we need to restore the registers */
2924       /* if this isr has no bank i.e. is going to
2925          run with bank 0 , then we need to save more
2926          registers :-) */
2927       if (!FUNC_REGBANK (sym->type))
2928         {
2929           /* if this function does not call any other
2930              function then we can be economical and
2931              save only those registers that are used */
2932           if (!IFFUNC_HASFCALL(sym->type))
2933             {
2934               int i;
2935
2936               /* if any registers used */
2937               if (sym->regsUsed)
2938                 {
2939                   /* save the registers used */
2940                   for (i = sym->regsUsed->size; i >= 0; i--)
2941                     {
2942                       if (bitVectBitValue (sym->regsUsed, i))
2943                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2944                     }
2945                 }
2946             }
2947           else
2948             {
2949               if (options.parms_in_bank1) {
2950                   int i;
2951                   for (i = 7 ; i >= 0 ; i-- ) {
2952                       emitcode ("pop","%s",rb1regs[i]);
2953                   }
2954               }
2955               /* this function has  a function call cannot
2956                  determines register usage so we will have to pop the
2957                  entire bank */
2958               unsaveRBank (0, ic, FALSE);
2959             }
2960         }
2961         else
2962         {
2963             /* This ISR uses a non-zero bank.
2964              *
2965              * Restore any register banks saved by genFunction
2966              * in reverse order.
2967              */
2968             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
2969             int ix;
2970
2971             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
2972             {
2973                 if (savedBanks & (1 << ix))
2974                 {
2975                     unsaveRBank(ix, NULL, FALSE);
2976                 }
2977             }
2978
2979             if (options.useXstack)
2980             {
2981                 /* Restore bank AFTER calling unsaveRBank,
2982                  * since it can trash r0.
2983                  */
2984                 emitcode ("pop", "psw");
2985             }
2986         }
2987
2988       if (!inExcludeList ("dph"))
2989         emitcode ("pop", "dph");
2990       if (!inExcludeList ("dpl"))
2991         emitcode ("pop", "dpl");
2992       if (!inExcludeList ("b"))
2993         emitcode ("pop", "b");
2994       if (!inExcludeList ("acc"))
2995         emitcode ("pop", "acc");
2996
2997       /* if debug then send end of function */
2998       if (options.debug && currFunc)
2999         {
3000           _G.debugLine = 1;
3001           emitcode ("", "C$%s$%d$%d$%d ==.",
3002                     FileBaseName (ic->filename), currFunc->lastLine,
3003                     ic->level, ic->block);
3004           if (IS_STATIC (currFunc->etype))
3005             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
3006           else
3007             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
3008           _G.debugLine = 0;
3009         }
3010
3011       emitcode ("reti", "");
3012     }
3013   else
3014     {
3015       if (IFFUNC_CALLEESAVES(sym->type))
3016         {
3017           int i;
3018
3019           /* if any registers used */
3020           if (sym->regsUsed)
3021             {
3022               /* save the registers used */
3023               for (i = sym->regsUsed->size; i >= 0; i--)
3024                 {
3025                   if (bitVectBitValue (sym->regsUsed, i) ||
3026                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3027                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3028                 }
3029             }
3030           else if (mcs51_ptrRegReq)
3031             {
3032               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3033               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3034             }
3035
3036         }
3037
3038       /* if debug then send end of function */
3039       if (options.debug && currFunc)
3040         {
3041           _G.debugLine = 1;
3042           emitcode ("", "C$%s$%d$%d$%d ==.",
3043                     FileBaseName (ic->filename), currFunc->lastLine,
3044                     ic->level, ic->block);
3045           if (IS_STATIC (currFunc->etype))
3046             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
3047           else
3048             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
3049           _G.debugLine = 0;
3050         }
3051
3052       emitcode ("ret", "");
3053     }
3054
3055   if (!port->peep.getRegsRead || !port->peep.getRegsWritten)
3056     return;
3057   
3058   /* If this was an interrupt handler using bank 0 that called another */
3059   /* function, then all registers must be saved; nothing to optimized. */
3060   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3061       && !FUNC_REGBANK(sym->type))
3062     return;
3063
3064   /* There are no push/pops to optimize if not callee-saves or ISR */
3065   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3066     return;
3067   
3068   /* If there were stack parameters, we cannot optimize without also    */
3069   /* fixing all of the stack offsets; this is too dificult to consider. */
3070   if (FUNC_HASSTACKPARM(sym->type))
3071     return;
3072     
3073   /* Compute the registers actually used */
3074   regsUsed = newBitVect (mcs51_nRegs);
3075   regsUsedPrologue = newBitVect (mcs51_nRegs);
3076   while (lnp)
3077     {
3078       if (lnp->ic && lnp->ic->op == FUNCTION)
3079         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3080       else
3081         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3082       
3083       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3084           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3085         break;
3086       if (!lnp->prev)
3087         break;
3088       lnp = lnp->prev;
3089     }
3090
3091   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3092       && !bitVectBitValue (regsUsed, CND_IDX))
3093     {
3094       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3095       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK(sym->type)
3096           && !sym->stack)
3097         bitVectUnSetBit (regsUsed, CND_IDX);
3098     }
3099   else
3100     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3101     
3102   /* If this was an interrupt handler that called another function */
3103   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3104   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3105     {
3106       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3107       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3108       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3109       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3110       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3111     }
3112
3113   /* Remove the unneeded push/pops */
3114   regsUnneeded = newBitVect (mcs51_nRegs);
3115   while (lnp)
3116     {
3117       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3118         {
3119           if (!strncmp(lnp->line, "push", 4))
3120             {
3121               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3122               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3123                 {
3124                   connectLine (lnp->prev, lnp->next);
3125                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3126                 }
3127             }
3128           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3129             {
3130               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3131               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3132                 {
3133                   connectLine (lnp->prev, lnp->next);
3134                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3135                 }
3136             }
3137         }
3138       lnp = lnp->next;
3139     }  
3140   
3141   for (idx = 0; idx < regsUnneeded->size; idx++)
3142     if (bitVectBitValue (regsUnneeded, idx))
3143       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3144   
3145   freeBitVect (regsUnneeded);
3146   freeBitVect (regsUsed);
3147   freeBitVect (regsUsedPrologue);
3148 }
3149
3150 /*-----------------------------------------------------------------*/
3151 /* genRet - generate code for return statement                     */
3152 /*-----------------------------------------------------------------*/
3153 static void
3154 genRet (iCode * ic)
3155 {
3156   int size, offset = 0, pushed = 0;
3157
3158   D(emitcode (";     genRet",""));
3159
3160   /* if we have no return value then
3161      just generate the "ret" */
3162   if (!IC_LEFT (ic))
3163     goto jumpret;
3164
3165   /* we have something to return then
3166      move the return value into place */
3167   aopOp (IC_LEFT (ic), ic, FALSE);
3168   size = AOP_SIZE (IC_LEFT (ic));
3169
3170   while (size--)
3171     {
3172       char *l;
3173       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3174         {
3175           /* #NOCHANGE */
3176           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3177                       FALSE, TRUE);
3178           emitcode ("push", "%s", l);
3179           pushed++;
3180         }
3181       else
3182         {
3183           l = aopGet (AOP (IC_LEFT (ic)), offset,
3184                       FALSE, FALSE);
3185           if (strcmp (fReturn[offset], l))
3186             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3187         }
3188     }
3189
3190   if (pushed)
3191     {
3192       while (pushed)
3193         {
3194           pushed--;
3195           if (strcmp (fReturn[pushed], "a"))
3196             emitcode ("pop", fReturn[pushed]);
3197           else
3198             emitcode ("pop", "acc");
3199         }
3200     }
3201   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3202
3203 jumpret:
3204   /* generate a jump to the return label
3205      if the next is not the return statement */
3206   if (!(ic->next && ic->next->op == LABEL &&
3207         IC_LABEL (ic->next) == returnLabel))
3208
3209     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3210
3211 }
3212
3213 /*-----------------------------------------------------------------*/
3214 /* genLabel - generates a label                                    */
3215 /*-----------------------------------------------------------------*/
3216 static void
3217 genLabel (iCode * ic)
3218 {
3219   /* special case never generate */
3220   if (IC_LABEL (ic) == entryLabel)
3221     return;
3222
3223   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3224 }
3225
3226 /*-----------------------------------------------------------------*/
3227 /* genGoto - generates a ljmp                                      */
3228 /*-----------------------------------------------------------------*/
3229 static void
3230 genGoto (iCode * ic)
3231 {
3232   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3233 }
3234
3235 /*-----------------------------------------------------------------*/
3236 /* findLabelBackwards: walks back through the iCode chain looking  */
3237 /* for the given label. Returns number of iCode instructions     */
3238 /* between that label and given ic.          */
3239 /* Returns zero if label not found.          */
3240 /*-----------------------------------------------------------------*/
3241 static int
3242 findLabelBackwards (iCode * ic, int key)
3243 {
3244   int count = 0;
3245
3246   while (ic->prev)
3247     {
3248       ic = ic->prev;
3249       count++;
3250
3251       /* If we have any pushes or pops, we cannot predict the distance.
3252          I don't like this at all, this should be dealt with in the
3253          back-end */
3254       if (ic->op == IPUSH || ic->op == IPOP) {
3255         return 0;
3256       }
3257
3258       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3259         {
3260           return count;
3261         }
3262     }
3263
3264   return 0;
3265 }
3266
3267 /*-----------------------------------------------------------------*/
3268 /* genPlusIncr :- does addition with increment if possible         */
3269 /*-----------------------------------------------------------------*/
3270 static bool
3271 genPlusIncr (iCode * ic)
3272 {
3273   unsigned int icount;
3274   unsigned int size = getDataSize (IC_RESULT (ic));
3275
3276   /* will try to generate an increment */
3277   /* if the right side is not a literal
3278      we cannot */
3279   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3280     return FALSE;
3281
3282   /* if the literal value of the right hand side
3283      is greater than 4 then it is not worth it */
3284   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3285     return FALSE;
3286
3287   D(emitcode (";     genPlusIncr",""));
3288
3289   /* if increment >=16 bits in register or direct space */
3290   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3291       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3292       (size > 1) &&
3293       (icount == 1))
3294     {
3295       symbol *tlbl;
3296       int emitTlbl;
3297       int labelRange;
3298
3299       /* If the next instruction is a goto and the goto target
3300        * is < 10 instructions previous to this, we can generate
3301        * jumps straight to that target.
3302        */
3303       if (ic->next && ic->next->op == GOTO
3304           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3305           && labelRange <= 10)
3306         {
3307           emitcode (";", "tail increment optimized");
3308           tlbl = IC_LABEL (ic->next);
3309           emitTlbl = 0;
3310         }
3311       else
3312         {
3313           tlbl = newiTempLabel (NULL);
3314           emitTlbl = 1;
3315         }
3316       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3317       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3318           IS_AOP_PREG (IC_RESULT (ic)))
3319         emitcode ("cjne", "%s,#0x00,%05d$",
3320                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3321                   tlbl->key + 100);
3322       else
3323         {
3324           emitcode ("clr", "a");
3325           emitcode ("cjne", "a,%s,%05d$",
3326                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3327                     tlbl->key + 100);
3328         }
3329
3330       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3331       if (size > 2)
3332         {
3333           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3334               IS_AOP_PREG (IC_RESULT (ic)))
3335             emitcode ("cjne", "%s,#0x00,%05d$",
3336                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3337                       tlbl->key + 100);
3338           else
3339             emitcode ("cjne", "a,%s,%05d$",
3340                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3341                       tlbl->key + 100);
3342
3343           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3344         }
3345       if (size > 3)
3346         {
3347           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3348               IS_AOP_PREG (IC_RESULT (ic)))
3349             emitcode ("cjne", "%s,#0x00,%05d$",
3350                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3351                       tlbl->key + 100);
3352           else
3353             {
3354               emitcode ("cjne", "a,%s,%05d$",
3355                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3356                         tlbl->key + 100);
3357             }
3358           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3359         }
3360
3361       if (emitTlbl)
3362         {
3363           emitcode ("", "%05d$:", tlbl->key + 100);
3364         }
3365       return TRUE;
3366     }
3367
3368   /* if the sizes are greater than 1 then we cannot */
3369   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3370       AOP_SIZE (IC_LEFT (ic)) > 1)
3371     return FALSE;
3372
3373   /* we can if the aops of the left & result match or
3374      if they are in registers and the registers are the
3375      same */
3376   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3377     {
3378
3379       if (icount > 3)
3380         {
3381           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3382           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3383           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3384         }
3385       else
3386         {
3387
3388           while (icount--)
3389             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3390         }
3391
3392       return TRUE;
3393     }
3394
3395   return FALSE;
3396 }
3397
3398 /*-----------------------------------------------------------------*/
3399 /* outBitAcc - output a bit in acc                                 */
3400 /*-----------------------------------------------------------------*/
3401 static void
3402 outBitAcc (operand * result)
3403 {
3404   symbol *tlbl = newiTempLabel (NULL);
3405   /* if the result is a bit */
3406   if (AOP_TYPE (result) == AOP_CRY)
3407     {
3408       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3409     }
3410   else
3411     {
3412       emitcode ("jz", "%05d$", tlbl->key + 100);
3413       emitcode ("mov", "a,%s", one);
3414       emitcode ("", "%05d$:", tlbl->key + 100);
3415       outAcc (result);
3416     }
3417 }
3418
3419 /*-----------------------------------------------------------------*/
3420 /* genPlusBits - generates code for addition of two bits           */
3421 /*-----------------------------------------------------------------*/
3422 static void
3423 genPlusBits (iCode * ic)
3424 {
3425   D(emitcode (";     genPlusBits",""));
3426
3427   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3428     {
3429       symbol *lbl = newiTempLabel (NULL);
3430       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3431       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3432       emitcode ("cpl", "c");
3433       emitcode ("", "%05d$:", (lbl->key + 100));
3434       outBitC (IC_RESULT (ic));
3435     }
3436   else
3437     {
3438       emitcode ("clr", "a");
3439       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3440       emitcode ("rlc", "a");
3441       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3442       emitcode ("addc", "a,#0x00");
3443       outAcc (IC_RESULT (ic));
3444     }
3445 }
3446
3447 #if 0
3448 /* This is the original version of this code.
3449
3450  * This is being kept around for reference,
3451  * because I am not entirely sure I got it right...
3452  */
3453 static void
3454 adjustArithmeticResult (iCode * ic)
3455 {
3456   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3457       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3458       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3459     aopPut (AOP (IC_RESULT (ic)),
3460             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3461             2,
3462             isOperandVolatile (IC_RESULT (ic), FALSE));
3463
3464   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3465       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3466       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3467     aopPut (AOP (IC_RESULT (ic)),
3468             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3469             2,
3470             isOperandVolatile (IC_RESULT (ic), FALSE));
3471
3472   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3473       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3474       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3475       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3476       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3477     {
3478       char buffer[5];
3479       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3480       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3481     }
3482 }
3483 #else
3484 /* This is the pure and virtuous version of this code.
3485  * I'm pretty certain it's right, but not enough to toss the old
3486  * code just yet...
3487  */
3488 static void
3489 adjustArithmeticResult (iCode * ic)
3490 {
3491   if (opIsGptr (IC_RESULT (ic)) &&
3492       opIsGptr (IC_LEFT (ic)) &&
3493       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3494     {
3495       aopPut (AOP (IC_RESULT (ic)),
3496               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3497               GPTRSIZE - 1,
3498               isOperandVolatile (IC_RESULT (ic), FALSE));
3499     }
3500
3501   if (opIsGptr (IC_RESULT (ic)) &&
3502       opIsGptr (IC_RIGHT (ic)) &&
3503       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3504     {
3505       aopPut (AOP (IC_RESULT (ic)),
3506               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3507               GPTRSIZE - 1,
3508               isOperandVolatile (IC_RESULT (ic), FALSE));
3509     }
3510
3511   if (opIsGptr (IC_RESULT (ic)) &&
3512       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3513       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3514       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3515       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3516     {
3517       char buffer[5];
3518       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3519       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3520     }
3521 }
3522 #endif
3523
3524 /*-----------------------------------------------------------------*/
3525 /* genPlus - generates code for addition                           */
3526 /*-----------------------------------------------------------------*/
3527 static void
3528 genPlus (iCode * ic)
3529 {
3530   int size, offset = 0;
3531   int skip_bytes = 0;
3532   char *add = "add";
3533   asmop *leftOp, *rightOp;
3534   operand * op;
3535
3536   /* special cases :- */
3537
3538   D(emitcode (";     genPlus",""));
3539
3540   aopOp (IC_LEFT (ic), ic, FALSE);
3541   aopOp (IC_RIGHT (ic), ic, FALSE);
3542   aopOp (IC_RESULT (ic), ic, TRUE);
3543
3544   /* if literal, literal on the right or
3545      if left requires ACC or right is already
3546      in ACC */
3547   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3548       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3549       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3550     {
3551       operand *t = IC_RIGHT (ic);
3552       IC_RIGHT (ic) = IC_LEFT (ic);
3553       IC_LEFT (ic) = t;
3554     }
3555
3556   /* if both left & right are in bit
3557      space */
3558   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3559       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3560     {
3561       genPlusBits (ic);
3562       goto release;
3563     }
3564
3565   /* if left in bit space & right literal */
3566   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3567       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3568     {
3569       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3570       /* if result in bit space */
3571       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3572         {
3573           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3574             emitcode ("cpl", "c");
3575           outBitC (IC_RESULT (ic));
3576         }
3577       else
3578         {
3579           size = getDataSize (IC_RESULT (ic));
3580           while (size--)
3581             {
3582               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3583               emitcode ("addc", "a,#00");
3584               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3585             }
3586         }
3587       goto release;
3588     }
3589
3590   /* if I can do an increment instead
3591      of add then GOOD for ME */
3592   if (genPlusIncr (ic) == TRUE)
3593     goto release;
3594
3595   size = getDataSize (IC_RESULT (ic));
3596   leftOp = AOP(IC_LEFT(ic));
3597   rightOp = AOP(IC_RIGHT(ic));
3598   op=IC_LEFT(ic);
3599
3600   /* if this is an add for an array access
3601      at a 256 byte boundary */
3602   if ( 2 == size
3603        && AOP_TYPE (op) == AOP_IMMD
3604        && IS_SYMOP (op)
3605        && IS_SPEC (OP_SYM_ETYPE (op))
3606        && SPEC_ABSA (OP_SYM_ETYPE (op))
3607        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3608      )
3609     {
3610       D(emitcode (";     genPlus aligned array",""));
3611       aopPut (AOP (IC_RESULT (ic)),
3612               aopGet (rightOp, 0, FALSE, FALSE),
3613               0,
3614               isOperandVolatile (IC_RESULT (ic), FALSE));
3615
3616       if( 1 == getDataSize (IC_RIGHT (ic)) )
3617         {
3618           aopPut (AOP (IC_RESULT (ic)),
3619                   aopGet (leftOp, 1, FALSE, FALSE),
3620                   1,
3621                   isOperandVolatile (IC_RESULT (ic), FALSE));
3622         }
3623       else
3624         {
3625           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3626           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3627           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3628         }
3629       goto release;
3630     }
3631
3632   /* if the lower bytes of a literal are zero skip the addition */
3633   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3634     {
3635        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3636               (skip_bytes+1 < size))
3637          {
3638            skip_bytes++;
3639          }
3640        if (skip_bytes)
3641          D(emitcode (";     genPlus shortcut",""));
3642     }
3643
3644   while (size--)
3645     {
3646       if( offset >= skip_bytes )
3647         {
3648           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3649             {
3650               emitcode("mov", "b,a");
3651               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3652               emitcode("xch", "a,b");
3653               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3654               emitcode (add, "a,b");
3655             }
3656           else if (aopGetUsesAcc (leftOp, offset))
3657             {
3658               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3659               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3660             }
3661           else
3662             {
3663               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3664               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3665             }
3666           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3667           add = "addc";  /* further adds must propagate carry */
3668         }
3669       else
3670         {
3671           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3672               isOperandVolatile (IC_RESULT (ic), FALSE))
3673             {
3674               /* just move */
3675               aopPut (AOP (IC_RESULT (ic)),
3676                       aopGet (leftOp, offset, FALSE, FALSE),
3677                       offset,
3678                       isOperandVolatile (IC_RESULT (ic), FALSE));
3679             }
3680         }
3681       offset++;
3682     }
3683
3684   adjustArithmeticResult (ic);
3685
3686 release:
3687   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3688   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3689   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3690 }
3691
3692 /*-----------------------------------------------------------------*/
3693 /* genMinusDec :- does subtraction with deccrement if possible     */
3694 /*-----------------------------------------------------------------*/
3695 static bool
3696 genMinusDec (iCode * ic)
3697 {
3698   unsigned int icount;
3699   unsigned int size = getDataSize (IC_RESULT (ic));
3700
3701   /* will try to generate an increment */
3702   /* if the right side is not a literal
3703      we cannot */
3704   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3705     return FALSE;
3706
3707   /* if the literal value of the right hand side
3708      is greater than 4 then it is not worth it */
3709   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3710     return FALSE;
3711
3712   D(emitcode (";     genMinusDec",""));
3713
3714   /* if decrement >=16 bits in register or direct space */
3715   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3716       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3717       (size > 1) &&
3718       (icount == 1))
3719     {
3720       symbol *tlbl;
3721       int emitTlbl;
3722       int labelRange;
3723
3724       /* If the next instruction is a goto and the goto target
3725        * is <= 10 instructions previous to this, we can generate
3726        * jumps straight to that target.
3727        */
3728       if (ic->next && ic->next->op == GOTO
3729           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3730           && labelRange <= 10)
3731         {
3732           emitcode (";", "tail decrement optimized");
3733           tlbl = IC_LABEL (ic->next);
3734           emitTlbl = 0;
3735         }
3736       else
3737         {
3738           tlbl = newiTempLabel (NULL);
3739           emitTlbl = 1;
3740         }
3741
3742       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3743       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3744           IS_AOP_PREG (IC_RESULT (ic)))
3745         emitcode ("cjne", "%s,#0xff,%05d$"
3746                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3747                   ,tlbl->key + 100);
3748       else
3749         {
3750           emitcode ("mov", "a,#0xff");
3751           emitcode ("cjne", "a,%s,%05d$"
3752                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3753                     ,tlbl->key + 100);
3754         }
3755       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3756       if (size > 2)
3757         {
3758           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3759               IS_AOP_PREG (IC_RESULT (ic)))
3760             emitcode ("cjne", "%s,#0xff,%05d$"
3761                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3762                       ,tlbl->key + 100);
3763           else
3764             {
3765               emitcode ("cjne", "a,%s,%05d$"
3766                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3767                         ,tlbl->key + 100);
3768             }
3769           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3770         }
3771       if (size > 3)
3772         {
3773           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3774               IS_AOP_PREG (IC_RESULT (ic)))
3775             emitcode ("cjne", "%s,#0xff,%05d$"
3776                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3777                       ,tlbl->key + 100);
3778           else
3779             {
3780               emitcode ("cjne", "a,%s,%05d$"
3781                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3782                         ,tlbl->key + 100);
3783             }
3784           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3785         }
3786       if (emitTlbl)
3787         {
3788           emitcode ("", "%05d$:", tlbl->key + 100);
3789         }
3790       return TRUE;
3791     }
3792
3793   /* if the sizes are greater than 1 then we cannot */
3794   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3795       AOP_SIZE (IC_LEFT (ic)) > 1)
3796     return FALSE;
3797
3798   /* we can if the aops of the left & result match or
3799      if they are in registers and the registers are the
3800      same */
3801   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3802     {
3803
3804       while (icount--)
3805         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3806
3807       return TRUE;
3808     }
3809
3810   return FALSE;
3811 }
3812
3813 /*-----------------------------------------------------------------*/
3814 /* addSign - complete with sign                                    */
3815 /*-----------------------------------------------------------------*/
3816 static void
3817 addSign (operand * result, int offset, int sign)
3818 {
3819   int size = (getDataSize (result) - offset);
3820   if (size > 0)
3821     {
3822       if (sign)
3823         {
3824           emitcode ("rlc", "a");
3825           emitcode ("subb", "a,acc");
3826           while (size--)
3827             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3828         }
3829       else
3830         while (size--)
3831           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3832     }
3833 }
3834
3835 /*-----------------------------------------------------------------*/
3836 /* genMinusBits - generates code for subtraction  of two bits      */
3837 /*-----------------------------------------------------------------*/
3838 static void
3839 genMinusBits (iCode * ic)
3840 {
3841   symbol *lbl = newiTempLabel (NULL);
3842
3843   D(emitcode (";     genMinusBits",""));
3844
3845   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3846     {
3847       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3848       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3849       emitcode ("cpl", "c");
3850       emitcode ("", "%05d$:", (lbl->key + 100));
3851       outBitC (IC_RESULT (ic));
3852     }
3853   else
3854     {
3855       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3856       emitcode ("subb", "a,acc");
3857       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
3858       emitcode ("inc", "a");
3859       emitcode ("", "%05d$:", (lbl->key + 100));
3860       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3861       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
3862     }
3863 }
3864
3865 /*-----------------------------------------------------------------*/
3866 /* genMinus - generates code for subtraction                       */
3867 /*-----------------------------------------------------------------*/
3868 static void
3869 genMinus (iCode * ic)
3870 {
3871   int size, offset = 0;
3872
3873   D(emitcode (";     genMinus",""));
3874
3875   aopOp (IC_LEFT (ic), ic, FALSE);
3876   aopOp (IC_RIGHT (ic), ic, FALSE);
3877   aopOp (IC_RESULT (ic), ic, TRUE);
3878
3879   /* special cases :- */
3880   /* if both left & right are in bit space */
3881   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3882       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3883     {
3884       genMinusBits (ic);
3885       goto release;
3886     }
3887
3888   /* if I can do an decrement instead
3889      of subtract then GOOD for ME */
3890   if (genMinusDec (ic) == TRUE)
3891     goto release;
3892
3893   size = getDataSize (IC_RESULT (ic));
3894
3895   /* if literal, add a,#-lit, else normal subb */
3896   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3897     {
3898       unsigned long lit = 0L;
3899
3900       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3901       lit = -(long) lit;
3902
3903       while (size--)
3904         {
3905           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
3906           /* first add without previous c */
3907           if (!offset) {
3908             if (!size && lit== (unsigned long) -1) {
3909               emitcode ("dec", "a");
3910             } else {
3911               emitcode ("add", "a,#0x%02x",
3912                         (unsigned int) (lit & 0x0FFL));
3913             }
3914           } else {
3915             emitcode ("addc", "a,#0x%02x",
3916                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3917           }
3918           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3919         }
3920     }
3921   else
3922     {
3923       asmop *leftOp, *rightOp;
3924
3925       leftOp = AOP(IC_LEFT(ic));
3926       rightOp = AOP(IC_RIGHT(ic));
3927
3928       while (size--)
3929         {
3930           if (aopGetUsesAcc(rightOp, offset)) {
3931             wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
3932             MOVA (aopGet(rightOp, offset, FALSE, TRUE));
3933             if (offset == 0) {
3934               emitcode( "setb", "c");
3935             }
3936             emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
3937             emitcode("cpl", "a");
3938           } else {
3939             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
3940             if (offset == 0)
3941               CLRC;
3942             emitcode ("subb", "a,%s",
3943                       aopGet(rightOp, offset, FALSE, TRUE));
3944           }
3945
3946           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3947         }
3948     }
3949
3950
3951   adjustArithmeticResult (ic);
3952
3953 release:
3954   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3955   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3956   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3957 }
3958
3959
3960 /*-----------------------------------------------------------------*/
3961 /* genMultbits :- multiplication of bits                           */
3962 /*-----------------------------------------------------------------*/
3963 static void
3964 genMultbits (operand * left,
3965              operand * right,
3966              operand * result)
3967 {
3968   D(emitcode (";     genMultbits",""));
3969
3970   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
3971   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
3972   outBitC (result);
3973 }
3974
3975 /*-----------------------------------------------------------------*/
3976 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
3977 /*-----------------------------------------------------------------*/
3978 static void
3979 genMultOneByte (operand * left,
3980                 operand * right,
3981                 operand * result)
3982 {
3983   symbol *lbl;
3984   int size = AOP_SIZE (result);
3985   bool runtimeSign, compiletimeSign;
3986   bool lUnsigned, rUnsigned;
3987
3988   D(emitcode (";     genMultOneByte",""));
3989
3990   if (size < 1 || size > 2)
3991     {
3992       /* this should never happen */
3993       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
3994                AOP_SIZE(result), __FILE__, lineno);
3995       exit (1);
3996     }
3997
3998   /* (if two literals: the value is computed before) */
3999   /* if one literal, literal on the right */
4000   if (AOP_TYPE (left) == AOP_LIT)
4001     {
4002       operand *t = right;
4003       right = left;
4004       left = t;
4005       /* emitcode (";", "swapped left and right"); */
4006     }
4007   /* if no literal, unsigned on the right: shorter code */
4008   if (   AOP_TYPE (right) != AOP_LIT
4009       && SPEC_USIGN (getSpec (operandType (left))))
4010     {
4011       operand *t = right;
4012       right = left;
4013       left = t;
4014     }
4015
4016   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4017   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4018
4019   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4020                    no need to take care about the signedness! */
4021       || (lUnsigned && rUnsigned))
4022     {
4023       /* just an unsigned 8 * 8 = 8 multiply
4024          or 8u * 8u = 16u */
4025       /* emitcode (";","unsigned"); */
4026       /* TODO: check for accumulator clash between left & right aops? */
4027
4028       if (AOP_TYPE (right) == AOP_LIT)
4029         {
4030           /* moving to accumulator first helps peepholes */
4031           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4032           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4033         }
4034       else
4035         {
4036           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4037           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4038         }
4039
4040       emitcode ("mul", "ab");
4041       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4042       if (size == 2)
4043         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4044       return;
4045     }
4046
4047   /* we have to do a signed multiply */
4048   /* emitcode (";", "signed"); */
4049
4050   /* now sign adjust for both left & right */
4051
4052   /* let's see what's needed: */
4053   /* apply negative sign during runtime */
4054   runtimeSign = FALSE;
4055   /* negative sign from literals */
4056   compiletimeSign = FALSE;
4057
4058   if (!lUnsigned)
4059     {
4060       if (AOP_TYPE(left) == AOP_LIT)
4061         {
4062           /* signed literal */
4063           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4064           if (val < 0)
4065             compiletimeSign = TRUE;
4066         }
4067       else
4068         /* signed but not literal */
4069         runtimeSign = TRUE;
4070     }
4071
4072   if (!rUnsigned)
4073     {
4074       if (AOP_TYPE(right) == AOP_LIT)
4075         {
4076           /* signed literal */
4077           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4078           if (val < 0)
4079             compiletimeSign ^= TRUE;
4080         }
4081       else
4082         /* signed but not literal */
4083         runtimeSign = TRUE;
4084     }
4085
4086   /* initialize F0, which stores the runtime sign */
4087   if (runtimeSign)
4088     {
4089       if (compiletimeSign)
4090         emitcode ("setb", "F0"); /* set sign flag */
4091       else
4092         emitcode ("clr", "F0"); /* reset sign flag */
4093     }
4094
4095   /* save the signs of the operands */
4096   if (AOP_TYPE(right) == AOP_LIT)
4097     {
4098       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4099
4100       if (!rUnsigned && val < 0)
4101         emitcode ("mov", "b,#0x%02x", -val);
4102       else
4103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4104     }
4105   else /* ! literal */
4106     {
4107       if (rUnsigned)  /* emitcode (";", "signed"); */
4108
4109         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4110       else
4111         {
4112           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4113           lbl = newiTempLabel (NULL);
4114           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4115           emitcode ("cpl", "F0"); /* complement sign flag */
4116           emitcode ("cpl", "a");  /* 2's complement */
4117           emitcode ("inc", "a");
4118           emitcode ("", "%05d$:", (lbl->key + 100));
4119           emitcode ("mov", "b,a");
4120         }
4121     }
4122
4123   if (AOP_TYPE(left) == AOP_LIT)
4124     {
4125       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4126
4127       if (!lUnsigned && val < 0)
4128         emitcode ("mov", "a,#0x%02x", -val);
4129       else
4130         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4131     }
4132   else /* ! literal */
4133     {
4134       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4135
4136       if (!lUnsigned)
4137         {
4138           lbl = newiTempLabel (NULL);
4139           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4140           emitcode ("cpl", "F0"); /* complement sign flag */
4141           emitcode ("cpl", "a"); /* 2's complement */
4142           emitcode ("inc", "a");
4143           emitcode ("", "%05d$:", (lbl->key + 100));
4144         }
4145     }
4146
4147   /* now the multiplication */
4148   emitcode ("mul", "ab");
4149   if (runtimeSign || compiletimeSign)
4150     {
4151       lbl = newiTempLabel (NULL);
4152       if (runtimeSign)
4153         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4154       emitcode ("cpl", "a"); /* lsb 2's complement */
4155       if (size != 2)
4156         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4157       else
4158         {
4159           emitcode ("add", "a,#1"); /* this sets carry flag */
4160           emitcode ("xch", "a,b");
4161           emitcode ("cpl", "a"); /* msb 2's complement */
4162           emitcode ("addc", "a,#0");
4163           emitcode ("xch", "a,b");
4164         }
4165       emitcode ("", "%05d$:", (lbl->key + 100));
4166     }
4167   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4168   if (size == 2)
4169     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4170 }
4171
4172 /*-----------------------------------------------------------------*/
4173 /* genMult - generates code for multiplication                     */
4174 /*-----------------------------------------------------------------*/
4175 static void
4176 genMult (iCode * ic)
4177 {
4178   operand *left = IC_LEFT (ic);
4179   operand *right = IC_RIGHT (ic);
4180   operand *result = IC_RESULT (ic);
4181
4182   D(emitcode (";     genMult",""));
4183
4184   /* assign the amsops */
4185   aopOp (left, ic, FALSE);
4186   aopOp (right, ic, FALSE);
4187   aopOp (result, ic, TRUE);
4188
4189   /* special cases first */
4190   /* both are bits */
4191   if (AOP_TYPE (left) == AOP_CRY &&
4192       AOP_TYPE (right) == AOP_CRY)
4193     {
4194       genMultbits (left, right, result);
4195       goto release;
4196     }
4197
4198   /* if both are of size == 1 */
4199 #if 0 // one of them can be a sloc shared with the result
4200     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4201 #else
4202   if (getSize(operandType(left)) == 1 &&
4203       getSize(operandType(right)) == 1)
4204 #endif
4205     {
4206       genMultOneByte (left, right, result);
4207       goto release;
4208     }
4209
4210   /* should have been converted to function call */
4211     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4212              getSize(OP_SYMBOL(right)->type));
4213   assert (0);
4214
4215 release:
4216   freeAsmop (result, NULL, ic, TRUE);
4217   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4218   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4219 }
4220
4221 /*-----------------------------------------------------------------*/
4222 /* genDivbits :- division of bits                                  */
4223 /*-----------------------------------------------------------------*/
4224 static void
4225 genDivbits (operand * left,
4226             operand * right,
4227             operand * result)
4228 {
4229
4230   char *l;
4231
4232   D(emitcode (";     genDivbits",""));
4233
4234   /* the result must be bit */
4235   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4236   l = aopGet (AOP (left), 0, FALSE, FALSE);
4237
4238   MOVA (l);
4239
4240   emitcode ("div", "ab");
4241   emitcode ("rrc", "a");
4242   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4243 }
4244
4245 /*-----------------------------------------------------------------*/
4246 /* genDivOneByte : 8 bit division                                  */
4247 /*-----------------------------------------------------------------*/
4248 static void
4249 genDivOneByte (operand * left,
4250                operand * right,
4251                operand * result)
4252 {
4253   bool lUnsigned, rUnsigned;
4254   bool runtimeSign, compiletimeSign;
4255   symbol *lbl;
4256   int size, offset;
4257
4258   D(emitcode (";     genDivOneByte",""));
4259
4260   /* Why is it necessary that genDivOneByte() can return an int result?
4261      Have a look at:
4262      
4263         volatile unsigned char uc;
4264         volatile signed char sc1, sc2;
4265         volatile int i;
4266      
4267         uc  = 255;
4268         sc1 = -1;
4269         i = uc / sc1;
4270
4271      Or:
4272   
4273         sc1 = -128;
4274         sc2 = -1;
4275         i = sc1 / sc2;
4276
4277      In all cases a one byte result would overflow, the following cast to int
4278      would return the wrong result.
4279   
4280      Two possible solution:
4281         a) cast operands to int, if ((unsigned) / (signed)) or
4282            ((signed) / (signed))
4283         b) return an 16 bit signed int; this is what we're doing here!
4284   */
4285   
4286   size = AOP_SIZE (result) - 1;
4287   offset = 1;
4288   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4289   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4290
4291   /* signed or unsigned */
4292   if (lUnsigned && rUnsigned)
4293     {
4294       /* unsigned is easy */
4295       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4296       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4297       emitcode ("div", "ab");
4298       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4299       while (size--)
4300         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4301       return;
4302     }
4303   
4304   /* signed is a little bit more difficult */
4305
4306   /* now sign adjust for both left & right */
4307
4308   /* let's see what's needed: */
4309   /* apply negative sign during runtime */
4310   runtimeSign = FALSE;
4311   /* negative sign from literals */
4312   compiletimeSign = FALSE;
4313
4314   if (!lUnsigned)
4315     {
4316       if (AOP_TYPE(left) == AOP_LIT)
4317         {
4318           /* signed literal */
4319           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4320           if (val < 0)
4321             compiletimeSign = TRUE;
4322         }
4323       else
4324         /* signed but not literal */
4325         runtimeSign = TRUE;
4326     }
4327
4328   if (!rUnsigned)
4329     {
4330       if (AOP_TYPE(right) == AOP_LIT)
4331         {
4332           /* signed literal */
4333           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4334           if (val < 0)
4335             compiletimeSign ^= TRUE;
4336         }
4337       else
4338         /* signed but not literal */
4339         runtimeSign = TRUE;
4340     }
4341
4342   /* initialize F0, which stores the runtime sign */
4343   if (runtimeSign)
4344     {
4345       if (compiletimeSign)
4346         emitcode ("setb", "F0"); /* set sign flag */
4347       else
4348         emitcode ("clr", "F0"); /* reset sign flag */
4349     }
4350
4351   /* save the signs of the operands */
4352   if (AOP_TYPE(right) == AOP_LIT)
4353     {
4354       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4355
4356       if (!rUnsigned && val < 0)
4357         emitcode ("mov", "b,#0x%02x", -val);
4358       else
4359         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4360     }
4361   else /* ! literal */
4362     {
4363       if (rUnsigned)
4364         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4365       else
4366         {
4367           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4368           lbl = newiTempLabel (NULL);
4369           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4370           emitcode ("cpl", "F0"); /* complement sign flag */
4371           emitcode ("cpl", "a");  /* 2's complement */
4372           emitcode ("inc", "a");
4373           emitcode ("", "%05d$:", (lbl->key + 100));
4374           emitcode ("mov", "b,a");
4375         }
4376     }
4377
4378   if (AOP_TYPE(left) == AOP_LIT)
4379     {
4380       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4381
4382       if (!lUnsigned && val < 0)
4383         emitcode ("mov", "a,#0x%02x", -val);
4384       else
4385         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4386     }
4387   else /* ! literal */
4388     {
4389       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4390
4391       if (!lUnsigned)
4392         {
4393           lbl = newiTempLabel (NULL);
4394           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4395           emitcode ("cpl", "F0"); /* complement sign flag */
4396           emitcode ("cpl", "a");  /* 2's complement */
4397           emitcode ("inc", "a");
4398           emitcode ("", "%05d$:", (lbl->key + 100));
4399         }
4400     }
4401
4402   /* now the division */
4403   emitcode ("div", "ab");
4404
4405   if (runtimeSign || compiletimeSign)
4406     {
4407       lbl = newiTempLabel (NULL);
4408       if (runtimeSign)
4409         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4410       emitcode ("cpl", "a"); /* lsb 2's complement */
4411       emitcode ("inc", "a");
4412       emitcode ("", "%05d$:", (lbl->key + 100));
4413
4414       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4415       if (size > 0)
4416         {
4417           /* msb is 0x00 or 0xff depending on the sign */
4418           if (runtimeSign)
4419             {
4420               emitcode ("mov", "c,F0");
4421               emitcode ("subb", "a,acc");
4422               while (size--)
4423                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4424             }
4425           else /* compiletimeSign */
4426             while (size--)
4427               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4428         }
4429     }
4430   else
4431     {
4432       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4433       while (size--)
4434         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4435     }
4436 }
4437
4438 /*-----------------------------------------------------------------*/
4439 /* genDiv - generates code for division                            */
4440 /*-----------------------------------------------------------------*/
4441 static void
4442 genDiv (iCode * ic)
4443 {
4444   operand *left = IC_LEFT (ic);
4445   operand *right = IC_RIGHT (ic);
4446   operand *result = IC_RESULT (ic);
4447
4448   D(emitcode (";     genDiv",""));
4449
4450   /* assign the amsops */
4451   aopOp (left, ic, FALSE);
4452   aopOp (right, ic, FALSE);
4453   aopOp (result, ic, TRUE);
4454
4455   /* special cases first */
4456   /* both are bits */
4457   if (AOP_TYPE (left) == AOP_CRY &&
4458       AOP_TYPE (right) == AOP_CRY)
4459     {
4460       genDivbits (left, right, result);
4461       goto release;
4462     }
4463
4464   /* if both are of size == 1 */
4465   if (AOP_SIZE (left) == 1 &&
4466       AOP_SIZE (right) == 1)
4467     {
4468       genDivOneByte (left, right, result);
4469       goto release;
4470     }
4471
4472   /* should have been converted to function call */
4473   assert (0);
4474 release:
4475   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4476   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4477   freeAsmop (result, NULL, ic, TRUE);
4478 }
4479
4480 /*-----------------------------------------------------------------*/
4481 /* genModbits :- modulus of bits                                   */
4482 /*-----------------------------------------------------------------*/
4483 static void
4484 genModbits (operand * left,
4485             operand * right,
4486             operand * result)
4487 {
4488
4489   char *l;
4490
4491   D(emitcode (";     genModbits",""));
4492
4493   /* the result must be bit */
4494   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4495   l = aopGet (AOP (left), 0, FALSE, FALSE);
4496
4497   MOVA (l);
4498
4499   emitcode ("div", "ab");
4500   emitcode ("mov", "a,b");
4501   emitcode ("rrc", "a");
4502   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4503 }
4504
4505 /*-----------------------------------------------------------------*/
4506 /* genModOneByte : 8 bit modulus                                   */
4507 /*-----------------------------------------------------------------*/
4508 static void
4509 genModOneByte (operand * left,
4510                operand * right,
4511                operand * result)
4512 {
4513   bool lUnsigned, rUnsigned;
4514   bool runtimeSign, compiletimeSign;
4515   symbol *lbl;
4516   int size, offset;
4517
4518   D(emitcode (";     genModOneByte",""));
4519
4520   size = AOP_SIZE (result) - 1;
4521   offset = 1;
4522   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4523   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4524   
4525   /* signed or unsigned */
4526   if (lUnsigned && rUnsigned)
4527     {
4528       /* unsigned is easy */
4529       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4530       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4531       emitcode ("div", "ab");
4532       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4533       while (size--)
4534         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4535       return;
4536     }
4537
4538   /* signed is a little bit more difficult */
4539
4540   /* now sign adjust for both left & right */
4541
4542   /* modulus: sign of the right operand has no influence on the result! */
4543   if (AOP_TYPE(right) == AOP_LIT)
4544     {
4545       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4546
4547       if (!rUnsigned && val < 0)
4548         emitcode ("mov", "b,#0x%02x", -val);
4549       else
4550         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4551     }
4552   else /* not literal */
4553     {
4554       if (rUnsigned)
4555         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4556       else
4557         {
4558           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4559           lbl = newiTempLabel (NULL);
4560           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4561           emitcode ("cpl", "a"); /* 2's complement */
4562           emitcode ("inc", "a");
4563           emitcode ("", "%05d$:", (lbl->key + 100));
4564           emitcode ("mov", "b,a");
4565         }
4566     }
4567
4568   /* let's see what's needed: */
4569   /* apply negative sign during runtime */
4570   runtimeSign = FALSE;
4571   /* negative sign from literals */
4572   compiletimeSign = FALSE;
4573   
4574   /* sign adjust left side */
4575   if (AOP_TYPE(left) == AOP_LIT)
4576     {
4577       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4578
4579       if (!lUnsigned && val < 0)
4580         {
4581           compiletimeSign = TRUE; /* set sign flag */
4582           emitcode ("mov", "a,#0x%02x", -val);
4583         }
4584       else
4585         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4586     }
4587   else /* ! literal */
4588     {
4589       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4590
4591       if (!lUnsigned)
4592         {
4593           runtimeSign = TRUE;
4594           emitcode ("clr", "F0"); /* clear sign flag */
4595
4596           lbl = newiTempLabel (NULL);
4597           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4598           emitcode ("setb", "F0"); /* set sign flag */
4599           emitcode ("cpl", "a");   /* 2's complement */
4600           emitcode ("inc", "a");
4601           emitcode ("", "%05d$:", (lbl->key + 100));
4602         }
4603     }
4604
4605   /* now the modulus */
4606   emitcode ("div", "ab");
4607   
4608   if (runtimeSign || compiletimeSign)
4609     {
4610       emitcode ("mov", "a,b");
4611       lbl = newiTempLabel (NULL);
4612       if (runtimeSign)
4613         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4614       emitcode ("cpl", "a"); /* 2's complement */
4615       emitcode ("inc", "a");
4616       emitcode ("", "%05d$:", (lbl->key + 100));
4617      
4618       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4619       if (size > 0)
4620         {
4621           /* msb is 0x00 or 0xff depending on the sign */
4622           if (runtimeSign)
4623             {
4624               emitcode ("mov", "c,F0");
4625               emitcode ("subb", "a,acc");
4626               while (size--)
4627                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4628             }
4629           else /* compiletimeSign */
4630             while (size--)
4631               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4632         }
4633     }
4634   else
4635     {
4636       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4637       while (size--)
4638         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4639     }
4640 }
4641
4642 /*-----------------------------------------------------------------*/
4643 /* genMod - generates code for division                            */
4644 /*-----------------------------------------------------------------*/
4645 static void
4646 genMod (iCode * ic)
4647 {
4648   operand *left = IC_LEFT (ic);
4649   operand *right = IC_RIGHT (ic);
4650   operand *result = IC_RESULT (ic);
4651
4652   D(emitcode (";     genMod",""));
4653
4654   /* assign the amsops */
4655   aopOp (left, ic, FALSE);
4656   aopOp (right, ic, FALSE);
4657   aopOp (result, ic, TRUE);
4658
4659   /* special cases first */
4660   /* both are bits */
4661   if (AOP_TYPE (left) == AOP_CRY &&
4662       AOP_TYPE (right) == AOP_CRY)
4663     {
4664       genModbits (left, right, result);
4665       goto release;
4666     }
4667
4668   /* if both are of size == 1 */
4669   if (AOP_SIZE (left) == 1 &&
4670       AOP_SIZE (right) == 1)
4671     {
4672       genModOneByte (left, right, result);
4673       goto release;
4674     }
4675
4676   /* should have been converted to function call */
4677   assert (0);
4678
4679 release:
4680   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4681   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4682   freeAsmop (result, NULL, ic, TRUE);
4683 }
4684
4685 /*-----------------------------------------------------------------*/
4686 /* genIfxJump :- will create a jump depending on the ifx           */
4687 /*-----------------------------------------------------------------*/
4688 static void
4689 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4690 {
4691   symbol *jlbl;
4692   symbol *tlbl = newiTempLabel (NULL);
4693   char *inst;
4694
4695   D(emitcode (";     genIfxJump",""));
4696
4697   /* if true label then we jump if condition
4698      supplied is true */
4699   if (IC_TRUE (ic))
4700     {
4701       jlbl = IC_TRUE (ic);
4702       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4703                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4704     }
4705   else
4706     {
4707       /* false label is present */
4708       jlbl = IC_FALSE (ic);
4709       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4710                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4711     }
4712   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4713     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4714   else
4715     emitcode (inst, "%05d$", tlbl->key + 100);
4716   freeForBranchAsmop (result);
4717   freeForBranchAsmop (right);
4718   freeForBranchAsmop (left);
4719   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4720   emitcode ("", "%05d$:", tlbl->key + 100);
4721
4722   /* mark the icode as generated */
4723   ic->generated = 1;
4724 }
4725
4726 /*-----------------------------------------------------------------*/
4727 /* genCmp :- greater or less than comparison                       */
4728 /*-----------------------------------------------------------------*/
4729 static void
4730 genCmp (operand * left, operand * right,
4731         operand * result, iCode * ifx, int sign, iCode *ic)
4732 {
4733   int size, offset = 0;
4734   unsigned long lit = 0L;
4735   bool rightInB;
4736
4737   D(emitcode (";     genCmp",""));
4738
4739   /* if left & right are bit variables */
4740   if (AOP_TYPE (left) == AOP_CRY &&
4741       AOP_TYPE (right) == AOP_CRY)
4742     {
4743       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4744       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4745     }
4746   else
4747     {
4748       /* subtract right from left if at the
4749          end the carry flag is set then we know that
4750          left is greater than right */
4751       size = max (AOP_SIZE (left), AOP_SIZE (right));
4752
4753       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4754       if ((size == 1) && !sign &&
4755           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4756         {
4757           symbol *lbl = newiTempLabel (NULL);
4758           emitcode ("cjne", "%s,%s,%05d$",
4759                     aopGet (AOP (left), offset, FALSE, FALSE),
4760                     aopGet (AOP (right), offset, FALSE, FALSE),
4761                     lbl->key + 100);
4762           emitcode ("", "%05d$:", lbl->key + 100);
4763         }
4764       else
4765         {
4766           if (AOP_TYPE (right) == AOP_LIT)
4767             {
4768               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4769               /* optimize if(x < 0) or if(x >= 0) */
4770               if (lit == 0L)
4771                 {
4772                   if (!sign)
4773                     {
4774                       CLRC;
4775                     }
4776                   else
4777                     {
4778                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
4779                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4780                         {
4781                           genIfxJump (ifx, "acc.7", left, right, result);
4782                           return;
4783                         }
4784                       else
4785                         emitcode ("rlc", "a");
4786                     }
4787                   goto release;
4788                 }
4789             }
4790           CLRC;
4791           while (size--)
4792             {
4793               rightInB = aopGetUsesAcc(AOP (right), offset);
4794               if (rightInB)
4795                 emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4796               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4797               if (sign && size == 0)
4798                 {
4799                   emitcode ("xrl", "a,#0x80");
4800                   if (AOP_TYPE (right) == AOP_LIT)
4801                     {
4802                       unsigned long lit = (unsigned long)
4803                       floatFromVal (AOP (right)->aopu.aop_lit);
4804                       emitcode ("subb", "a,#0x%02x",
4805                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4806                     }
4807                   else
4808                     {
4809                       if (!rightInB)
4810                         emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4811                       emitcode ("xrl", "b,#0x80");
4812                       emitcode ("subb", "a,b");
4813                     }
4814                 }
4815               else
4816                 {
4817                   if (rightInB)
4818                     emitcode ("subb", "a,b");
4819                   else
4820                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4821                 }
4822               offset++;
4823             }
4824         }
4825     }
4826
4827 release:
4828   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4829   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4830   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4831     {
4832       outBitC (result);
4833     }
4834   else
4835     {
4836       /* if the result is used in the next
4837          ifx conditional branch then generate
4838          code a little differently */
4839       if (ifx)
4840         genIfxJump (ifx, "c", NULL, NULL, result);
4841       else
4842         outBitC (result);
4843       /* leave the result in acc */
4844     }
4845 }
4846
4847 /*-----------------------------------------------------------------*/
4848 /* genCmpGt :- greater than comparison                             */
4849 /*-----------------------------------------------------------------*/
4850 static void
4851 genCmpGt (iCode * ic, iCode * ifx)
4852 {
4853   operand *left, *right, *result;
4854   sym_link *letype, *retype;
4855   int sign;
4856
4857   D(emitcode (";     genCmpGt",""));
4858
4859   left = IC_LEFT (ic);
4860   right = IC_RIGHT (ic);
4861   result = IC_RESULT (ic);
4862
4863   letype = getSpec (operandType (left));
4864   retype = getSpec (operandType (right));
4865   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4866            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4867   /* assign the amsops */
4868   aopOp (left, ic, FALSE);
4869   aopOp (right, ic, FALSE);
4870   aopOp (result, ic, TRUE);
4871
4872   genCmp (right, left, result, ifx, sign,ic);
4873
4874   freeAsmop (result, NULL, ic, TRUE);
4875 }
4876
4877 /*-----------------------------------------------------------------*/
4878 /* genCmpLt - less than comparisons                                */
4879 /*-----------------------------------------------------------------*/
4880 static void
4881 genCmpLt (iCode * ic, iCode * ifx)
4882 {
4883   operand *left, *right, *result;
4884   sym_link *letype, *retype;
4885   int sign;
4886
4887   D(emitcode (";     genCmpLt",""));
4888
4889   left = IC_LEFT (ic);
4890   right = IC_RIGHT (ic);
4891   result = IC_RESULT (ic);
4892
4893   letype = getSpec (operandType (left));
4894   retype = getSpec (operandType (right));
4895   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4896            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4897   /* assign the amsops */
4898   aopOp (left, ic, FALSE);
4899   aopOp (right, ic, FALSE);
4900   aopOp (result, ic, TRUE);
4901
4902   genCmp (left, right, result, ifx, sign,ic);
4903
4904   freeAsmop (result, NULL, ic, TRUE);
4905 }
4906
4907 /*-----------------------------------------------------------------*/
4908 /* gencjneshort - compare and jump if not equal                    */
4909 /*-----------------------------------------------------------------*/
4910 static void
4911 gencjneshort (operand * left, operand * right, symbol * lbl)
4912 {
4913   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4914   int offset = 0;
4915   unsigned long lit = 0L;
4916
4917   /* if the left side is a literal or
4918      if the right is in a pointer register and left
4919      is not */
4920   if ((AOP_TYPE (left) == AOP_LIT) ||
4921       (AOP_TYPE (left) == AOP_IMMD) ||
4922       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4923     {
4924       operand *t = right;
4925       right = left;
4926       left = t;
4927     }
4928
4929   if (AOP_TYPE (right) == AOP_LIT)
4930     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4931
4932   /* if the right side is a literal then anything goes */
4933   if (AOP_TYPE (right) == AOP_LIT &&
4934       AOP_TYPE (left) != AOP_DIR  &&
4935       AOP_TYPE (left) != AOP_IMMD)
4936     {
4937       while (size--)
4938         {
4939           emitcode ("cjne", "%s,%s,%05d$",
4940                     aopGet (AOP (left), offset, FALSE, FALSE),
4941                     aopGet (AOP (right), offset, FALSE, FALSE),
4942                     lbl->key + 100);
4943           offset++;
4944         }
4945     }
4946
4947   /* if the right side is in a register or in direct space or
4948      if the left is a pointer register & right is not */
4949   else if (AOP_TYPE (right) == AOP_REG ||
4950            AOP_TYPE (right) == AOP_DIR ||
4951            AOP_TYPE (right) == AOP_LIT ||
4952            AOP_TYPE (right) == AOP_IMMD ||
4953            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
4954            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
4955     {
4956       while (size--)
4957         {
4958           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4959           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4960               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4961             emitcode ("jnz", "%05d$", lbl->key + 100);
4962           else
4963             emitcode ("cjne", "a,%s,%05d$",
4964                       aopGet (AOP (right), offset, FALSE, TRUE),
4965                       lbl->key + 100);
4966           offset++;
4967         }
4968     }
4969   else
4970     {
4971       /* right is a pointer reg need both a & b */
4972       while (size--)
4973         {
4974           char *l = aopGet (AOP (left), offset, FALSE, FALSE);
4975           if (strcmp (l, "b"))
4976             emitcode ("mov", "b,%s", l);
4977           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
4978           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
4979           offset++;
4980         }
4981     }
4982 }
4983
4984 /*-----------------------------------------------------------------*/
4985 /* gencjne - compare and jump if not equal                         */
4986 /*-----------------------------------------------------------------*/
4987 static void
4988 gencjne (operand * left, operand * right, symbol * lbl)
4989 {
4990   symbol *tlbl = newiTempLabel (NULL);
4991
4992   gencjneshort (left, right, lbl);
4993
4994   emitcode ("mov", "a,%s", one);
4995   emitcode ("sjmp", "%05d$", tlbl->key + 100);
4996   emitcode ("", "%05d$:", lbl->key + 100);
4997   emitcode ("clr", "a");
4998   emitcode ("", "%05d$:", tlbl->key + 100);
4999 }
5000
5001 /*-----------------------------------------------------------------*/
5002 /* genCmpEq - generates code for equal to                          */
5003 /*-----------------------------------------------------------------*/
5004 static void
5005 genCmpEq (iCode * ic, iCode * ifx)
5006 {
5007   operand *left, *right, *result;
5008
5009   D(emitcode (";     genCmpEq",""));
5010
5011   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5012   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5013   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5014
5015   /* if literal, literal on the right or
5016      if the right is in a pointer register and left
5017      is not */
5018   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5019       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5020     {
5021       operand *t = IC_RIGHT (ic);
5022       IC_RIGHT (ic) = IC_LEFT (ic);
5023       IC_LEFT (ic) = t;
5024     }
5025
5026   if (ifx && !AOP_SIZE (result))
5027     {
5028       symbol *tlbl;
5029       /* if they are both bit variables */
5030       if (AOP_TYPE (left) == AOP_CRY &&
5031           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5032         {
5033           if (AOP_TYPE (right) == AOP_LIT)
5034             {
5035               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5036               if (lit == 0L)
5037                 {
5038                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5039                   emitcode ("cpl", "c");
5040                 }
5041               else if (lit == 1L)
5042                 {
5043                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5044                 }
5045               else
5046                 {
5047                   emitcode ("clr", "c");
5048                 }
5049               /* AOP_TYPE(right) == AOP_CRY */
5050             }
5051           else
5052             {
5053               symbol *lbl = newiTempLabel (NULL);
5054               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5055               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5056               emitcode ("cpl", "c");
5057               emitcode ("", "%05d$:", (lbl->key + 100));
5058             }
5059           /* if true label then we jump if condition
5060              supplied is true */
5061           tlbl = newiTempLabel (NULL);
5062           if (IC_TRUE (ifx))
5063             {
5064               emitcode ("jnc", "%05d$", tlbl->key + 100);
5065               freeForBranchAsmop (result);
5066               freeForBranchAsmop (right);
5067               freeForBranchAsmop (left);
5068               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5069             }
5070           else
5071             {
5072               emitcode ("jc", "%05d$", tlbl->key + 100);
5073               freeForBranchAsmop (result);
5074               freeForBranchAsmop (right);
5075               freeForBranchAsmop (left);
5076               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5077             }
5078           emitcode ("", "%05d$:", tlbl->key + 100);
5079         }
5080       else
5081         {
5082           tlbl = newiTempLabel (NULL);
5083           gencjneshort (left, right, tlbl);
5084           if (IC_TRUE (ifx))
5085             {
5086               freeForBranchAsmop (result);
5087               freeForBranchAsmop (right);
5088               freeForBranchAsmop (left);
5089               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5090               emitcode ("", "%05d$:", tlbl->key + 100);
5091             }
5092           else
5093             {
5094               symbol *lbl = newiTempLabel (NULL);
5095               emitcode ("sjmp", "%05d$", lbl->key + 100);
5096               emitcode ("", "%05d$:", tlbl->key + 100);
5097               freeForBranchAsmop (result);
5098               freeForBranchAsmop (right);
5099               freeForBranchAsmop (left);
5100               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5101               emitcode ("", "%05d$:", lbl->key + 100);
5102             }
5103         }
5104       /* mark the icode as generated */
5105       ifx->generated = 1;
5106       goto release;
5107     }
5108
5109   /* if they are both bit variables */
5110   if (AOP_TYPE (left) == AOP_CRY &&
5111       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5112     {
5113       if (AOP_TYPE (right) == AOP_LIT)
5114         {
5115           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5116           if (lit == 0L)
5117             {
5118               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5119               emitcode ("cpl", "c");
5120             }
5121           else if (lit == 1L)
5122             {
5123               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5124             }
5125           else
5126             {
5127               emitcode ("clr", "c");
5128             }
5129           /* AOP_TYPE(right) == AOP_CRY */
5130         }
5131       else
5132         {
5133           symbol *lbl = newiTempLabel (NULL);
5134           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5135           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5136           emitcode ("cpl", "c");
5137           emitcode ("", "%05d$:", (lbl->key + 100));
5138         }
5139       /* c = 1 if egal */
5140       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5141         {
5142           outBitC (result);
5143           goto release;
5144         }
5145       if (ifx)
5146         {
5147           genIfxJump (ifx, "c", left, right, result);
5148           goto release;
5149         }
5150       /* if the result is used in an arithmetic operation
5151          then put the result in place */
5152       outBitC (result);
5153     }
5154   else
5155     {
5156       gencjne (left, right, newiTempLabel (NULL));
5157       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5158         {
5159           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5160           goto release;
5161         }
5162       if (ifx)
5163         {
5164           genIfxJump (ifx, "a", left, right, result);
5165           goto release;
5166         }
5167       /* if the result is used in an arithmetic operation
5168          then put the result in place */
5169       if (AOP_TYPE (result) != AOP_CRY)
5170         outAcc (result);
5171       /* leave the result in acc */
5172     }
5173
5174 release:
5175   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5176   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5177   freeAsmop (result, NULL, ic, TRUE);
5178 }
5179
5180 /*-----------------------------------------------------------------*/
5181 /* ifxForOp - returns the icode containing the ifx for operand     */
5182 /*-----------------------------------------------------------------*/
5183 static iCode *
5184 ifxForOp (operand * op, iCode * ic)
5185 {
5186   /* if true symbol then needs to be assigned */
5187   if (IS_TRUE_SYMOP (op))
5188     return NULL;
5189
5190   /* if this has register type condition and
5191      the next instruction is ifx with the same operand
5192      and live to of the operand is upto the ifx only then */
5193   if (ic->next &&
5194       ic->next->op == IFX &&
5195       IC_COND (ic->next)->key == op->key &&
5196       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5197     return ic->next;
5198
5199   return NULL;
5200 }
5201
5202 /*-----------------------------------------------------------------*/
5203 /* hasInc - operand is incremented before any other use            */
5204 /*-----------------------------------------------------------------*/
5205 static iCode *
5206 hasInc (operand *op, iCode *ic,int osize)
5207 {
5208   sym_link *type = operandType(op);
5209   sym_link *retype = getSpec (type);
5210   iCode *lic = ic->next;
5211   int isize ;
5212
5213   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5214   if (!IS_SYMOP(op)) return NULL;
5215
5216   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5217   if (IS_AGGREGATE(type->next)) return NULL;
5218   if (osize != (isize = getSize(type->next))) return NULL;
5219
5220   while (lic) {
5221     /* if operand of the form op = op + <sizeof *op> */
5222     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5223         isOperandEqual(IC_RESULT(lic),op) &&
5224         isOperandLiteral(IC_RIGHT(lic)) &&
5225         operandLitValue(IC_RIGHT(lic)) == isize) {
5226       return lic;
5227     }
5228     /* if the operand used or deffed */
5229     if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
5230       return NULL;
5231     }
5232     /* if GOTO or IFX */
5233     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5234     lic = lic->next;
5235   }
5236   return NULL;
5237 }
5238
5239 /*-----------------------------------------------------------------*/
5240 /* genAndOp - for && operation                                     */
5241 /*-----------------------------------------------------------------*/
5242 static void
5243 genAndOp (iCode * ic)
5244 {
5245   operand *left, *right, *result;
5246   symbol *tlbl;
5247
5248   D(emitcode (";     genAndOp",""));
5249
5250   /* note here that && operations that are in an
5251      if statement are taken away by backPatchLabels
5252      only those used in arthmetic operations remain */
5253   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5254   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5255   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5256
5257   /* if both are bit variables */
5258   if (AOP_TYPE (left) == AOP_CRY &&
5259       AOP_TYPE (right) == AOP_CRY)
5260     {
5261       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5262       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5263       outBitC (result);
5264     }
5265   else
5266     {
5267       tlbl = newiTempLabel (NULL);
5268       toBoolean (left);
5269       emitcode ("jz", "%05d$", tlbl->key + 100);
5270       toBoolean (right);
5271       emitcode ("", "%05d$:", tlbl->key + 100);
5272       outBitAcc (result);
5273     }
5274
5275   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5276   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5277   freeAsmop (result, NULL, ic, TRUE);
5278 }
5279
5280
5281 /*-----------------------------------------------------------------*/
5282 /* genOrOp - for || operation                                      */
5283 /*-----------------------------------------------------------------*/
5284 static void
5285 genOrOp (iCode * ic)
5286 {
5287   operand *left, *right, *result;
5288   symbol *tlbl;
5289
5290   D(emitcode (";     genOrOp",""));
5291
5292   /* note here that || operations that are in an
5293      if statement are taken away by backPatchLabels
5294      only those used in arthmetic operations remain */
5295   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5296   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5297   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5298
5299   /* if both are bit variables */
5300   if (AOP_TYPE (left) == AOP_CRY &&
5301       AOP_TYPE (right) == AOP_CRY)
5302     {
5303       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5304       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5305       outBitC (result);
5306     }
5307   else
5308     {
5309       tlbl = newiTempLabel (NULL);
5310       toBoolean (left);
5311       emitcode ("jnz", "%05d$", tlbl->key + 100);
5312       toBoolean (right);
5313       emitcode ("", "%05d$:", tlbl->key + 100);
5314       outBitAcc (result);
5315     }
5316
5317   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5318   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5319   freeAsmop (result, NULL, ic, TRUE);
5320 }
5321
5322 /*-----------------------------------------------------------------*/
5323 /* isLiteralBit - test if lit == 2^n                               */
5324 /*-----------------------------------------------------------------*/
5325 static int
5326 isLiteralBit (unsigned long lit)
5327 {
5328   unsigned long pw[32] =
5329   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5330    0x100L, 0x200L, 0x400L, 0x800L,
5331    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5332    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5333    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5334    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5335    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5336   int idx;
5337
5338   for (idx = 0; idx < 32; idx++)
5339     if (lit == pw[idx])
5340       return idx + 1;
5341   return 0;
5342 }
5343
5344 /*-----------------------------------------------------------------*/
5345 /* continueIfTrue -                                                */
5346 /*-----------------------------------------------------------------*/
5347 static void
5348 continueIfTrue (iCode * ic)
5349 {
5350   if (IC_TRUE (ic))
5351     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5352   ic->generated = 1;
5353 }
5354
5355 /*-----------------------------------------------------------------*/
5356 /* jmpIfTrue -                                                     */
5357 /*-----------------------------------------------------------------*/
5358 static void
5359 jumpIfTrue (iCode * ic)
5360 {
5361   if (!IC_TRUE (ic))
5362     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5363   ic->generated = 1;
5364 }
5365
5366 /*-----------------------------------------------------------------*/
5367 /* jmpTrueOrFalse -                                                */
5368 /*-----------------------------------------------------------------*/
5369 static void
5370 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5371 {
5372   // ugly but optimized by peephole
5373   if (IC_TRUE (ic))
5374     {
5375       symbol *nlbl = newiTempLabel (NULL);
5376       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5377       emitcode ("", "%05d$:", tlbl->key + 100);
5378       freeForBranchAsmop (result);
5379       freeForBranchAsmop (right);
5380       freeForBranchAsmop (left);
5381       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5382       emitcode ("", "%05d$:", nlbl->key + 100);
5383     }
5384   else
5385     {
5386       freeForBranchAsmop (result);
5387       freeForBranchAsmop (right);
5388       freeForBranchAsmop (left);
5389       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5390       emitcode ("", "%05d$:", tlbl->key + 100);
5391     }
5392   ic->generated = 1;
5393 }
5394
5395 /*-----------------------------------------------------------------*/
5396 /* genAnd  - code for and                                          */
5397 /*-----------------------------------------------------------------*/
5398 static void
5399 genAnd (iCode * ic, iCode * ifx)
5400 {
5401   operand *left, *right, *result;
5402   int size, offset = 0;
5403   unsigned long lit = 0L;
5404   int bytelit = 0;
5405   char buffer[10];
5406
5407   D(emitcode (";     genAnd",""));
5408
5409   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5410   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5411   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5412
5413 #ifdef DEBUG_TYPE
5414   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5415             AOP_TYPE (result),
5416             AOP_TYPE (left), AOP_TYPE (right));
5417   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5418             AOP_SIZE (result),
5419             AOP_SIZE (left), AOP_SIZE (right));
5420 #endif
5421
5422   /* if left is a literal & right is not then exchange them */
5423   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5424       AOP_NEEDSACC (left))
5425     {
5426       operand *tmp = right;
5427       right = left;
5428       left = tmp;
5429     }
5430
5431   /* if result = right then exchange them */
5432   if (sameRegs (AOP (result), AOP (right)))
5433     {
5434       operand *tmp = right;
5435       right = left;
5436       left = tmp;
5437     }
5438
5439   /* if right is bit then exchange them */
5440   if (AOP_TYPE (right) == AOP_CRY &&
5441       AOP_TYPE (left) != AOP_CRY)
5442     {
5443       operand *tmp = right;
5444       right = left;
5445       left = tmp;
5446     }
5447   if (AOP_TYPE (right) == AOP_LIT)
5448     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5449
5450   size = AOP_SIZE (result);
5451
5452   // if(bit & yy)
5453   // result = bit & yy;
5454   if (AOP_TYPE (left) == AOP_CRY)
5455     {
5456       // c = bit & literal;
5457       if (AOP_TYPE (right) == AOP_LIT)
5458         {
5459           if (lit & 1)
5460             {
5461               if (size && sameRegs (AOP (result), AOP (left)))
5462                 // no change
5463                 goto release;
5464               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5465             }
5466           else
5467             {
5468               // bit(result) = 0;
5469               if (size && (AOP_TYPE (result) == AOP_CRY))
5470                 {
5471                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5472                   goto release;
5473                 }
5474               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5475                 {
5476                   jumpIfTrue (ifx);
5477                   goto release;
5478                 }
5479               emitcode ("clr", "c");
5480             }
5481         }
5482       else
5483         {
5484           if (AOP_TYPE (right) == AOP_CRY)
5485             {
5486               // c = bit & bit;
5487               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5488               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5489             }
5490           else
5491             {
5492               // c = bit & val;
5493               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5494               // c = lsb
5495               emitcode ("rrc", "a");
5496               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5497             }
5498         }
5499       // bit = c
5500       // val = c
5501       if (size)
5502         outBitC (result);
5503       // if(bit & ...)
5504       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5505         genIfxJump (ifx, "c", left, right, result);
5506       goto release;
5507     }
5508
5509   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5510   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5511   if ((AOP_TYPE (right) == AOP_LIT) &&
5512       (AOP_TYPE (result) == AOP_CRY) &&
5513       (AOP_TYPE (left) != AOP_CRY))
5514     {
5515       int posbit = isLiteralBit (lit);
5516       /* left &  2^n */
5517       if (posbit)
5518         {
5519           posbit--;
5520           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5521           // bit = left & 2^n
5522           if (size)
5523             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5524           // if(left &  2^n)
5525           else
5526             {
5527               if (ifx)
5528                 {
5529                   sprintf (buffer, "acc.%d", posbit & 0x07);
5530                   genIfxJump (ifx, buffer, left, right, result);
5531                 }
5532               goto release;
5533             }
5534         }
5535       else
5536         {
5537           symbol *tlbl = newiTempLabel (NULL);
5538           int sizel = AOP_SIZE (left);
5539           if (size)
5540             emitcode ("setb", "c");
5541           while (sizel--)
5542             {
5543               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5544                 {
5545                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5546                   // byte ==  2^n ?
5547                   if ((posbit = isLiteralBit (bytelit)) != 0)
5548                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5549                   else
5550                     {
5551                       if (bytelit != 0x0FFL)
5552                         emitcode ("anl", "a,%s",
5553                                   aopGet (AOP (right), offset, FALSE, TRUE));
5554                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5555                     }
5556                 }
5557               offset++;
5558             }
5559           // bit = left & literal
5560           if (size)
5561             {
5562               emitcode ("clr", "c");
5563               emitcode ("", "%05d$:", tlbl->key + 100);
5564             }
5565           // if(left & literal)
5566           else
5567             {
5568               if (ifx)
5569                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5570               else
5571                 emitcode ("", "%05d$:", tlbl->key + 100);
5572               goto release;
5573             }
5574         }
5575       outBitC (result);
5576       goto release;
5577     }
5578
5579   /* if left is same as result */
5580   if (sameRegs (AOP (result), AOP (left)))
5581     {
5582       for (; size--; offset++)
5583         {
5584           if (AOP_TYPE (right) == AOP_LIT)
5585             {
5586               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5587                 continue;
5588               else if (bytelit == 0)
5589                 {
5590                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5591                 }
5592               else if (IS_AOP_PREG (result))
5593                 {
5594                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5595                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5596                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5597                 }
5598               else
5599                 emitcode ("anl", "%s,%s",
5600                           aopGet (AOP (left), offset, FALSE, TRUE),
5601                           aopGet (AOP (right), offset, FALSE, FALSE));
5602             }
5603           else
5604             {
5605               if (AOP_TYPE (left) == AOP_ACC)
5606                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5607               else
5608                 {
5609                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5610                   if (IS_AOP_PREG (result))
5611                     {
5612                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5613                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5614
5615                     }
5616                   else
5617                     emitcode ("anl", "%s,a",
5618                               aopGet (AOP (left), offset, FALSE, TRUE));
5619                 }
5620             }
5621         }
5622     }
5623   else
5624     {
5625       // left & result in different registers
5626       if (AOP_TYPE (result) == AOP_CRY)
5627         {
5628           // result = bit
5629           // if(size), result in bit
5630           // if(!size && ifx), conditional oper: if(left & right)
5631           symbol *tlbl = newiTempLabel (NULL);
5632           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5633           if (size)
5634             emitcode ("setb", "c");
5635           while (sizer--)
5636             {
5637               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5638                 emitcode ("anl", "a,%s",
5639                           aopGet (AOP (right), offset, FALSE, FALSE));
5640               } else {
5641                 if (AOP_TYPE(left)==AOP_ACC) {
5642                   emitcode("mov", "b,a");
5643                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5644                   emitcode("anl", "a,b");
5645                 }else {
5646                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5647                   emitcode ("anl", "a,%s",
5648                             aopGet (AOP (left), offset, FALSE, FALSE));
5649                 }
5650               }
5651               emitcode ("jnz", "%05d$", tlbl->key + 100);
5652               offset++;
5653             }
5654           if (size)
5655             {
5656               CLRC;
5657               emitcode ("", "%05d$:", tlbl->key + 100);
5658               outBitC (result);
5659             }
5660           else if (ifx)
5661             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5662           else
5663             emitcode ("", "%05d$:", tlbl->key + 100);
5664         }
5665       else
5666         {
5667           for (; (size--); offset++)
5668             {
5669               // normal case
5670               // result = left & right
5671               if (AOP_TYPE (right) == AOP_LIT)
5672                 {
5673                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5674                     {
5675                       aopPut (AOP (result),
5676                               aopGet (AOP (left), offset, FALSE, FALSE),
5677                               offset,
5678                               isOperandVolatile (result, FALSE));
5679                       continue;
5680                     }
5681                   else if (bytelit == 0)
5682                     {
5683                       /* dummy read of volatile operand */
5684                       if (isOperandVolatile (left, FALSE))
5685                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5686                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5687                       continue;
5688                     }
5689                 }
5690               // faster than result <- left, anl result,right
5691               // and better if result is SFR
5692               if (AOP_TYPE (left) == AOP_ACC)
5693                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5694               else
5695                 {
5696                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5697                   emitcode ("anl", "a,%s",
5698                             aopGet (AOP (left), offset, FALSE, FALSE));
5699                 }
5700               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5701             }
5702         }
5703     }
5704
5705 release:
5706   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5707   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5708   freeAsmop (result, NULL, ic, TRUE);
5709 }
5710
5711 /*-----------------------------------------------------------------*/
5712 /* genOr  - code for or                                            */
5713 /*-----------------------------------------------------------------*/
5714 static void
5715 genOr (iCode * ic, iCode * ifx)
5716 {
5717   operand *left, *right, *result;
5718   int size, offset = 0;
5719   unsigned long lit = 0L;
5720
5721   D(emitcode (";     genOr",""));
5722
5723   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5724   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5725   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5726
5727 #ifdef DEBUG_TYPE
5728   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5729             AOP_TYPE (result),
5730             AOP_TYPE (left), AOP_TYPE (right));
5731   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5732             AOP_SIZE (result),
5733             AOP_SIZE (left), AOP_SIZE (right));
5734 #endif
5735
5736   /* if left is a literal & right is not then exchange them */
5737   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5738       AOP_NEEDSACC (left))
5739     {
5740       operand *tmp = right;
5741       right = left;
5742       left = tmp;
5743     }
5744
5745   /* if result = right then exchange them */
5746   if (sameRegs (AOP (result), AOP (right)))
5747     {
5748       operand *tmp = right;
5749       right = left;
5750       left = tmp;
5751     }
5752
5753   /* if right is bit then exchange them */
5754   if (AOP_TYPE (right) == AOP_CRY &&
5755       AOP_TYPE (left) != AOP_CRY)
5756     {
5757       operand *tmp = right;
5758       right = left;
5759       left = tmp;
5760     }
5761   if (AOP_TYPE (right) == AOP_LIT)
5762     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5763
5764   size = AOP_SIZE (result);
5765
5766   // if(bit | yy)
5767   // xx = bit | yy;
5768   if (AOP_TYPE (left) == AOP_CRY)
5769     {
5770       if (AOP_TYPE (right) == AOP_LIT)
5771         {
5772           // c = bit | literal;
5773           if (lit)
5774             {
5775               // lit != 0 => result = 1
5776               if (AOP_TYPE (result) == AOP_CRY)
5777                 {
5778                   if (size)
5779                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5780                   else if (ifx)
5781                     continueIfTrue (ifx);
5782                   goto release;
5783                 }
5784               emitcode ("setb", "c");
5785             }
5786           else
5787             {
5788               // lit == 0 => result = left
5789               if (size && sameRegs (AOP (result), AOP (left)))
5790                 goto release;
5791               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5792             }
5793         }
5794       else
5795         {
5796           if (AOP_TYPE (right) == AOP_CRY)
5797             {
5798               // c = bit | bit;
5799               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5800               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5801             }
5802           else
5803             {
5804               // c = bit | val;
5805               symbol *tlbl = newiTempLabel (NULL);
5806               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5807                 emitcode ("setb", "c");
5808               emitcode ("jb", "%s,%05d$",
5809                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5810               toBoolean (right);
5811               emitcode ("jnz", "%05d$", tlbl->key + 100);
5812               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5813                 {
5814                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
5815                   goto release;
5816                 }
5817               else
5818                 {
5819                   CLRC;
5820                   emitcode ("", "%05d$:", tlbl->key + 100);
5821                 }
5822             }
5823         }
5824       // bit = c
5825       // val = c
5826       if (size)
5827         outBitC (result);
5828       // if(bit | ...)
5829       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5830         genIfxJump (ifx, "c", left, right, result);
5831       goto release;
5832     }
5833
5834   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5835   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5836   if ((AOP_TYPE (right) == AOP_LIT) &&
5837       (AOP_TYPE (result) == AOP_CRY) &&
5838       (AOP_TYPE (left) != AOP_CRY))
5839     {
5840       if (lit)
5841         {
5842           // result = 1
5843           if (size)
5844             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5845           else
5846             continueIfTrue (ifx);
5847           goto release;
5848         }
5849       else
5850         {
5851           // lit = 0, result = boolean(left)
5852           if (size)
5853             emitcode ("setb", "c");
5854           toBoolean (right);
5855           if (size)
5856             {
5857               symbol *tlbl = newiTempLabel (NULL);
5858               emitcode ("jnz", "%05d$", tlbl->key + 100);
5859               CLRC;
5860               emitcode ("", "%05d$:", tlbl->key + 100);
5861             }
5862           else
5863             {
5864               genIfxJump (ifx, "a", left, right, result);
5865               goto release;
5866             }
5867         }
5868       outBitC (result);
5869       goto release;
5870     }
5871
5872   /* if left is same as result */
5873   if (sameRegs (AOP (result), AOP (left)))
5874     {
5875       for (; size--; offset++)
5876         {
5877           if (AOP_TYPE (right) == AOP_LIT)
5878             {
5879               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5880                 {
5881                   /* dummy read of volatile operand */
5882                   if (isOperandVolatile (left, FALSE))
5883                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5884                   else
5885                     continue;
5886                 }
5887               else if (IS_AOP_PREG (left))
5888                 {
5889                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5890                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5891                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5892                 }
5893               else
5894                 emitcode ("orl", "%s,%s",
5895                           aopGet (AOP (left), offset, FALSE, TRUE),
5896                           aopGet (AOP (right), offset, FALSE, FALSE));
5897             }
5898           else
5899             {
5900               if (AOP_TYPE (left) == AOP_ACC)
5901                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5902               else
5903                 {
5904                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5905                   if (IS_AOP_PREG (left))
5906                     {
5907                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5908                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5909                     }
5910                   else
5911                     emitcode ("orl", "%s,a",
5912                               aopGet (AOP (left), offset, FALSE, TRUE));
5913                 }
5914             }
5915         }
5916     }
5917   else
5918     {
5919       // left & result in different registers
5920       if (AOP_TYPE (result) == AOP_CRY)
5921         {
5922           // result = bit
5923           // if(size), result in bit
5924           // if(!size && ifx), conditional oper: if(left | right)
5925           symbol *tlbl = newiTempLabel (NULL);
5926           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
5927           if (size)
5928             emitcode ("setb", "c");
5929           while (sizer--)
5930             {
5931               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5932                 emitcode ("orl", "a,%s",
5933                           aopGet (AOP (right), offset, FALSE, FALSE));
5934               } else {
5935                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5936                 emitcode ("orl", "a,%s",
5937                           aopGet (AOP (left), offset, FALSE, FALSE));
5938               }
5939               emitcode ("jnz", "%05d$", tlbl->key + 100);
5940               offset++;
5941             }
5942           if (size)
5943             {
5944               CLRC;
5945               emitcode ("", "%05d$:", tlbl->key + 100);
5946               outBitC (result);
5947             }
5948           else if (ifx)
5949             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5950           else
5951             emitcode ("", "%05d$:", tlbl->key + 100);
5952         }
5953       else
5954         for (; (size--); offset++)
5955           {
5956             // normal case
5957             // result = left & right
5958             if (AOP_TYPE (right) == AOP_LIT)
5959               {
5960                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5961                   {
5962                     aopPut (AOP (result),
5963                             aopGet (AOP (left), offset, FALSE, FALSE),
5964                             offset,
5965                             isOperandVolatile (result, FALSE));
5966                     continue;
5967                   }
5968               }
5969             // faster than result <- left, anl result,right
5970             // and better if result is SFR
5971             if (AOP_TYPE (left) == AOP_ACC)
5972               emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5973             else
5974               {
5975                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5976                 emitcode ("orl", "a,%s",
5977                           aopGet (AOP (left), offset, FALSE, FALSE));
5978               }
5979             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5980           }
5981     }
5982
5983 release:
5984   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5985   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5986   freeAsmop (result, NULL, ic, TRUE);
5987 }
5988
5989 /*-----------------------------------------------------------------*/
5990 /* genXor - code for xclusive or                                   */
5991 /*-----------------------------------------------------------------*/
5992 static void
5993 genXor (iCode * ic, iCode * ifx)
5994 {
5995   operand *left, *right, *result;
5996   int size, offset = 0;
5997   unsigned long lit = 0L;
5998
5999   D(emitcode (";     genXor",""));
6000
6001   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6002   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6003   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6004
6005 #ifdef DEBUG_TYPE
6006   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6007             AOP_TYPE (result),
6008             AOP_TYPE (left), AOP_TYPE (right));
6009   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6010             AOP_SIZE (result),
6011             AOP_SIZE (left), AOP_SIZE (right));
6012 #endif
6013
6014   /* if left is a literal & right is not ||
6015      if left needs acc & right does not */
6016   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6017       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6018     {
6019       operand *tmp = right;
6020       right = left;
6021       left = tmp;
6022     }
6023
6024   /* if result = right then exchange them */
6025   if (sameRegs (AOP (result), AOP (right)))
6026     {
6027       operand *tmp = right;
6028       right = left;
6029       left = tmp;
6030     }
6031
6032   /* if right is bit then exchange them */
6033   if (AOP_TYPE (right) == AOP_CRY &&
6034       AOP_TYPE (left) != AOP_CRY)
6035     {
6036       operand *tmp = right;
6037       right = left;
6038       left = tmp;
6039     }
6040   if (AOP_TYPE (right) == AOP_LIT)
6041     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6042
6043   size = AOP_SIZE (result);
6044
6045   // if(bit ^ yy)
6046   // xx = bit ^ yy;
6047   if (AOP_TYPE (left) == AOP_CRY)
6048     {
6049       if (AOP_TYPE (right) == AOP_LIT)
6050         {
6051           // c = bit & literal;
6052           if (lit >> 1)
6053             {
6054               // lit>>1  != 0 => result = 1
6055               if (AOP_TYPE (result) == AOP_CRY)
6056                 {
6057                   if (size)
6058                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6059                   else if (ifx)
6060                     continueIfTrue (ifx);
6061                   goto release;
6062                 }
6063               emitcode ("setb", "c");
6064             }
6065           else
6066             {
6067               // lit == (0 or 1)
6068               if (lit == 0)
6069                 {
6070                   // lit == 0, result = left
6071                   if (size && sameRegs (AOP (result), AOP (left)))
6072                     goto release;
6073                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6074                 }
6075               else
6076                 {
6077                   // lit == 1, result = not(left)
6078                   if (size && sameRegs (AOP (result), AOP (left)))
6079                     {
6080                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6081                       goto release;
6082                     }
6083                   else
6084                     {
6085                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6086                       emitcode ("cpl", "c");
6087                     }
6088                 }
6089             }
6090
6091         }
6092       else
6093         {
6094           // right != literal
6095           symbol *tlbl = newiTempLabel (NULL);
6096           if (AOP_TYPE (right) == AOP_CRY)
6097             {
6098               // c = bit ^ bit;
6099               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6100             }
6101           else
6102             {
6103               int sizer = AOP_SIZE (right);
6104               // c = bit ^ val
6105               // if val>>1 != 0, result = 1
6106               emitcode ("setb", "c");
6107               while (sizer)
6108                 {
6109                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6110                   if (sizer == 1)
6111                     // test the msb of the lsb
6112                     emitcode ("anl", "a,#0xfe");
6113                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6114                   sizer--;
6115                 }
6116               // val = (0,1)
6117               emitcode ("rrc", "a");
6118             }
6119           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6120           emitcode ("cpl", "c");
6121           emitcode ("", "%05d$:", (tlbl->key + 100));
6122         }
6123       // bit = c
6124       // val = c
6125       if (size)
6126         outBitC (result);
6127       // if(bit | ...)
6128       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6129         genIfxJump (ifx, "c", left, right, result);
6130       goto release;
6131     }
6132
6133   if (sameRegs (AOP (result), AOP (left)))
6134     {
6135       /* if left is same as result */
6136       for (; size--; offset++)
6137         {
6138           if (AOP_TYPE (right) == AOP_LIT)
6139             {
6140               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6141                 continue;
6142               else if (IS_AOP_PREG (left))
6143                 {
6144                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6145                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6146                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6147                 }
6148               else
6149                 emitcode ("xrl", "%s,%s",
6150                           aopGet (AOP (left), offset, FALSE, TRUE),
6151                           aopGet (AOP (right), offset, FALSE, FALSE));
6152             }
6153           else
6154             {
6155               if (AOP_TYPE (left) == AOP_ACC)
6156                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6157               else
6158                 {
6159                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6160                   if (IS_AOP_PREG (left))
6161                     {
6162                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6163                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6164                     }
6165                   else
6166                     emitcode ("xrl", "%s,a",
6167                               aopGet (AOP (left), offset, FALSE, TRUE));
6168                 }
6169             }
6170         }
6171     }
6172   else
6173     {
6174       // left & result in different registers
6175       if (AOP_TYPE (result) == AOP_CRY)
6176         {
6177           // result = bit
6178           // if(size), result in bit
6179           // if(!size && ifx), conditional oper: if(left ^ right)
6180           symbol *tlbl = newiTempLabel (NULL);
6181           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6182           if (size)
6183             emitcode ("setb", "c");
6184           while (sizer--)
6185             {
6186               if ((AOP_TYPE (right) == AOP_LIT) &&
6187                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6188                 {
6189                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6190                 }
6191               else
6192                 {
6193                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6194                     emitcode ("xrl", "a,%s",
6195                               aopGet (AOP (right), offset, FALSE, FALSE));
6196                   } else {
6197                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6198                     emitcode ("xrl", "a,%s",
6199                               aopGet (AOP (left), offset, FALSE, FALSE));
6200                   }
6201                 }
6202               emitcode ("jnz", "%05d$", tlbl->key + 100);
6203               offset++;
6204             }
6205           if (size)
6206             {
6207               CLRC;
6208               emitcode ("", "%05d$:", tlbl->key + 100);
6209               outBitC (result);
6210             }
6211           else if (ifx)
6212             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6213         }
6214       else
6215         for (; (size--); offset++)
6216           {
6217             // normal case
6218             // result = left & right
6219             if (AOP_TYPE (right) == AOP_LIT)
6220               {
6221                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6222                   {
6223                     aopPut (AOP (result),
6224                             aopGet (AOP (left), offset, FALSE, FALSE),
6225                             offset,
6226                             isOperandVolatile (result, FALSE));
6227                     continue;
6228                   }
6229               }
6230             // faster than result <- left, anl result,right
6231             // and better if result is SFR
6232             if (AOP_TYPE (left) == AOP_ACC)
6233               emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6234             else
6235               {
6236                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6237                 emitcode ("xrl", "a,%s",
6238                           aopGet (AOP (left), offset, FALSE, TRUE));
6239               }
6240             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6241           }
6242     }
6243
6244 release:
6245   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6246   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6247   freeAsmop (result, NULL, ic, TRUE);
6248 }
6249
6250 /*-----------------------------------------------------------------*/
6251 /* genInline - write the inline code out                           */
6252 /*-----------------------------------------------------------------*/
6253 static void
6254 genInline (iCode * ic)
6255 {
6256   char *buffer, *bp, *bp1;
6257
6258   D(emitcode (";     genInline",""));
6259
6260   _G.inLine += (!options.asmpeep);
6261
6262   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6263   strcpy (buffer, IC_INLINE (ic));
6264
6265   /* emit each line as a code */
6266   while (*bp)
6267     {
6268       if (*bp == '\n')
6269         {
6270           *bp++ = '\0';
6271           emitcode (bp1, "");
6272           bp1 = bp;
6273         }
6274       else
6275         {
6276           if (*bp == ':')
6277             {
6278               bp++;
6279               *bp = '\0';
6280               bp++;
6281               emitcode (bp1, "");
6282               bp1 = bp;
6283             }
6284           else
6285             bp++;
6286         }
6287     }
6288   if (bp1 != bp)
6289     emitcode (bp1, "");
6290   /*     emitcode("",buffer); */
6291   _G.inLine -= (!options.asmpeep);
6292 }
6293
6294 /*-----------------------------------------------------------------*/
6295 /* genRRC - rotate right with carry                                */
6296 /*-----------------------------------------------------------------*/
6297 static void
6298 genRRC (iCode * ic)
6299 {
6300   operand *left, *result;
6301   int size, offset = 0;
6302   char *l;
6303
6304   D(emitcode (";     genRRC",""));
6305
6306   /* rotate right with carry */
6307   left = IC_LEFT (ic);
6308   result = IC_RESULT (ic);
6309   aopOp (left, ic, FALSE);
6310   aopOp (result, ic, FALSE);
6311
6312   /* move it to the result */
6313   size = AOP_SIZE (result);
6314   offset = size - 1;
6315   if (size == 1) { /* special case for 1 byte */
6316       l = aopGet (AOP (left), offset, FALSE, FALSE);
6317       MOVA (l);
6318       emitcode ("rr", "a");
6319       goto release;
6320   }
6321   CLRC;
6322   while (size--)
6323     {
6324       l = aopGet (AOP (left), offset, FALSE, FALSE);
6325       MOVA (l);
6326       emitcode ("rrc", "a");
6327       if (AOP_SIZE (result) > 1)
6328         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6329     }
6330   /* now we need to put the carry into the
6331      highest order byte of the result */
6332   if (AOP_SIZE (result) > 1)
6333     {
6334       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6335       MOVA (l);
6336     }
6337   emitcode ("mov", "acc.7,c");
6338  release:
6339   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6340   freeAsmop (left, NULL, ic, TRUE);
6341   freeAsmop (result, NULL, ic, TRUE);
6342 }
6343
6344 /*-----------------------------------------------------------------*/
6345 /* genRLC - generate code for rotate left with carry               */
6346 /*-----------------------------------------------------------------*/
6347 static void
6348 genRLC (iCode * ic)
6349 {
6350   operand *left, *result;
6351   int size, offset = 0;
6352   char *l;
6353
6354   D(emitcode (";     genRLC",""));
6355
6356   /* rotate right with carry */
6357   left = IC_LEFT (ic);
6358   result = IC_RESULT (ic);
6359   aopOp (left, ic, FALSE);
6360   aopOp (result, ic, FALSE);
6361
6362   /* move it to the result */
6363   size = AOP_SIZE (result);
6364   offset = 0;
6365   if (size--)
6366     {
6367       l = aopGet (AOP (left), offset, FALSE, FALSE);
6368       MOVA (l);
6369       if (size == 0) { /* special case for 1 byte */
6370               emitcode("rl","a");
6371               goto release;
6372       }
6373       emitcode ("add", "a,acc");
6374       if (AOP_SIZE (result) > 1)
6375         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6376       while (size--)
6377         {
6378           l = aopGet (AOP (left), offset, FALSE, FALSE);
6379           MOVA (l);
6380           emitcode ("rlc", "a");
6381           if (AOP_SIZE (result) > 1)
6382             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6383         }
6384     }
6385   /* now we need to put the carry into the
6386      highest order byte of the result */
6387   if (AOP_SIZE (result) > 1)
6388     {
6389       l = aopGet (AOP (result), 0, FALSE, FALSE);
6390       MOVA (l);
6391     }
6392   emitcode ("mov", "acc.0,c");
6393  release:
6394   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6395   freeAsmop (left, NULL, ic, TRUE);
6396   freeAsmop (result, NULL, ic, TRUE);
6397 }
6398
6399 /*-----------------------------------------------------------------*/
6400 /* genGetHbit - generates code get highest order bit               */
6401 /*-----------------------------------------------------------------*/
6402 static void
6403 genGetHbit (iCode * ic)
6404 {
6405   operand *left, *result;
6406
6407   D(emitcode (";     genGetHbit",""));
6408
6409   left = IC_LEFT (ic);
6410   result = IC_RESULT (ic);
6411   aopOp (left, ic, FALSE);
6412   aopOp (result, ic, FALSE);
6413
6414   /* get the highest order byte into a */
6415   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6416   if (AOP_TYPE (result) == AOP_CRY)
6417     {
6418       emitcode ("rlc", "a");
6419       outBitC (result);
6420     }
6421   else
6422     {
6423       emitcode ("rl", "a");
6424       emitcode ("anl", "a,#0x01");
6425       outAcc (result);
6426     }
6427
6428
6429   freeAsmop (left, NULL, ic, TRUE);
6430   freeAsmop (result, NULL, ic, TRUE);
6431 }
6432
6433 /*-----------------------------------------------------------------*/
6434 /* genSwap - generates code to swap nibbles or bytes               */
6435 /*-----------------------------------------------------------------*/
6436 static void
6437 genSwap (iCode * ic)
6438 {
6439   operand *left, *result;
6440
6441   D(emitcode (";     genSwap",""));
6442
6443   left = IC_LEFT (ic);
6444   result = IC_RESULT (ic);
6445   aopOp (left, ic, FALSE);
6446   aopOp (result, ic, FALSE);
6447
6448   switch (AOP_SIZE (left))
6449     {
6450     case 1: /* swap nibbles in byte */
6451       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6452       emitcode ("swap", "a");
6453       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6454       break;
6455     case 2: /* swap bytes in word */
6456       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6457         {
6458           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6459           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6460                   0, isOperandVolatile (result, FALSE));
6461           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6462         }
6463       else if (operandsEqu (left, result))
6464         {
6465           char * reg = "a";
6466           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6467           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6468             {
6469               emitcode ("mov", "b,a");
6470               reg = "b";
6471             }
6472           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6473                   0, isOperandVolatile (result, FALSE));
6474           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6475         }
6476       else
6477         {
6478           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6479                   0, isOperandVolatile (result, FALSE));
6480           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6481                   1, isOperandVolatile (result, FALSE));
6482         }
6483       break;
6484     default:
6485       wassertl(FALSE, "unsupported SWAP operand size");
6486     }
6487
6488   freeAsmop (left, NULL, ic, TRUE);
6489   freeAsmop (result, NULL, ic, TRUE);
6490 }
6491
6492
6493 /*-----------------------------------------------------------------*/
6494 /* AccRol - rotate left accumulator by known count                 */
6495 /*-----------------------------------------------------------------*/
6496 static void
6497 AccRol (int shCount)
6498 {
6499   shCount &= 0x0007;            // shCount : 0..7
6500
6501   switch (shCount)
6502     {
6503     case 0:
6504       break;
6505     case 1:
6506       emitcode ("rl", "a");
6507       break;
6508     case 2:
6509       emitcode ("rl", "a");
6510       emitcode ("rl", "a");
6511       break;
6512     case 3:
6513       emitcode ("swap", "a");
6514       emitcode ("rr", "a");
6515       break;
6516     case 4:
6517       emitcode ("swap", "a");
6518       break;
6519     case 5:
6520       emitcode ("swap", "a");
6521       emitcode ("rl", "a");
6522       break;
6523     case 6:
6524       emitcode ("rr", "a");
6525       emitcode ("rr", "a");
6526       break;
6527     case 7:
6528       emitcode ("rr", "a");
6529       break;
6530     }
6531 }
6532
6533 /*-----------------------------------------------------------------*/
6534 /* AccLsh - left shift accumulator by known count                  */
6535 /*-----------------------------------------------------------------*/
6536 static void
6537 AccLsh (int shCount)
6538 {
6539   if (shCount != 0)
6540     {
6541       if (shCount == 1)
6542         emitcode ("add", "a,acc");
6543       else if (shCount == 2)
6544         {
6545           emitcode ("add", "a,acc");
6546           emitcode ("add", "a,acc");
6547         }
6548       else
6549         {
6550           /* rotate left accumulator */
6551           AccRol (shCount);
6552           /* and kill the lower order bits */
6553           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6554         }
6555     }
6556 }
6557
6558 /*-----------------------------------------------------------------*/
6559 /* AccRsh - right shift accumulator by known count                 */
6560 /*-----------------------------------------------------------------*/
6561 static void
6562 AccRsh (int shCount)
6563 {
6564   if (shCount != 0)
6565     {
6566       if (shCount == 1)
6567         {
6568           CLRC;
6569           emitcode ("rrc", "a");
6570         }
6571       else
6572         {
6573           /* rotate right accumulator */
6574           AccRol (8 - shCount);
6575           /* and kill the higher order bits */
6576           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6577         }
6578     }
6579 }
6580
6581 /*-----------------------------------------------------------------*/
6582 /* AccSRsh - signed right shift accumulator by known count                 */
6583 /*-----------------------------------------------------------------*/
6584 static void
6585 AccSRsh (int shCount)
6586 {
6587   symbol *tlbl;
6588   if (shCount != 0)
6589     {
6590       if (shCount == 1)
6591         {
6592           emitcode ("mov", "c,acc.7");
6593           emitcode ("rrc", "a");
6594         }
6595       else if (shCount == 2)
6596         {
6597           emitcode ("mov", "c,acc.7");
6598           emitcode ("rrc", "a");
6599           emitcode ("mov", "c,acc.7");
6600           emitcode ("rrc", "a");
6601         }
6602       else
6603         {
6604           tlbl = newiTempLabel (NULL);
6605           /* rotate right accumulator */
6606           AccRol (8 - shCount);
6607           /* and kill the higher order bits */
6608           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6609           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6610           emitcode ("orl", "a,#0x%02x",
6611                     (unsigned char) ~SRMask[shCount]);
6612           emitcode ("", "%05d$:", tlbl->key + 100);
6613         }
6614     }
6615 }
6616
6617 /*-----------------------------------------------------------------*/
6618 /* shiftR1Left2Result - shift right one byte from left to result   */
6619 /*-----------------------------------------------------------------*/
6620 static void
6621 shiftR1Left2Result (operand * left, int offl,
6622                     operand * result, int offr,
6623                     int shCount, int sign)
6624 {
6625   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6626   /* shift right accumulator */
6627   if (sign)
6628     AccSRsh (shCount);
6629   else
6630     AccRsh (shCount);
6631   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6632 }
6633
6634 /*-----------------------------------------------------------------*/
6635 /* shiftL1Left2Result - shift left one byte from left to result    */
6636 /*-----------------------------------------------------------------*/
6637 static void
6638 shiftL1Left2Result (operand * left, int offl,
6639                     operand * result, int offr, int shCount)
6640 {
6641   char *l;
6642   l = aopGet (AOP (left), offl, FALSE, FALSE);
6643   MOVA (l);
6644   /* shift left accumulator */
6645   AccLsh (shCount);
6646   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6647 }
6648
6649 /*-----------------------------------------------------------------*/
6650 /* movLeft2Result - move byte from left to result                  */
6651 /*-----------------------------------------------------------------*/
6652 static void
6653 movLeft2Result (operand * left, int offl,
6654                 operand * result, int offr, int sign)
6655 {
6656   char *l;
6657   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6658     {
6659       l = aopGet (AOP (left), offl, FALSE, FALSE);
6660
6661       if (*l == '@' && (IS_AOP_PREG (result)))
6662         {
6663           emitcode ("mov", "a,%s", l);
6664           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6665         }
6666       else
6667         {
6668           if (!sign)
6669             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6670           else
6671             {
6672               /* MSB sign in acc.7 ! */
6673               if (getDataSize (left) == offl + 1)
6674                 {
6675                   emitcode ("mov", "a,%s", l);
6676                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6677                 }
6678             }
6679         }
6680     }
6681 }
6682
6683 /*-----------------------------------------------------------------*/
6684 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6685 /*-----------------------------------------------------------------*/
6686 static void
6687 AccAXRrl1 (char *x)
6688 {
6689   emitcode ("rrc", "a");
6690   emitcode ("xch", "a,%s", x);
6691   emitcode ("rrc", "a");
6692   emitcode ("xch", "a,%s", x);
6693 }
6694
6695 /*-----------------------------------------------------------------*/
6696 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6697 /*-----------------------------------------------------------------*/
6698 static void
6699 AccAXLrl1 (char *x)
6700 {
6701   emitcode ("xch", "a,%s", x);
6702   emitcode ("rlc", "a");
6703   emitcode ("xch", "a,%s", x);
6704   emitcode ("rlc", "a");
6705 }
6706
6707 /*-----------------------------------------------------------------*/
6708 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6709 /*-----------------------------------------------------------------*/
6710 static void
6711 AccAXLsh1 (char *x)
6712 {
6713   emitcode ("xch", "a,%s", x);
6714   emitcode ("add", "a,acc");
6715   emitcode ("xch", "a,%s", x);
6716   emitcode ("rlc", "a");
6717 }
6718
6719 /*-----------------------------------------------------------------*/
6720 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6721 /*-----------------------------------------------------------------*/
6722 static void
6723 AccAXLsh (char *x, int shCount)
6724 {
6725   switch (shCount)
6726     {
6727     case 0:
6728       break;
6729     case 1:
6730       AccAXLsh1 (x);
6731       break;
6732     case 2:
6733       AccAXLsh1 (x);
6734       AccAXLsh1 (x);
6735       break;
6736     case 3:
6737     case 4:
6738     case 5:                     // AAAAABBB:CCCCCDDD
6739
6740       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6741
6742       emitcode ("anl", "a,#0x%02x",
6743                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6744
6745       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6746
6747       AccRol (shCount);         // DDDCCCCC:BBB00000
6748
6749       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6750
6751       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6752
6753       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6754
6755       emitcode ("anl", "a,#0x%02x",
6756                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6757
6758       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6759
6760       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6761
6762       break;
6763     case 6:                     // AAAAAABB:CCCCCCDD
6764       emitcode ("anl", "a,#0x%02x",
6765                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6766       emitcode ("mov", "c,acc.0");      // c = B
6767       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6768 #if 0 // REMOVE ME
6769       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6770       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6771 #else
6772       emitcode("rrc","a");
6773       emitcode("xch","a,%s", x);
6774       emitcode("rrc","a");
6775       emitcode("mov","c,acc.0"); //<< get correct bit
6776       emitcode("xch","a,%s", x);
6777
6778       emitcode("rrc","a");
6779       emitcode("xch","a,%s", x);
6780       emitcode("rrc","a");
6781       emitcode("xch","a,%s", x);
6782 #endif
6783       break;
6784     case 7:                     // a:x <<= 7
6785
6786       emitcode ("anl", "a,#0x%02x",
6787                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6788
6789       emitcode ("mov", "c,acc.0");      // c = B
6790
6791       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6792
6793       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6794
6795       break;
6796     default:
6797       break;
6798     }
6799 }
6800
6801 /*-----------------------------------------------------------------*/
6802 /* AccAXRsh - right shift a:x known count (0..7)                   */
6803 /*-----------------------------------------------------------------*/
6804 static void
6805 AccAXRsh (char *x, int shCount)
6806 {
6807   switch (shCount)
6808     {
6809     case 0:
6810       break;
6811     case 1:
6812       CLRC;
6813       AccAXRrl1 (x);            // 0->a:x
6814
6815       break;
6816     case 2:
6817       CLRC;
6818       AccAXRrl1 (x);            // 0->a:x
6819
6820       CLRC;
6821       AccAXRrl1 (x);            // 0->a:x
6822
6823       break;
6824     case 3:
6825     case 4:
6826     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6827
6828       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
6829
6830       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6831
6832       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6833
6834       emitcode ("anl", "a,#0x%02x",
6835                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6836
6837       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6838
6839       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6840
6841       emitcode ("anl", "a,#0x%02x",
6842                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6843
6844       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6845
6846       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6847
6848       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
6849
6850       break;
6851     case 6:                     // AABBBBBB:CCDDDDDD
6852
6853       emitcode ("mov", "c,acc.7");
6854       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6855
6856       emitcode ("mov", "c,acc.7");
6857       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6858
6859       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6860
6861       emitcode ("anl", "a,#0x%02x",
6862                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6863
6864       break;
6865     case 7:                     // ABBBBBBB:CDDDDDDD
6866
6867       emitcode ("mov", "c,acc.7");      // c = A
6868
6869       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6870
6871       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6872
6873       emitcode ("anl", "a,#0x%02x",
6874                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6875
6876       break;
6877     default:
6878       break;
6879     }
6880 }
6881
6882 /*-----------------------------------------------------------------*/
6883 /* AccAXRshS - right shift signed a:x known count (0..7)           */
6884 /*-----------------------------------------------------------------*/
6885 static void
6886 AccAXRshS (char *x, int shCount)
6887 {
6888   symbol *tlbl;
6889   switch (shCount)
6890     {
6891     case 0:
6892       break;
6893     case 1:
6894       emitcode ("mov", "c,acc.7");
6895       AccAXRrl1 (x);            // s->a:x
6896
6897       break;
6898     case 2:
6899       emitcode ("mov", "c,acc.7");
6900       AccAXRrl1 (x);            // s->a:x
6901
6902       emitcode ("mov", "c,acc.7");
6903       AccAXRrl1 (x);            // s->a:x
6904
6905       break;
6906     case 3:
6907     case 4:
6908     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6909
6910       tlbl = newiTempLabel (NULL);
6911       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
6912
6913       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6914
6915       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6916
6917       emitcode ("anl", "a,#0x%02x",
6918                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6919
6920       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6921
6922       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6923
6924       emitcode ("anl", "a,#0x%02x",
6925                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6926
6927       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6928
6929       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6930
6931       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
6932
6933       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6934       emitcode ("orl", "a,#0x%02x",
6935                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
6936
6937       emitcode ("", "%05d$:", tlbl->key + 100);
6938       break;                    // SSSSAAAA:BBBCCCCC
6939
6940     case 6:                     // AABBBBBB:CCDDDDDD
6941
6942       tlbl = newiTempLabel (NULL);
6943       emitcode ("mov", "c,acc.7");
6944       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6945
6946       emitcode ("mov", "c,acc.7");
6947       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6948
6949       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6950
6951       emitcode ("anl", "a,#0x%02x",
6952                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6953
6954       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6955       emitcode ("orl", "a,#0x%02x",
6956                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
6957
6958       emitcode ("", "%05d$:", tlbl->key + 100);
6959       break;
6960     case 7:                     // ABBBBBBB:CDDDDDDD
6961
6962       tlbl = newiTempLabel (NULL);
6963       emitcode ("mov", "c,acc.7");      // c = A
6964
6965       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6966
6967       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6968
6969       emitcode ("anl", "a,#0x%02x",
6970                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6971
6972       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6973       emitcode ("orl", "a,#0x%02x",
6974                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
6975
6976       emitcode ("", "%05d$:", tlbl->key + 100);
6977       break;
6978     default:
6979       break;
6980     }
6981 }
6982
6983 /*-----------------------------------------------------------------*/
6984 /* shiftL2Left2Result - shift left two bytes from left to result   */
6985 /*-----------------------------------------------------------------*/
6986 static void
6987 shiftL2Left2Result (operand * left, int offl,
6988                     operand * result, int offr, int shCount)
6989 {
6990   if (sameRegs (AOP (result), AOP (left)) &&
6991       ((offl + MSB16) == offr))
6992     {
6993       /* don't crash result[offr] */
6994       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6995       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6996     }
6997   else
6998     {
6999       movLeft2Result (left, offl, result, offr, 0);
7000       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7001     }
7002   /* ax << shCount (x = lsb(result)) */
7003   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7004   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7005 }
7006
7007
7008 /*-----------------------------------------------------------------*/
7009 /* shiftR2Left2Result - shift right two bytes from left to result  */
7010 /*-----------------------------------------------------------------*/
7011 static void
7012 shiftR2Left2Result (operand * left, int offl,
7013                     operand * result, int offr,
7014                     int shCount, int sign)
7015 {
7016   if (sameRegs (AOP (result), AOP (left)) &&
7017       ((offl + MSB16) == offr))
7018     {
7019       /* don't crash result[offr] */
7020       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7021       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7022     }
7023   else
7024     {
7025       movLeft2Result (left, offl, result, offr, 0);
7026       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7027     }
7028   /* a:x >> shCount (x = lsb(result)) */
7029   if (sign)
7030     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7031   else
7032     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7033   if (getDataSize (result) > 1)
7034     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7035 }
7036
7037 /*-----------------------------------------------------------------*/
7038 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7039 /*-----------------------------------------------------------------*/
7040 static void
7041 shiftLLeftOrResult (operand * left, int offl,
7042                     operand * result, int offr, int shCount)
7043 {
7044   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7045   /* shift left accumulator */
7046   AccLsh (shCount);
7047   /* or with result */
7048   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7049   /* back to result */
7050   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7051 }
7052
7053 /*-----------------------------------------------------------------*/
7054 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7055 /*-----------------------------------------------------------------*/
7056 static void
7057 shiftRLeftOrResult (operand * left, int offl,
7058                     operand * result, int offr, int shCount)
7059 {
7060   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7061   /* shift right accumulator */
7062   AccRsh (shCount);
7063   /* or with result */
7064   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7065   /* back to result */
7066   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7067 }
7068
7069 /*-----------------------------------------------------------------*/
7070 /* genlshOne - left shift a one byte quantity by known count       */
7071 /*-----------------------------------------------------------------*/
7072 static void
7073 genlshOne (operand * result, operand * left, int shCount)
7074 {
7075   D(emitcode (";     genlshOne",""));
7076
7077   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7078 }
7079
7080 /*-----------------------------------------------------------------*/
7081 /* genlshTwo - left shift two bytes by known amount != 0           */
7082 /*-----------------------------------------------------------------*/
7083 static void
7084 genlshTwo (operand * result, operand * left, int shCount)
7085 {
7086   int size;
7087
7088   D(emitcode (";     genlshTwo",""));
7089
7090   size = getDataSize (result);
7091
7092   /* if shCount >= 8 */
7093   if (shCount >= 8)
7094     {
7095       shCount -= 8;
7096
7097       if (size > 1)
7098         {
7099           if (shCount)
7100             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7101           else
7102             movLeft2Result (left, LSB, result, MSB16, 0);
7103         }
7104       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7105     }
7106
7107   /*  1 <= shCount <= 7 */
7108   else
7109     {
7110       if (size == 1)
7111         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7112       else
7113         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7114     }
7115 }
7116
7117 /*-----------------------------------------------------------------*/
7118 /* shiftLLong - shift left one long from left to result            */
7119 /* offl = LSB or MSB16                                             */
7120 /*-----------------------------------------------------------------*/
7121 static void
7122 shiftLLong (operand * left, operand * result, int offr)
7123 {
7124   char *l;
7125   int size = AOP_SIZE (result);
7126
7127   if (size >= LSB + offr)
7128     {
7129       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7130       MOVA (l);
7131       emitcode ("add", "a,acc");
7132       if (sameRegs (AOP (left), AOP (result)) &&
7133           size >= MSB16 + offr && offr != LSB)
7134         emitcode ("xch", "a,%s",
7135                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7136       else
7137         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7138     }
7139
7140   if (size >= MSB16 + offr)
7141     {
7142       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7143         {
7144           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7145           MOVA (l);
7146         }
7147       emitcode ("rlc", "a");
7148       if (sameRegs (AOP (left), AOP (result)) &&
7149           size >= MSB24 + offr && offr != LSB)
7150         emitcode ("xch", "a,%s",
7151                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7152       else
7153         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7154     }
7155
7156   if (size >= MSB24 + offr)
7157     {
7158       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7159         {
7160           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7161           MOVA (l);
7162         }
7163       emitcode ("rlc", "a");
7164       if (sameRegs (AOP (left), AOP (result)) &&
7165           size >= MSB32 + offr && offr != LSB)
7166         emitcode ("xch", "a,%s",
7167                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7168       else
7169         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7170     }
7171
7172   if (size > MSB32 + offr)
7173     {
7174       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7175         {
7176           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7177           MOVA (l);
7178         }
7179       emitcode ("rlc", "a");
7180       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7181     }
7182   if (offr != LSB)
7183     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7184 }
7185
7186 /*-----------------------------------------------------------------*/
7187 /* genlshFour - shift four byte by a known amount != 0             */
7188 /*-----------------------------------------------------------------*/
7189 static void
7190 genlshFour (operand * result, operand * left, int shCount)
7191 {
7192   int size;
7193
7194   D(emitcode (";     genlshFour",""));
7195
7196   size = AOP_SIZE (result);
7197
7198   /* if shifting more that 3 bytes */
7199   if (shCount >= 24)
7200     {
7201       shCount -= 24;
7202       if (shCount)
7203         /* lowest order of left goes to the highest
7204            order of the destination */
7205         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7206       else
7207         movLeft2Result (left, LSB, result, MSB32, 0);
7208       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7209       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7210       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7211       return;
7212     }
7213
7214   /* more than two bytes */
7215   else if (shCount >= 16)
7216     {
7217       /* lower order two bytes goes to higher order two bytes */
7218       shCount -= 16;
7219       /* if some more remaining */
7220       if (shCount)
7221         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7222       else
7223         {
7224           movLeft2Result (left, MSB16, result, MSB32, 0);
7225           movLeft2Result (left, LSB, result, MSB24, 0);
7226         }
7227       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7228       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7229       return;
7230     }
7231
7232   /* if more than 1 byte */
7233   else if (shCount >= 8)
7234     {
7235       /* lower order three bytes goes to higher order  three bytes */
7236       shCount -= 8;
7237       if (size == 2)
7238         {
7239           if (shCount)
7240             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7241           else
7242             movLeft2Result (left, LSB, result, MSB16, 0);
7243         }
7244       else
7245         {                       /* size = 4 */
7246           if (shCount == 0)
7247             {
7248               movLeft2Result (left, MSB24, result, MSB32, 0);
7249               movLeft2Result (left, MSB16, result, MSB24, 0);
7250               movLeft2Result (left, LSB, result, MSB16, 0);
7251               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7252             }
7253           else if (shCount == 1)
7254             shiftLLong (left, result, MSB16);
7255           else
7256             {
7257               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7258               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7259               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7260               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7261             }
7262         }
7263     }
7264
7265   /* 1 <= shCount <= 7 */
7266   else if (shCount <= 2)
7267     {
7268       shiftLLong (left, result, LSB);
7269       if (shCount == 2)
7270         shiftLLong (result, result, LSB);
7271     }
7272   /* 3 <= shCount <= 7, optimize */
7273   else
7274     {
7275       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7276       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7277       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7278     }
7279 }
7280
7281 /*-----------------------------------------------------------------*/
7282 /* genLeftShiftLiteral - left shifting by known count              */
7283 /*-----------------------------------------------------------------*/
7284 static void
7285 genLeftShiftLiteral (operand * left,
7286                      operand * right,
7287                      operand * result,
7288                      iCode * ic)
7289 {
7290   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7291   int size;
7292
7293   D(emitcode (";     genLeftShiftLiteral",""));
7294
7295   freeAsmop (right, NULL, ic, TRUE);
7296
7297   aopOp (left, ic, FALSE);
7298   aopOp (result, ic, FALSE);
7299
7300   size = getSize (operandType (result));
7301
7302 #if VIEW_SIZE
7303   emitcode ("; shift left ", "result %d, left %d", size,
7304             AOP_SIZE (left));
7305 #endif
7306
7307   /* I suppose that the left size >= result size */
7308   if (shCount == 0)
7309     {
7310       while (size--)
7311         {
7312           movLeft2Result (left, size, result, size, 0);
7313         }
7314     }
7315
7316   else if (shCount >= (size * 8))
7317     while (size--)
7318       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7319   else
7320     {
7321       switch (size)
7322         {
7323         case 1:
7324           genlshOne (result, left, shCount);
7325           break;
7326
7327         case 2:
7328           genlshTwo (result, left, shCount);
7329           break;
7330
7331         case 4:
7332           genlshFour (result, left, shCount);
7333           break;
7334         default:
7335           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7336                   "*** ack! mystery literal shift!\n");
7337           break;
7338         }
7339     }
7340   freeAsmop (left, NULL, ic, TRUE);
7341   freeAsmop (result, NULL, ic, TRUE);
7342 }
7343
7344 /*-----------------------------------------------------------------*/
7345 /* genLeftShift - generates code for left shifting                 */
7346 /*-----------------------------------------------------------------*/
7347 static void
7348 genLeftShift (iCode * ic)
7349 {
7350   operand *left, *right, *result;
7351   int size, offset;
7352   char *l;
7353   symbol *tlbl, *tlbl1;
7354
7355   D(emitcode (";     genLeftShift",""));
7356
7357   right = IC_RIGHT (ic);
7358   left = IC_LEFT (ic);
7359   result = IC_RESULT (ic);
7360
7361   aopOp (right, ic, FALSE);
7362
7363   /* if the shift count is known then do it
7364      as efficiently as possible */
7365   if (AOP_TYPE (right) == AOP_LIT)
7366     {
7367       genLeftShiftLiteral (left, right, result, ic);
7368       return;
7369     }
7370
7371   /* shift count is unknown then we have to form
7372      a loop get the loop count in B : Note: we take
7373      only the lower order byte since shifting
7374      more that 32 bits make no sense anyway, ( the
7375      largest size of an object can be only 32 bits ) */
7376
7377   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7378   emitcode ("inc", "b");
7379   freeAsmop (right, NULL, ic, TRUE);
7380   aopOp (left, ic, FALSE);
7381   aopOp (result, ic, FALSE);
7382
7383   /* now move the left to the result if they are not the
7384      same */
7385   if (!sameRegs (AOP (left), AOP (result)) &&
7386       AOP_SIZE (result) > 1)
7387     {
7388
7389       size = AOP_SIZE (result);
7390       offset = 0;
7391       while (size--)
7392         {
7393           l = aopGet (AOP (left), offset, FALSE, TRUE);
7394           if (*l == '@' && (IS_AOP_PREG (result)))
7395             {
7396
7397               emitcode ("mov", "a,%s", l);
7398               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7399             }
7400           else
7401             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7402           offset++;
7403         }
7404     }
7405
7406   tlbl = newiTempLabel (NULL);
7407   size = AOP_SIZE (result);
7408   offset = 0;
7409   tlbl1 = newiTempLabel (NULL);
7410
7411   /* if it is only one byte then */
7412   if (size == 1)
7413     {
7414       symbol *tlbl1 = newiTempLabel (NULL);
7415
7416       l = aopGet (AOP (left), 0, FALSE, FALSE);
7417       MOVA (l);
7418       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7419       emitcode ("", "%05d$:", tlbl->key + 100);
7420       emitcode ("add", "a,acc");
7421       emitcode ("", "%05d$:", tlbl1->key + 100);
7422       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7423       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7424       goto release;
7425     }
7426
7427   reAdjustPreg (AOP (result));
7428
7429   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7430   emitcode ("", "%05d$:", tlbl->key + 100);
7431   l = aopGet (AOP (result), offset, FALSE, FALSE);
7432   MOVA (l);
7433   emitcode ("add", "a,acc");
7434   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7435   while (--size)
7436     {
7437       l = aopGet (AOP (result), offset, FALSE, FALSE);
7438       MOVA (l);
7439       emitcode ("rlc", "a");
7440       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7441     }
7442   reAdjustPreg (AOP (result));
7443
7444   emitcode ("", "%05d$:", tlbl1->key + 100);
7445   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7446 release:
7447   freeAsmop (left, NULL, ic, TRUE);
7448   freeAsmop (result, NULL, ic, TRUE);
7449 }
7450
7451 /*-----------------------------------------------------------------*/
7452 /* genrshOne - right shift a one byte quantity by known count      */
7453 /*-----------------------------------------------------------------*/
7454 static void
7455 genrshOne (operand * result, operand * left,
7456            int shCount, int sign)
7457 {
7458   D(emitcode (";     genrshOne",""));
7459
7460   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7461 }
7462
7463 /*-----------------------------------------------------------------*/
7464 /* genrshTwo - right shift two bytes by known amount != 0          */
7465 /*-----------------------------------------------------------------*/
7466 static void
7467 genrshTwo (operand * result, operand * left,
7468            int shCount, int sign)
7469 {
7470   D(emitcode (";     genrshTwo",""));
7471
7472   /* if shCount >= 8 */
7473   if (shCount >= 8)
7474     {
7475       shCount -= 8;
7476       if (shCount)
7477         shiftR1Left2Result (left, MSB16, result, LSB,
7478                             shCount, sign);
7479       else
7480         movLeft2Result (left, MSB16, result, LSB, sign);
7481       addSign (result, MSB16, sign);
7482     }
7483
7484   /*  1 <= shCount <= 7 */
7485   else
7486     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7487 }
7488
7489 /*-----------------------------------------------------------------*/
7490 /* shiftRLong - shift right one long from left to result           */
7491 /* offl = LSB or MSB16                                             */
7492 /*-----------------------------------------------------------------*/
7493 static void
7494 shiftRLong (operand * left, int offl,
7495             operand * result, int sign)
7496 {
7497   int isSameRegs=sameRegs(AOP(left),AOP(result));
7498
7499   if (isSameRegs && offl>1) {
7500     // we are in big trouble, but this shouldn't happen
7501     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7502   }
7503
7504   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7505
7506   if (offl==MSB16) {
7507     // shift is > 8
7508     if (sign) {
7509       emitcode ("rlc", "a");
7510       emitcode ("subb", "a,acc");
7511       if (isSameRegs)
7512         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7513       else {
7514         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7515         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7516       }
7517     } else {
7518       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7519     }
7520   }
7521
7522   if (!sign) {
7523     emitcode ("clr", "c");
7524   } else {
7525     emitcode ("mov", "c,acc.7");
7526   }
7527
7528   emitcode ("rrc", "a");
7529
7530   if (isSameRegs && offl==MSB16) {
7531     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7532   } else {
7533     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7534     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7535   }
7536
7537   emitcode ("rrc", "a");
7538   if (isSameRegs && offl==1) {
7539     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7540   } else {
7541     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7542     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7543   }
7544   emitcode ("rrc", "a");
7545   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7546
7547   if (offl == LSB)
7548     {
7549       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7550       emitcode ("rrc", "a");
7551       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7552     }
7553 }
7554
7555 /*-----------------------------------------------------------------*/
7556 /* genrshFour - shift four byte by a known amount != 0             */
7557 /*-----------------------------------------------------------------*/
7558 static void
7559 genrshFour (operand * result, operand * left,
7560             int shCount, int sign)
7561 {
7562   D(emitcode (";     genrshFour",""));
7563
7564   /* if shifting more that 3 bytes */
7565   if (shCount >= 24)
7566     {
7567       shCount -= 24;
7568       if (shCount)
7569         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7570       else
7571         movLeft2Result (left, MSB32, result, LSB, sign);
7572       addSign (result, MSB16, sign);
7573     }
7574   else if (shCount >= 16)
7575     {
7576       shCount -= 16;
7577       if (shCount)
7578         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7579       else
7580         {
7581           movLeft2Result (left, MSB24, result, LSB, 0);
7582           movLeft2Result (left, MSB32, result, MSB16, sign);
7583         }
7584       addSign (result, MSB24, sign);
7585     }
7586   else if (shCount >= 8)
7587     {
7588       shCount -= 8;
7589       if (shCount == 1)
7590         shiftRLong (left, MSB16, result, sign);
7591       else if (shCount == 0)
7592         {
7593           movLeft2Result (left, MSB16, result, LSB, 0);
7594           movLeft2Result (left, MSB24, result, MSB16, 0);
7595           movLeft2Result (left, MSB32, result, MSB24, sign);
7596           addSign (result, MSB32, sign);
7597         }
7598       else
7599         {
7600           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7601           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7602           /* the last shift is signed */
7603           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7604           addSign (result, MSB32, sign);
7605         }
7606     }
7607   else
7608     {                           /* 1 <= shCount <= 7 */
7609       if (shCount <= 2)
7610         {
7611           shiftRLong (left, LSB, result, sign);
7612           if (shCount == 2)
7613             shiftRLong (result, LSB, result, sign);
7614         }
7615       else
7616         {
7617           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7618           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7619           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7620         }
7621     }
7622 }
7623
7624 /*-----------------------------------------------------------------*/
7625 /* genRightShiftLiteral - right shifting by known count            */
7626 /*-----------------------------------------------------------------*/
7627 static void
7628 genRightShiftLiteral (operand * left,
7629                       operand * right,
7630                       operand * result,
7631                       iCode * ic,
7632                       int sign)
7633 {
7634   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7635   int size;
7636
7637   D(emitcode (";     genRightShiftLiteral",""));
7638
7639   freeAsmop (right, NULL, ic, TRUE);
7640
7641   aopOp (left, ic, FALSE);
7642   aopOp (result, ic, FALSE);
7643
7644 #if VIEW_SIZE
7645   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7646             AOP_SIZE (left));
7647 #endif
7648
7649   size = getDataSize (left);
7650   /* test the LEFT size !!! */
7651
7652   /* I suppose that the left size >= result size */
7653   if (shCount == 0)
7654     {
7655       size = getDataSize (result);
7656       while (size--)
7657         movLeft2Result (left, size, result, size, 0);
7658     }
7659
7660   else if (shCount >= (size * 8))
7661     {
7662       if (sign) {
7663         /* get sign in acc.7 */
7664         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7665       }
7666       addSign (result, LSB, sign);
7667     }
7668   else
7669     {
7670       switch (size)
7671         {
7672         case 1:
7673           genrshOne (result, left, shCount, sign);
7674           break;
7675
7676         case 2:
7677           genrshTwo (result, left, shCount, sign);
7678           break;
7679
7680         case 4:
7681           genrshFour (result, left, shCount, sign);
7682           break;
7683         default:
7684           break;
7685         }
7686     }
7687   freeAsmop (left, NULL, ic, TRUE);
7688   freeAsmop (result, NULL, ic, TRUE);
7689 }
7690
7691 /*-----------------------------------------------------------------*/
7692 /* genSignedRightShift - right shift of signed number              */
7693 /*-----------------------------------------------------------------*/
7694 static void
7695 genSignedRightShift (iCode * ic)
7696 {
7697   operand *right, *left, *result;
7698   int size, offset;
7699   char *l;
7700   symbol *tlbl, *tlbl1;
7701
7702   D(emitcode (";     genSignedRightShift",""));
7703
7704   /* we do it the hard way put the shift count in b
7705      and loop thru preserving the sign */
7706
7707   right = IC_RIGHT (ic);
7708   left = IC_LEFT (ic);
7709   result = IC_RESULT (ic);
7710
7711   aopOp (right, ic, FALSE);
7712
7713
7714   if (AOP_TYPE (right) == AOP_LIT)
7715     {
7716       genRightShiftLiteral (left, right, result, ic, 1);
7717       return;
7718     }
7719   /* shift count is unknown then we have to form
7720      a loop get the loop count in B : Note: we take
7721      only the lower order byte since shifting
7722      more that 32 bits make no sense anyway, ( the
7723      largest size of an object can be only 32 bits ) */
7724
7725   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7726   emitcode ("inc", "b");
7727   freeAsmop (right, NULL, ic, TRUE);
7728   aopOp (left, ic, FALSE);
7729   aopOp (result, ic, FALSE);
7730
7731   /* now move the left to the result if they are not the
7732      same */
7733   if (!sameRegs (AOP (left), AOP (result)) &&
7734       AOP_SIZE (result) > 1)
7735     {
7736
7737       size = AOP_SIZE (result);
7738       offset = 0;
7739       while (size--)
7740         {
7741           l = aopGet (AOP (left), offset, FALSE, TRUE);
7742           if (*l == '@' && IS_AOP_PREG (result))
7743             {
7744
7745               emitcode ("mov", "a,%s", l);
7746               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7747             }
7748           else
7749             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7750           offset++;
7751         }
7752     }
7753
7754   /* mov the highest order bit to OVR */
7755   tlbl = newiTempLabel (NULL);
7756   tlbl1 = newiTempLabel (NULL);
7757
7758   size = AOP_SIZE (result);
7759   offset = size - 1;
7760   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7761   emitcode ("rlc", "a");
7762   emitcode ("mov", "ov,c");
7763   /* if it is only one byte then */
7764   if (size == 1)
7765     {
7766       l = aopGet (AOP (left), 0, FALSE, FALSE);
7767       MOVA (l);
7768       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7769       emitcode ("", "%05d$:", tlbl->key + 100);
7770       emitcode ("mov", "c,ov");
7771       emitcode ("rrc", "a");
7772       emitcode ("", "%05d$:", tlbl1->key + 100);
7773       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7774       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7775       goto release;
7776     }
7777
7778   reAdjustPreg (AOP (result));
7779   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7780   emitcode ("", "%05d$:", tlbl->key + 100);
7781   emitcode ("mov", "c,ov");
7782   while (size--)
7783     {
7784       l = aopGet (AOP (result), offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rrc", "a");
7787       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7788     }
7789   reAdjustPreg (AOP (result));
7790   emitcode ("", "%05d$:", tlbl1->key + 100);
7791   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7792
7793 release:
7794   freeAsmop (left, NULL, ic, TRUE);
7795   freeAsmop (result, NULL, ic, TRUE);
7796 }
7797
7798 /*-----------------------------------------------------------------*/
7799 /* genRightShift - generate code for right shifting                */
7800 /*-----------------------------------------------------------------*/
7801 static void
7802 genRightShift (iCode * ic)
7803 {
7804   operand *right, *left, *result;
7805   sym_link *letype;
7806   int size, offset;
7807   char *l;
7808   symbol *tlbl, *tlbl1;
7809
7810   D(emitcode (";     genRightShift",""));
7811
7812   /* if signed then we do it the hard way preserve the
7813      sign bit moving it inwards */
7814   letype = getSpec (operandType (IC_LEFT (ic)));
7815
7816   if (!SPEC_USIGN (letype))
7817     {
7818       genSignedRightShift (ic);
7819       return;
7820     }
7821
7822   /* signed & unsigned types are treated the same : i.e. the
7823      signed is NOT propagated inwards : quoting from the
7824      ANSI - standard : "for E1 >> E2, is equivalent to division
7825      by 2**E2 if unsigned or if it has a non-negative value,
7826      otherwise the result is implementation defined ", MY definition
7827      is that the sign does not get propagated */
7828
7829   right = IC_RIGHT (ic);
7830   left = IC_LEFT (ic);
7831   result = IC_RESULT (ic);
7832
7833   aopOp (right, ic, FALSE);
7834
7835   /* if the shift count is known then do it
7836      as efficiently as possible */
7837   if (AOP_TYPE (right) == AOP_LIT)
7838     {
7839       genRightShiftLiteral (left, right, result, ic, 0);
7840       return;
7841     }
7842
7843   /* shift count is unknown then we have to form
7844      a loop get the loop count in B : Note: we take
7845      only the lower order byte since shifting
7846      more that 32 bits make no sense anyway, ( the
7847      largest size of an object can be only 32 bits ) */
7848
7849   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7850   emitcode ("inc", "b");
7851   freeAsmop (right, NULL, ic, TRUE);
7852   aopOp (left, ic, FALSE);
7853   aopOp (result, ic, FALSE);
7854
7855   /* now move the left to the result if they are not the
7856      same */
7857   if (!sameRegs (AOP (left), AOP (result)) &&
7858       AOP_SIZE (result) > 1)
7859     {
7860
7861       size = AOP_SIZE (result);
7862       offset = 0;
7863       while (size--)
7864         {
7865           l = aopGet (AOP (left), offset, FALSE, TRUE);
7866           if (*l == '@' && IS_AOP_PREG (result))
7867             {
7868
7869               emitcode ("mov", "a,%s", l);
7870               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7871             }
7872           else
7873             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7874           offset++;
7875         }
7876     }
7877
7878   tlbl = newiTempLabel (NULL);
7879   tlbl1 = newiTempLabel (NULL);
7880   size = AOP_SIZE (result);
7881   offset = size - 1;
7882
7883   /* if it is only one byte then */
7884   if (size == 1)
7885     {
7886       l = aopGet (AOP (left), 0, FALSE, FALSE);
7887       MOVA (l);
7888       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7889       emitcode ("", "%05d$:", tlbl->key + 100);
7890       CLRC;
7891       emitcode ("rrc", "a");
7892       emitcode ("", "%05d$:", tlbl1->key + 100);
7893       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7894       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7895       goto release;
7896     }
7897
7898   reAdjustPreg (AOP (result));
7899   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7900   emitcode ("", "%05d$:", tlbl->key + 100);
7901   CLRC;
7902   while (size--)
7903     {
7904       l = aopGet (AOP (result), offset, FALSE, FALSE);
7905       MOVA (l);
7906       emitcode ("rrc", "a");
7907       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7908     }
7909   reAdjustPreg (AOP (result));
7910
7911   emitcode ("", "%05d$:", tlbl1->key + 100);
7912   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7913
7914 release:
7915   freeAsmop (left, NULL, ic, TRUE);
7916   freeAsmop (result, NULL, ic, TRUE);
7917 }
7918
7919 /*-----------------------------------------------------------------*/
7920 /* emitPtrByteGet - emits code to get a byte into A through a      */
7921 /*                  pointer register (R0, R1, or DPTR). The        */
7922 /*                  original value of A can be preserved in B.     */
7923 /*-----------------------------------------------------------------*/
7924 static void
7925 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
7926 {
7927   switch (p_type)
7928     {
7929     case IPOINTER:
7930     case POINTER:
7931       if (preserveAinB)
7932         emitcode ("mov", "b,a");
7933       emitcode ("mov", "a,@%s", rname);
7934       break;
7935
7936     case PPOINTER:
7937       if (preserveAinB)
7938         emitcode ("mov", "b,a");
7939       emitcode ("movx", "a,@%s", rname);
7940       break;
7941
7942     case FPOINTER:
7943       if (preserveAinB)
7944         emitcode ("mov", "b,a");
7945       emitcode ("movx", "a,@dptr");
7946       break;
7947
7948     case CPOINTER:
7949       if (preserveAinB)
7950         emitcode ("mov", "b,a");
7951       emitcode ("clr", "a");
7952       emitcode ("movc", "a,@a+dptr");
7953       break;
7954
7955     case GPOINTER:
7956       if (preserveAinB)
7957         {
7958           emitcode ("push", "b");
7959           emitcode ("push", "acc");
7960         }
7961       emitcode ("lcall", "__gptrget");
7962       if (preserveAinB)
7963         emitcode ("pop", "b");
7964       break;
7965     }
7966 }
7967
7968 /*-----------------------------------------------------------------*/
7969 /* emitPtrByteSet - emits code to set a byte from src through a    */
7970 /*                  pointer register (R0, R1, or DPTR).            */
7971 /*-----------------------------------------------------------------*/
7972 static void
7973 emitPtrByteSet (char *rname, int p_type, char *src)
7974 {
7975   switch (p_type)
7976     {
7977     case IPOINTER:
7978     case POINTER:
7979       if (*src=='@')
7980         {
7981           MOVA (src);
7982           emitcode ("mov", "@%s,a", rname);
7983         }
7984       else
7985         emitcode ("mov", "@%s,%s", rname, src);
7986       break;
7987
7988     case PPOINTER:
7989       MOVA (src);
7990       emitcode ("movx", "@%s,a", rname);
7991       break;
7992
7993     case FPOINTER:
7994       MOVA (src);
7995       emitcode ("movx", "@dptr,a");
7996       break;
7997
7998     case GPOINTER:
7999       MOVA (src);
8000       emitcode ("lcall", "__gptrput");
8001       break;
8002     }
8003 }
8004
8005 /*-----------------------------------------------------------------*/
8006 /* genUnpackBits - generates code for unpacking bits               */
8007 /*-----------------------------------------------------------------*/
8008 static void
8009 genUnpackBits (operand * result, char *rname, int ptype)
8010 {
8011   int offset = 0;       /* result byte offset */
8012   int rsize;            /* result size */
8013   int rlen = 0;         /* remaining bitfield length */
8014   sym_link *etype;      /* bitfield type information */
8015   int blen;             /* bitfield length */
8016   int bstr;             /* bitfield starting bit within byte */
8017
8018   D(emitcode (";     genUnpackBits",""));
8019
8020   etype = getSpec (operandType (result));
8021   rsize = getSize (operandType (result));
8022   blen = SPEC_BLEN (etype);
8023   bstr = SPEC_BSTR (etype);
8024
8025   /* If the bitfield length is less than a byte */
8026   if (blen < 8)
8027     {
8028       emitPtrByteGet (rname, ptype, FALSE);
8029       AccRsh (bstr);
8030       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8031       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8032       goto finish;
8033     }
8034
8035   /* Bit field did not fit in a byte. Copy all
8036      but the partial byte at the end.  */
8037   for (rlen=blen;rlen>=8;rlen-=8)
8038     {
8039       emitPtrByteGet (rname, ptype, FALSE);
8040       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8041       if (rlen>8)
8042         emitcode ("inc", "%s", rname);
8043     }
8044
8045   /* Handle the partial byte at the end */
8046   if (rlen)
8047     {
8048       emitPtrByteGet (rname, ptype, FALSE);
8049       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8050       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8051     }
8052
8053 finish:
8054   if (offset < rsize)
8055     {
8056       rsize -= offset;
8057       while (rsize--)
8058         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8059     }
8060 }
8061
8062
8063 /*-----------------------------------------------------------------*/
8064 /* genDataPointerGet - generates code when ptr offset is known     */
8065 /*-----------------------------------------------------------------*/
8066 static void
8067 genDataPointerGet (operand * left,
8068                    operand * result,
8069                    iCode * ic)
8070 {
8071   char *l;
8072   char buffer[256];
8073   int size, offset = 0;
8074
8075   D(emitcode (";     genDataPointerGet",""));
8076
8077   aopOp (result, ic, TRUE);
8078
8079   /* get the string representation of the name */
8080   l = aopGet (AOP (left), 0, FALSE, TRUE);
8081   size = AOP_SIZE (result);
8082   while (size--)
8083     {
8084       if (offset)
8085         sprintf (buffer, "(%s + %d)", l + 1, offset);
8086       else
8087         sprintf (buffer, "%s", l + 1);
8088       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8089     }
8090
8091   freeAsmop (left, NULL, ic, TRUE);
8092   freeAsmop (result, NULL, ic, TRUE);
8093 }
8094
8095 /*-----------------------------------------------------------------*/
8096 /* genNearPointerGet - emitcode for near pointer fetch             */
8097 /*-----------------------------------------------------------------*/
8098 static void
8099 genNearPointerGet (operand * left,
8100                    operand * result,
8101                    iCode * ic,
8102                    iCode * pi)
8103 {
8104   asmop *aop = NULL;
8105   regs *preg = NULL;
8106   char *rname;
8107   sym_link *rtype, *retype;
8108   sym_link *ltype = operandType (left);
8109   char buffer[80];
8110
8111   D(emitcode (";     genNearPointerGet",""));
8112
8113   rtype = operandType (result);
8114   retype = getSpec (rtype);
8115
8116   aopOp (left, ic, FALSE);
8117
8118   /* if left is rematerialisable and
8119      result is not bitfield variable type and
8120      the left is pointer to data space i.e
8121      lower 128 bytes of space */
8122   if (AOP_TYPE (left) == AOP_IMMD &&
8123       !IS_BITFIELD (retype) &&
8124       DCL_TYPE (ltype) == POINTER)
8125     {
8126       genDataPointerGet (left, result, ic);
8127       return;
8128     }
8129
8130  /* if the value is already in a pointer register
8131      then don't need anything more */
8132   if (!AOP_INPREG (AOP (left)))
8133     {
8134       if (IS_AOP_PREG (left))
8135         {
8136           // Aha, it is a pointer, just in disguise.
8137           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8138           if (*rname != '@')
8139             {
8140               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8141                       __FILE__, __LINE__);
8142             }
8143           else
8144             {
8145               // Expected case.
8146               emitcode ("mov", "a%s,%s", rname + 1, rname);
8147               rname++;  // skip the '@'.
8148             }
8149         }
8150       else
8151         {
8152           /* otherwise get a free pointer register */
8153           aop = newAsmop (0);
8154           preg = getFreePtr (ic, &aop, FALSE);
8155           emitcode ("mov", "%s,%s",
8156                     preg->name,
8157                     aopGet (AOP (left), 0, FALSE, TRUE));
8158           rname = preg->name;
8159         }
8160     }
8161   else
8162     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8163
8164   //aopOp (result, ic, FALSE);
8165   aopOp (result, ic, result?TRUE:FALSE);
8166
8167   /* if bitfield then unpack the bits */
8168   if (IS_BITFIELD (retype))
8169     genUnpackBits (result, rname, POINTER);
8170   else
8171     {
8172       /* we have can just get the values */
8173       int size = AOP_SIZE (result);
8174       int offset = 0;
8175
8176       while (size--)
8177         {
8178           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8179             {
8180
8181               emitcode ("mov", "a,@%s", rname);
8182               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8183             }
8184           else
8185             {
8186               sprintf (buffer, "@%s", rname);
8187               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8188             }
8189           offset++;
8190           if (size || pi)
8191             emitcode ("inc", "%s", rname);
8192         }
8193     }
8194
8195   /* now some housekeeping stuff */
8196   if (aop)       /* we had to allocate for this iCode */
8197     {
8198       if (pi) { /* post increment present */
8199         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8200       }
8201       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8202     }
8203   else
8204     {
8205       /* we did not allocate which means left
8206          already in a pointer register, then
8207          if size > 0 && this could be used again
8208          we have to point it back to where it
8209          belongs */
8210       if ((AOP_SIZE (result) > 1 &&
8211            !OP_SYMBOL (left)->remat &&
8212            (OP_SYMBOL (left)->liveTo > ic->seq ||
8213             ic->depth)) &&
8214           !pi)
8215         {
8216           int size = AOP_SIZE (result) - 1;
8217           while (size--)
8218             emitcode ("dec", "%s", rname);
8219         }
8220     }
8221
8222   /* done */
8223   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8224   freeAsmop (left, NULL, ic, TRUE);
8225   if (pi) pi->generated = 1;
8226 }
8227
8228 /*-----------------------------------------------------------------*/
8229 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8230 /*-----------------------------------------------------------------*/
8231 static void
8232 genPagedPointerGet (operand * left,
8233                     operand * result,
8234                     iCode * ic,
8235                     iCode *pi)
8236 {
8237   asmop *aop = NULL;
8238   regs *preg = NULL;
8239   char *rname;
8240   sym_link *rtype, *retype;
8241
8242   D(emitcode (";     genPagedPointerGet",""));
8243
8244   rtype = operandType (result);
8245   retype = getSpec (rtype);
8246
8247   aopOp (left, ic, FALSE);
8248
8249   /* if the value is already in a pointer register
8250      then don't need anything more */
8251   if (!AOP_INPREG (AOP (left)))
8252     {
8253       /* otherwise get a free pointer register */
8254       aop = newAsmop (0);
8255       preg = getFreePtr (ic, &aop, FALSE);
8256       emitcode ("mov", "%s,%s",
8257                 preg->name,
8258                 aopGet (AOP (left), 0, FALSE, TRUE));
8259       rname = preg->name;
8260     }
8261   else
8262     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8263
8264   aopOp (result, ic, FALSE);
8265
8266   /* if bitfield then unpack the bits */
8267   if (IS_BITFIELD (retype))
8268     genUnpackBits (result, rname, PPOINTER);
8269   else
8270     {
8271       /* we have can just get the values */
8272       int size = AOP_SIZE (result);
8273       int offset = 0;
8274
8275       while (size--)
8276         {
8277
8278           emitcode ("movx", "a,@%s", rname);
8279           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8280
8281           offset++;
8282
8283           if (size || pi)
8284             emitcode ("inc", "%s", rname);
8285         }
8286     }
8287
8288   /* now some housekeeping stuff */
8289   if (aop) /* we had to allocate for this iCode */
8290     {
8291       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8292       freeAsmop (NULL, aop, ic, TRUE);
8293     }
8294   else
8295     {
8296       /* we did not allocate which means left
8297          already in a pointer register, then
8298          if size > 0 && this could be used again
8299          we have to point it back to where it
8300          belongs */
8301       if ((AOP_SIZE (result) > 1 &&
8302            !OP_SYMBOL (left)->remat &&
8303            (OP_SYMBOL (left)->liveTo > ic->seq ||
8304             ic->depth)) &&
8305           !pi)
8306         {
8307           int size = AOP_SIZE (result) - 1;
8308           while (size--)
8309             emitcode ("dec", "%s", rname);
8310         }
8311     }
8312
8313   /* done */
8314   freeAsmop (left, NULL, ic, TRUE);
8315   freeAsmop (result, NULL, ic, TRUE);
8316   if (pi) pi->generated = 1;
8317
8318 }
8319
8320 /*--------------------------------------------------------------------*/
8321 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8322 /*--------------------------------------------------------------------*/
8323 static void
8324 loadDptrFromOperand (operand *op, bool loadBToo)
8325 {
8326   if (AOP_TYPE (op) != AOP_STR)
8327     {
8328       /* if this is remateriazable */
8329       if (AOP_TYPE (op) == AOP_IMMD)
8330         {
8331           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8332           if (loadBToo)
8333             {
8334               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8335                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8336               else
8337                 {
8338                   wassertl(FALSE, "need pointerCode");
8339                   emitcode ("", "; mov b,???");
8340                   /* genPointerGet and genPointerSet originally did different
8341                   ** things for this case. Both seem wrong.
8342                   ** from genPointerGet:
8343                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8344                   ** from genPointerSet:
8345                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8346                   */
8347                 }
8348             }
8349         }
8350       else if (AOP_TYPE (op) == AOP_DPTR)
8351         {
8352           if (loadBToo)
8353             {
8354               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8355               emitcode ("push", "acc");
8356               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8357               emitcode ("push", "acc");
8358               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8359               emitcode ("pop", "dph");
8360               emitcode ("pop", "dpl");
8361             }
8362           else
8363             {
8364               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8365               emitcode ("push", "acc");
8366               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8367               emitcode ("pop", "dpl");
8368             }
8369         }
8370       else
8371         {                       /* we need to get it byte by byte */
8372           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8373           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8374           if (loadBToo)
8375             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8376         }
8377     }
8378 }
8379
8380 /*-----------------------------------------------------------------*/
8381 /* genFarPointerGet - gget value from far space                    */
8382 /*-----------------------------------------------------------------*/
8383 static void
8384 genFarPointerGet (operand * left,
8385                   operand * result, iCode * ic, iCode * pi)
8386 {
8387   int size, offset;
8388   sym_link *retype = getSpec (operandType (result));
8389
8390   D(emitcode (";     genFarPointerGet",""));
8391
8392   aopOp (left, ic, FALSE);
8393   loadDptrFromOperand (left, FALSE);
8394
8395   /* so dptr now contains the address */
8396   aopOp (result, ic, FALSE);
8397
8398   /* if bit then unpack */
8399   if (IS_BITFIELD (retype))
8400     genUnpackBits (result, "dptr", FPOINTER);
8401   else
8402     {
8403       size = AOP_SIZE (result);
8404       offset = 0;
8405
8406       while (size--)
8407         {
8408           emitcode ("movx", "a,@dptr");
8409           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8410           if (size || pi)
8411             emitcode ("inc", "dptr");
8412         }
8413     }
8414
8415   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8416     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8417     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8418     pi->generated = 1;
8419   }
8420   freeAsmop (left, NULL, ic, TRUE);
8421   freeAsmop (result, NULL, ic, TRUE);
8422 }
8423
8424 /*-----------------------------------------------------------------*/
8425 /* genCodePointerGet - gget value from code space                  */
8426 /*-----------------------------------------------------------------*/
8427 static void
8428 genCodePointerGet (operand * left,
8429                     operand * result, iCode * ic, iCode *pi)
8430 {
8431   int size, offset;
8432   sym_link *retype = getSpec (operandType (result));
8433
8434   D(emitcode (";     genCodePointerGet",""));
8435
8436   aopOp (left, ic, FALSE);
8437   loadDptrFromOperand (left, FALSE);
8438
8439   /* so dptr now contains the address */
8440   aopOp (result, ic, FALSE);
8441
8442   /* if bit then unpack */
8443   if (IS_BITFIELD (retype))
8444     genUnpackBits (result, "dptr", CPOINTER);
8445   else
8446     {
8447       size = AOP_SIZE (result);
8448       offset = 0;
8449
8450       while (size--)
8451         {
8452           if (pi)
8453             {
8454               emitcode ("clr", "a");
8455               emitcode ("movc", "a,@a+dptr");
8456               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8457               emitcode ("inc", "dptr");
8458             }
8459           else
8460             {
8461               emitcode ("mov", "a,#0x%02x", offset);
8462               emitcode ("movc", "a,@a+dptr");
8463               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8464             }
8465         }
8466     }
8467
8468   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8469     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8470     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8471     pi->generated = 1;
8472   }
8473   freeAsmop (left, NULL, ic, TRUE);
8474   freeAsmop (result, NULL, ic, TRUE);
8475 }
8476
8477 /*-----------------------------------------------------------------*/
8478 /* genGenPointerGet - gget value from generic pointer space        */
8479 /*-----------------------------------------------------------------*/
8480 static void
8481 genGenPointerGet (operand * left,
8482                   operand * result, iCode * ic, iCode *pi)
8483 {
8484   int size, offset;
8485   sym_link *retype = getSpec (operandType (result));
8486
8487   D(emitcode (";     genGenPointerGet",""));
8488
8489   aopOp (left, ic, FALSE);
8490   loadDptrFromOperand (left, TRUE);
8491
8492   /* so dptr know contains the address */
8493   aopOp (result, ic, FALSE);
8494
8495   /* if bit then unpack */
8496   if (IS_BITFIELD (retype))
8497     genUnpackBits (result, "dptr", GPOINTER);
8498   else
8499     {
8500       size = AOP_SIZE (result);
8501       offset = 0;
8502
8503       while (size--)
8504         {
8505           emitcode ("lcall", "__gptrget");
8506           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8507           if (size || pi)
8508             emitcode ("inc", "dptr");
8509         }
8510     }
8511
8512   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8513     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8514     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8515     pi->generated = 1;
8516   }
8517   freeAsmop (left, NULL, ic, TRUE);
8518   freeAsmop (result, NULL, ic, TRUE);
8519 }
8520
8521 /*-----------------------------------------------------------------*/
8522 /* genPointerGet - generate code for pointer get                   */
8523 /*-----------------------------------------------------------------*/
8524 static void
8525 genPointerGet (iCode * ic, iCode *pi)
8526 {
8527   operand *left, *result;
8528   sym_link *type, *etype;
8529   int p_type;
8530
8531   D(emitcode (";     genPointerGet",""));
8532
8533   left = IC_LEFT (ic);
8534   result = IC_RESULT (ic);
8535
8536   /* depending on the type of pointer we need to
8537      move it to the correct pointer register */
8538   type = operandType (left);
8539   etype = getSpec (type);
8540   /* if left is of type of pointer then it is simple */
8541   if (IS_PTR (type) && !IS_FUNC (type->next))
8542     p_type = DCL_TYPE (type);
8543   else
8544     {
8545       /* we have to go by the storage class */
8546       p_type = PTR_TYPE (SPEC_OCLS (etype));
8547     }
8548
8549   /* special case when cast remat */
8550   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8551       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8552           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8553           type = operandType (left);
8554           p_type = DCL_TYPE (type);
8555   }
8556   /* now that we have the pointer type we assign
8557      the pointer values */
8558   switch (p_type)
8559     {
8560
8561     case POINTER:
8562     case IPOINTER:
8563       genNearPointerGet (left, result, ic, pi);
8564       break;
8565
8566     case PPOINTER:
8567       genPagedPointerGet (left, result, ic, pi);
8568       break;
8569
8570     case FPOINTER:
8571       genFarPointerGet (left, result, ic, pi);
8572       break;
8573
8574     case CPOINTER:
8575       genCodePointerGet (left, result, ic, pi);
8576       break;
8577
8578     case GPOINTER:
8579       genGenPointerGet (left, result, ic, pi);
8580       break;
8581     }
8582
8583 }
8584
8585
8586
8587 /*-----------------------------------------------------------------*/
8588 /* genPackBits - generates code for packed bit storage             */
8589 /*-----------------------------------------------------------------*/
8590 static void
8591 genPackBits (sym_link * etype,
8592              operand * right,
8593              char *rname, int p_type)
8594 {
8595   int offset = 0;       /* source byte offset */
8596   int rlen = 0;         /* remaining bitfield length */
8597   int blen;             /* bitfield length */
8598   int bstr;             /* bitfield starting bit within byte */
8599   int litval;           /* source literal value (if AOP_LIT) */
8600   unsigned char mask;   /* bitmask within current byte */
8601
8602   D(emitcode (";     genPackBits",""));
8603
8604   blen = SPEC_BLEN (etype);
8605   bstr = SPEC_BSTR (etype);
8606
8607   /* If the bitfield length is less than a byte */
8608   if (blen < 8)
8609     {
8610       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8611               (unsigned char) (0xFF >> (8 - bstr)));
8612
8613       if (AOP_TYPE (right) == AOP_LIT)
8614         {
8615           /* Case with a bitfield length <8 and literal source
8616           */
8617           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8618           litval <<= bstr;
8619           litval &= (~mask) & 0xff;
8620           emitPtrByteGet (rname, p_type, FALSE);
8621           if ((mask|litval)!=0xff)
8622             emitcode ("anl","a,#0x%02x", mask);
8623           if (litval)
8624             emitcode ("orl","a,#0x%02x", litval);
8625         }
8626       else
8627         {
8628           if ((blen==1) && (p_type!=GPOINTER))
8629             {
8630               /* Case with a bitfield length == 1 and no generic pointer
8631               */
8632               if (AOP_TYPE (right) == AOP_CRY)
8633                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8634               else
8635                 {
8636                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8637                   emitcode ("rrc","a");
8638                 }
8639               emitPtrByteGet (rname, p_type, FALSE);
8640               emitcode ("mov","acc.%d,c",bstr);
8641             }
8642           else
8643             {
8644               /* Case with a bitfield length < 8 and arbitrary source
8645               */
8646               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8647               /* shift and mask source value */
8648               AccLsh (bstr);
8649               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8650
8651               /* transfer A to B and get next byte */
8652               emitPtrByteGet (rname, p_type, TRUE);
8653
8654               emitcode ("anl", "a,#0x%02x", mask);
8655               emitcode ("orl", "a,b");
8656               if (p_type == GPOINTER)
8657                 emitcode ("pop", "b");
8658            }
8659         }
8660
8661       emitPtrByteSet (rname, p_type, "a");
8662       return;
8663     }
8664
8665   /* Bit length is greater than 7 bits. In this case, copy  */
8666   /* all except the partial byte at the end                 */
8667   for (rlen=blen;rlen>=8;rlen-=8)
8668     {
8669       emitPtrByteSet (rname, p_type,
8670                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8671       if (rlen>8)
8672         emitcode ("inc", "%s", rname);
8673     }
8674
8675   /* If there was a partial byte at the end */
8676   if (rlen)
8677     {
8678       mask = (((unsigned char) -1 << rlen) & 0xff);
8679
8680       if (AOP_TYPE (right) == AOP_LIT)
8681         {
8682           /* Case with partial byte and literal source
8683           */
8684           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8685           litval >>= (blen-rlen);
8686           litval &= (~mask) & 0xff;
8687           emitPtrByteGet (rname, p_type, FALSE);
8688           if ((mask|litval)!=0xff)
8689             emitcode ("anl","a,#0x%02x", mask);
8690           if (litval)
8691             emitcode ("orl","a,#0x%02x", litval);
8692         }
8693       else
8694         {
8695           /* Case with partial byte and arbitrary source
8696           */
8697           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8698           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8699
8700           /* transfer A to B and get next byte */
8701           emitPtrByteGet (rname, p_type, TRUE);
8702
8703           emitcode ("anl", "a,#0x%02x", mask);
8704           emitcode ("orl", "a,b");
8705           if (p_type == GPOINTER)
8706             emitcode ("pop", "b");
8707         }
8708       emitPtrByteSet (rname, p_type, "a");
8709     }
8710
8711 }
8712
8713
8714 /*-----------------------------------------------------------------*/
8715 /* genDataPointerSet - remat pointer to data space                 */
8716 /*-----------------------------------------------------------------*/
8717 static void
8718 genDataPointerSet (operand * right,
8719                    operand * result,
8720                    iCode * ic)
8721 {
8722   int size, offset = 0;
8723   char *l, buffer[256];
8724
8725   D(emitcode (";     genDataPointerSet",""));
8726
8727   aopOp (right, ic, FALSE);
8728
8729   l = aopGet (AOP (result), 0, FALSE, TRUE);
8730   size = AOP_SIZE (right);
8731   while (size--)
8732     {
8733       if (offset)
8734         sprintf (buffer, "(%s + %d)", l + 1, offset);
8735       else
8736         sprintf (buffer, "%s", l + 1);
8737       emitcode ("mov", "%s,%s", buffer,
8738                 aopGet (AOP (right), offset++, FALSE, FALSE));
8739     }
8740
8741   freeAsmop (right, NULL, ic, TRUE);
8742   freeAsmop (result, NULL, ic, TRUE);
8743 }
8744
8745 /*-----------------------------------------------------------------*/
8746 /* genNearPointerSet - emitcode for near pointer put                */
8747 /*-----------------------------------------------------------------*/
8748 static void
8749 genNearPointerSet (operand * right,
8750                    operand * result,
8751                    iCode * ic,
8752                    iCode * pi)
8753 {
8754   asmop *aop = NULL;
8755   regs *preg = NULL;
8756   char *rname, *l;
8757   sym_link *retype, *letype;
8758   sym_link *ptype = operandType (result);
8759
8760   D(emitcode (";     genNearPointerSet",""));
8761
8762   retype = getSpec (operandType (right));
8763   letype = getSpec (ptype);
8764   aopOp (result, ic, FALSE);
8765
8766   /* if the result is rematerializable &
8767      in data space & not a bit variable */
8768   if (AOP_TYPE (result) == AOP_IMMD &&
8769       DCL_TYPE (ptype) == POINTER &&
8770       !IS_BITVAR (retype) &&
8771       !IS_BITVAR (letype))
8772     {
8773       genDataPointerSet (right, result, ic);
8774       return;
8775     }
8776
8777   /* if the value is already in a pointer register
8778      then don't need anything more */
8779   if (!AOP_INPREG (AOP (result)))
8780     {
8781         if (
8782             //AOP_TYPE (result) == AOP_STK
8783             IS_AOP_PREG(result)
8784             )
8785         {
8786             // Aha, it is a pointer, just in disguise.
8787             rname = aopGet (AOP (result), 0, FALSE, FALSE);
8788             if (*rname != '@')
8789             {
8790                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8791                         __FILE__, __LINE__);
8792             }
8793             else
8794             {
8795                 // Expected case.
8796                 emitcode ("mov", "a%s,%s", rname + 1, rname);
8797                 rname++;  // skip the '@'.
8798             }
8799         }
8800         else
8801         {
8802             /* otherwise get a free pointer register */
8803             aop = newAsmop (0);
8804             preg = getFreePtr (ic, &aop, FALSE);
8805             emitcode ("mov", "%s,%s",
8806                       preg->name,
8807                       aopGet (AOP (result), 0, FALSE, TRUE));
8808             rname = preg->name;
8809         }
8810     }
8811     else
8812     {
8813         rname = aopGet (AOP (result), 0, FALSE, FALSE);
8814     }
8815
8816   aopOp (right, ic, FALSE);
8817
8818   /* if bitfield then unpack the bits */
8819   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8820     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
8821   else
8822     {
8823       /* we have can just get the values */
8824       int size = AOP_SIZE (right);
8825       int offset = 0;
8826
8827       while (size--)
8828         {
8829           l = aopGet (AOP (right), offset, FALSE, TRUE);
8830           if (*l == '@')
8831             {
8832               MOVA (l);
8833               emitcode ("mov", "@%s,a", rname);
8834             }
8835           else
8836             emitcode ("mov", "@%s,%s", rname, l);
8837           if (size || pi)
8838             emitcode ("inc", "%s", rname);
8839           offset++;
8840         }
8841     }
8842
8843   /* now some housekeeping stuff */
8844   if (aop) /* we had to allocate for this iCode */
8845     {
8846       if (pi)
8847         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8848       freeAsmop (NULL, aop, ic, TRUE);
8849     }
8850   else
8851     {
8852       /* we did not allocate which means left
8853          already in a pointer register, then
8854          if size > 0 && this could be used again
8855          we have to point it back to where it
8856          belongs */
8857       if ((AOP_SIZE (right) > 1 &&
8858            !OP_SYMBOL (result)->remat &&
8859            (OP_SYMBOL (result)->liveTo > ic->seq ||
8860             ic->depth)) &&
8861           !pi)
8862         {
8863           int size = AOP_SIZE (right) - 1;
8864           while (size--)
8865             emitcode ("dec", "%s", rname);
8866         }
8867     }
8868
8869   /* done */
8870   if (pi) pi->generated = 1;
8871   freeAsmop (result, NULL, ic, TRUE);
8872   freeAsmop (right, NULL, ic, TRUE);
8873 }
8874
8875 /*-----------------------------------------------------------------*/
8876 /* genPagedPointerSet - emitcode for Paged pointer put             */
8877 /*-----------------------------------------------------------------*/
8878 static void
8879 genPagedPointerSet (operand * right,
8880                     operand * result,
8881                     iCode * ic,
8882                     iCode * pi)
8883 {
8884   asmop *aop = NULL;
8885   regs *preg = NULL;
8886   char *rname, *l;
8887   sym_link *retype, *letype;
8888
8889   D(emitcode (";     genPagedPointerSet",""));
8890
8891   retype = getSpec (operandType (right));
8892   letype = getSpec (operandType (result));
8893
8894   aopOp (result, ic, FALSE);
8895
8896   /* if the value is already in a pointer register
8897      then don't need anything more */
8898   if (!AOP_INPREG (AOP (result)))
8899     {
8900       /* otherwise get a free pointer register */
8901       aop = newAsmop (0);
8902       preg = getFreePtr (ic, &aop, FALSE);
8903       emitcode ("mov", "%s,%s",
8904                 preg->name,
8905                 aopGet (AOP (result), 0, FALSE, TRUE));
8906       rname = preg->name;
8907     }
8908   else
8909     rname = aopGet (AOP (result), 0, FALSE, FALSE);
8910
8911   aopOp (right, ic, FALSE);
8912
8913   /* if bitfield then unpack the bits */
8914   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8915     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
8916   else
8917     {
8918       /* we have can just get the values */
8919       int size = AOP_SIZE (right);
8920       int offset = 0;
8921
8922       while (size--)
8923         {
8924           l = aopGet (AOP (right), offset, FALSE, TRUE);
8925
8926           MOVA (l);
8927           emitcode ("movx", "@%s,a", rname);
8928
8929           if (size || pi)
8930             emitcode ("inc", "%s", rname);
8931
8932           offset++;
8933         }
8934     }
8935
8936   /* now some housekeeping stuff */
8937   if (aop) /* we had to allocate for this iCode */
8938     {
8939       if (pi)
8940         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8941       freeAsmop (NULL, aop, ic, TRUE);
8942     }
8943   else
8944     {
8945       /* we did not allocate which means left
8946          already in a pointer register, then
8947          if size > 0 && this could be used again
8948          we have to point it back to where it
8949          belongs */
8950       if (AOP_SIZE (right) > 1 &&
8951           !OP_SYMBOL (result)->remat &&
8952           (OP_SYMBOL (result)->liveTo > ic->seq ||
8953            ic->depth))
8954         {
8955           int size = AOP_SIZE (right) - 1;
8956           while (size--)
8957             emitcode ("dec", "%s", rname);
8958         }
8959     }
8960
8961   /* done */
8962   if (pi) pi->generated = 1;
8963   freeAsmop (result, NULL, ic, TRUE);
8964   freeAsmop (right, NULL, ic, TRUE);
8965
8966
8967 }
8968
8969 /*-----------------------------------------------------------------*/
8970 /* genFarPointerSet - set value from far space                     */
8971 /*-----------------------------------------------------------------*/
8972 static void
8973 genFarPointerSet (operand * right,
8974                   operand * result, iCode * ic, iCode * pi)
8975 {
8976   int size, offset;
8977   sym_link *retype = getSpec (operandType (right));
8978   sym_link *letype = getSpec (operandType (result));
8979
8980   D(emitcode (";     genFarPointerSet",""));
8981
8982   aopOp (result, ic, FALSE);
8983   loadDptrFromOperand (result, FALSE);
8984
8985   /* so dptr know contains the address */
8986   aopOp (right, ic, FALSE);
8987
8988   /* if bit then unpack */
8989   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8990     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
8991   else
8992     {
8993       size = AOP_SIZE (right);
8994       offset = 0;
8995
8996       while (size--)
8997         {
8998           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
8999           MOVA (l);
9000           emitcode ("movx", "@dptr,a");
9001           if (size || pi)
9002             emitcode ("inc", "dptr");
9003         }
9004     }
9005   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9006     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9007     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9008     pi->generated=1;
9009   }
9010   freeAsmop (result, NULL, ic, TRUE);
9011   freeAsmop (right, NULL, ic, TRUE);
9012 }
9013
9014 /*-----------------------------------------------------------------*/
9015 /* genGenPointerSet - set value from generic pointer space         */
9016 /*-----------------------------------------------------------------*/
9017 static void
9018 genGenPointerSet (operand * right,
9019                   operand * result, iCode * ic, iCode * pi)
9020 {
9021   int size, offset;
9022   sym_link *retype = getSpec (operandType (right));
9023   sym_link *letype = getSpec (operandType (result));
9024
9025   D(emitcode (";     genGenPointerSet",""));
9026
9027   aopOp (result, ic, FALSE);
9028   loadDptrFromOperand (result, TRUE);
9029
9030   /* so dptr know contains the address */
9031   aopOp (right, ic, FALSE);
9032
9033   /* if bit then unpack */
9034   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9035     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9036   else
9037     {
9038       size = AOP_SIZE (right);
9039       offset = 0;
9040
9041       while (size--)
9042         {
9043           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9044           MOVA (l);
9045           emitcode ("lcall", "__gptrput");
9046           if (size || pi)
9047             emitcode ("inc", "dptr");
9048         }
9049     }
9050
9051   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9052     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9053     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9054     pi->generated=1;
9055   }
9056   freeAsmop (result, NULL, ic, TRUE);
9057   freeAsmop (right, NULL, ic, TRUE);
9058 }
9059
9060 /*-----------------------------------------------------------------*/
9061 /* genPointerSet - stores the value into a pointer location        */
9062 /*-----------------------------------------------------------------*/
9063 static void
9064 genPointerSet (iCode * ic, iCode *pi)
9065 {
9066   operand *right, *result;
9067   sym_link *type, *etype;
9068   int p_type;
9069
9070   D(emitcode (";     genPointerSet",""));
9071
9072   right = IC_RIGHT (ic);
9073   result = IC_RESULT (ic);
9074
9075   /* depending on the type of pointer we need to
9076      move it to the correct pointer register */
9077   type = operandType (result);
9078   etype = getSpec (type);
9079   /* if left is of type of pointer then it is simple */
9080   if (IS_PTR (type) && !IS_FUNC (type->next))
9081     {
9082       p_type = DCL_TYPE (type);
9083     }
9084   else
9085     {
9086       /* we have to go by the storage class */
9087       p_type = PTR_TYPE (SPEC_OCLS (etype));
9088     }
9089
9090   /* special case when cast remat */
9091   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9092       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9093           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9094           type = operandType (result);
9095           p_type = DCL_TYPE (type);
9096   }
9097   /* now that we have the pointer type we assign
9098      the pointer values */
9099   switch (p_type)
9100     {
9101
9102     case POINTER:
9103     case IPOINTER:
9104       genNearPointerSet (right, result, ic, pi);
9105       break;
9106
9107     case PPOINTER:
9108       genPagedPointerSet (right, result, ic, pi);
9109       break;
9110
9111     case FPOINTER:
9112       genFarPointerSet (right, result, ic, pi);
9113       break;
9114
9115     case GPOINTER:
9116       genGenPointerSet (right, result, ic, pi);
9117       break;
9118
9119     default:
9120       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9121               "genPointerSet: illegal pointer type");
9122     }
9123
9124 }
9125
9126 /*-----------------------------------------------------------------*/
9127 /* genIfx - generate code for Ifx statement                        */
9128 /*-----------------------------------------------------------------*/
9129 static void
9130 genIfx (iCode * ic, iCode * popIc)
9131 {
9132   operand *cond = IC_COND (ic);
9133   int isbit = 0;
9134
9135   D(emitcode (";     genIfx",""));
9136
9137   aopOp (cond, ic, FALSE);
9138
9139   /* get the value into acc */
9140   if (AOP_TYPE (cond) != AOP_CRY)
9141     toBoolean (cond);
9142   else
9143     isbit = 1;
9144   /* the result is now in the accumulator */
9145   freeAsmop (cond, NULL, ic, TRUE);
9146
9147   /* if there was something to be popped then do it */
9148   if (popIc)
9149     genIpop (popIc);
9150
9151   /* if the condition is  a bit variable */
9152   if (isbit && IS_ITEMP (cond) &&
9153       SPIL_LOC (cond))
9154     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9155   else if (isbit && !IS_ITEMP (cond))
9156     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9157   else
9158     genIfxJump (ic, "a", NULL, NULL, NULL);
9159
9160   ic->generated = 1;
9161 }
9162
9163 /*-----------------------------------------------------------------*/
9164 /* genAddrOf - generates code for address of                       */
9165 /*-----------------------------------------------------------------*/
9166 static void
9167 genAddrOf (iCode * ic)
9168 {
9169   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9170   int size, offset;
9171
9172   D(emitcode (";     genAddrOf",""));
9173
9174   aopOp (IC_RESULT (ic), ic, FALSE);
9175
9176   /* if the operand is on the stack then we
9177      need to get the stack offset of this
9178      variable */
9179   if (sym->onStack)
9180     {
9181       /* if it has an offset then we need to compute
9182          it */
9183       if (sym->stack)
9184         {
9185           emitcode ("mov", "a,_bp");
9186           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9187                                          ((char) (sym->stack - _G.nRegsSaved)) :
9188                                          ((char) sym->stack)) & 0xff);
9189           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9190         }
9191       else
9192         {
9193           /* we can just move _bp */
9194           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9195         }
9196       /* fill the result with zero */
9197       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9198
9199       offset = 1;
9200       while (size--)
9201         {
9202           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9203         }
9204
9205       goto release;
9206     }
9207
9208   /* object not on stack then we need the name */
9209   size = AOP_SIZE (IC_RESULT (ic));
9210   offset = 0;
9211
9212   while (size--)
9213     {
9214       char s[SDCC_NAME_MAX];
9215       if (offset)
9216         sprintf (s, "#(%s >> %d)",
9217                  sym->rname,
9218                  offset * 8);
9219       else
9220         sprintf (s, "#%s", sym->rname);
9221       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9222     }
9223
9224 release:
9225   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9226
9227 }
9228
9229 /*-----------------------------------------------------------------*/
9230 /* genFarFarAssign - assignment when both are in far space         */
9231 /*-----------------------------------------------------------------*/
9232 static void
9233 genFarFarAssign (operand * result, operand * right, iCode * ic)
9234 {
9235   int size = AOP_SIZE (right);
9236   int offset = 0;
9237   char *l;
9238
9239   D(emitcode (";     genFarFarAssign",""));
9240
9241   /* first push the right side on to the stack */
9242   while (size--)
9243     {
9244       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9245       MOVA (l);
9246       emitcode ("push", "acc");
9247     }
9248
9249   freeAsmop (right, NULL, ic, FALSE);
9250   /* now assign DPTR to result */
9251   aopOp (result, ic, FALSE);
9252   size = AOP_SIZE (result);
9253   while (size--)
9254     {
9255       emitcode ("pop", "acc");
9256       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9257     }
9258   freeAsmop (result, NULL, ic, FALSE);
9259
9260 }
9261
9262 /*-----------------------------------------------------------------*/
9263 /* genAssign - generate code for assignment                        */
9264 /*-----------------------------------------------------------------*/
9265 static void
9266 genAssign (iCode * ic)
9267 {
9268   operand *result, *right;
9269   int size, offset;
9270   unsigned long lit = 0L;
9271
9272   D(emitcode(";     genAssign",""));
9273
9274   result = IC_RESULT (ic);
9275   right = IC_RIGHT (ic);
9276
9277   /* if they are the same */
9278   if (operandsEqu (result, right) &&
9279       !isOperandVolatile (result, FALSE) &&
9280       !isOperandVolatile (right, FALSE))
9281     return;
9282
9283   aopOp (right, ic, FALSE);
9284
9285   /* special case both in far space */
9286   if (AOP_TYPE (right) == AOP_DPTR &&
9287       IS_TRUE_SYMOP (result) &&
9288       isOperandInFarSpace (result))
9289     {
9290
9291       genFarFarAssign (result, right, ic);
9292       return;
9293     }
9294
9295   aopOp (result, ic, TRUE);
9296
9297   /* if they are the same registers */
9298   if (sameRegs (AOP (right), AOP (result)) &&
9299       !isOperandVolatile (result, FALSE) &&
9300       !isOperandVolatile (right, FALSE))
9301     goto release;
9302
9303   /* if the result is a bit */
9304   if (AOP_TYPE (result) == AOP_CRY)
9305     {
9306
9307       /* if the right size is a literal then
9308          we know what the value is */
9309       if (AOP_TYPE (right) == AOP_LIT)
9310         {
9311           if (((int) operandLitValue (right)))
9312             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9313           else
9314             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9315           goto release;
9316         }
9317
9318       /* the right is also a bit variable */
9319       if (AOP_TYPE (right) == AOP_CRY)
9320         {
9321           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9322           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9323           goto release;
9324         }
9325
9326       /* we need to or */
9327       toBoolean (right);
9328       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9329       goto release;
9330     }
9331
9332   /* bit variables done */
9333   /* general case */
9334   size = AOP_SIZE (result);
9335   offset = 0;
9336   if (AOP_TYPE (right) == AOP_LIT)
9337     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9338   if ((size > 1) &&
9339       (AOP_TYPE (result) != AOP_REG) &&
9340       (AOP_TYPE (right) == AOP_LIT) &&
9341       !IS_FLOAT (operandType (right)) &&
9342       (lit < 256L))
9343     {
9344       emitcode ("clr", "a");
9345       while (size--)
9346         {
9347           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9348             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9349           else
9350             aopPut (AOP (result),
9351                     aopGet (AOP (right), size, FALSE, FALSE),
9352                     size,
9353                     isOperandVolatile (result, FALSE));
9354         }
9355     }
9356   else
9357     {
9358       while (size--)
9359         {
9360           aopPut (AOP (result),
9361                   aopGet (AOP (right), offset, FALSE, FALSE),
9362                   offset,
9363                   isOperandVolatile (result, FALSE));
9364           offset++;
9365         }
9366     }
9367
9368 release:
9369   freeAsmop (right, NULL, ic, TRUE);
9370   freeAsmop (result, NULL, ic, TRUE);
9371 }
9372
9373 /*-----------------------------------------------------------------*/
9374 /* genJumpTab - genrates code for jump table                       */
9375 /*-----------------------------------------------------------------*/
9376 static void
9377 genJumpTab (iCode * ic)
9378 {
9379   symbol *jtab;
9380   char *l;
9381
9382   D(emitcode (";     genJumpTab",""));
9383
9384   aopOp (IC_JTCOND (ic), ic, FALSE);
9385   /* get the condition into accumulator */
9386   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9387   MOVA (l);
9388   /* multiply by three */
9389   emitcode ("add", "a,acc");
9390   emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9391   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9392
9393   jtab = newiTempLabel (NULL);
9394   emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9395   emitcode ("jmp", "@a+dptr");
9396   emitcode ("", "%05d$:", jtab->key + 100);
9397   /* now generate the jump labels */
9398   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9399        jtab = setNextItem (IC_JTLABELS (ic)))
9400     emitcode ("ljmp", "%05d$", jtab->key + 100);
9401
9402 }
9403
9404 /*-----------------------------------------------------------------*/
9405 /* genCast - gen code for casting                                  */
9406 /*-----------------------------------------------------------------*/
9407 static void
9408 genCast (iCode * ic)
9409 {
9410   operand *result = IC_RESULT (ic);
9411   sym_link *ctype = operandType (IC_LEFT (ic));
9412   sym_link *rtype = operandType (IC_RIGHT (ic));
9413   operand *right = IC_RIGHT (ic);
9414   int size, offset;
9415
9416   D(emitcode(";     genCast",""));
9417
9418   /* if they are equivalent then do nothing */
9419   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9420     return;
9421
9422   aopOp (right, ic, FALSE);
9423   aopOp (result, ic, FALSE);
9424
9425   /* if the result is a bit (and not a bitfield) */
9426   // if (AOP_TYPE (result) == AOP_CRY)
9427   if (IS_BITVAR (OP_SYMBOL (result)->type)
9428       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9429     {
9430       /* if the right size is a literal then
9431          we know what the value is */
9432       if (AOP_TYPE (right) == AOP_LIT)
9433         {
9434           if (((int) operandLitValue (right)))
9435             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9436           else
9437             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9438
9439           goto release;
9440         }
9441
9442       /* the right is also a bit variable */
9443       if (AOP_TYPE (right) == AOP_CRY)
9444         {
9445           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9446           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9447           goto release;
9448         }
9449
9450       /* we need to or */
9451       toBoolean (right);
9452       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9453       goto release;
9454     }
9455
9456
9457   /* if they are the same size : or less */
9458   if (AOP_SIZE (result) <= AOP_SIZE (right))
9459     {
9460
9461       /* if they are in the same place */
9462       if (sameRegs (AOP (right), AOP (result)))
9463         goto release;
9464
9465       /* if they in different places then copy */
9466       size = AOP_SIZE (result);
9467       offset = 0;
9468       while (size--)
9469         {
9470           aopPut (AOP (result),
9471                   aopGet (AOP (right), offset, FALSE, FALSE),
9472                   offset,
9473                   isOperandVolatile (result, FALSE));
9474           offset++;
9475         }
9476       goto release;
9477     }
9478
9479
9480   /* if the result is of type pointer */
9481   if (IS_PTR (ctype))
9482     {
9483
9484       int p_type;
9485       sym_link *type = operandType (right);
9486       sym_link *etype = getSpec (type);
9487
9488       /* pointer to generic pointer */
9489       if (IS_GENPTR (ctype))
9490         {
9491           if (IS_PTR (type))
9492             p_type = DCL_TYPE (type);
9493           else
9494             {
9495               if (SPEC_SCLS(etype)==S_REGISTER) {
9496                 // let's assume it is a generic pointer
9497                 p_type=GPOINTER;
9498               } else {
9499                 /* we have to go by the storage class */
9500                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9501               }
9502             }
9503
9504           /* the first two bytes are known */
9505           size = GPTRSIZE - 1;
9506           offset = 0;
9507           while (size--)
9508             {
9509               aopPut (AOP (result),
9510                       aopGet (AOP (right), offset, FALSE, FALSE),
9511                       offset,
9512                       isOperandVolatile (result, FALSE));
9513               offset++;
9514             }
9515           /* the last byte depending on type */
9516             {
9517                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9518                 char gpValStr[10];
9519
9520                 if (gpVal == -1)
9521                 {
9522                     // pointerTypeToGPByte will have bitched.
9523                     exit(1);
9524                 }
9525
9526                 sprintf(gpValStr, "#0x%d", gpVal);
9527                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9528             }
9529           goto release;
9530         }
9531
9532       /* just copy the pointers */
9533       size = AOP_SIZE (result);
9534       offset = 0;
9535       while (size--)
9536         {
9537           aopPut (AOP (result),
9538                   aopGet (AOP (right), offset, FALSE, FALSE),
9539                   offset,
9540                   isOperandVolatile (result, FALSE));
9541           offset++;
9542         }
9543       goto release;
9544     }
9545
9546   /* so we now know that the size of destination is greater
9547      than the size of the source */
9548   /* we move to result for the size of source */
9549   size = AOP_SIZE (right);
9550   offset = 0;
9551   while (size--)
9552     {
9553       aopPut (AOP (result),
9554               aopGet (AOP (right), offset, FALSE, FALSE),
9555               offset,
9556               isOperandVolatile (result, FALSE));
9557       offset++;
9558     }
9559
9560   /* now depending on the sign of the source && destination */
9561   size = AOP_SIZE (result) - AOP_SIZE (right);
9562   /* if unsigned or not an integral type */
9563   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9564     {
9565       while (size--)
9566         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9567     }
9568   else
9569     {
9570       /* we need to extend the sign :{ */
9571       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9572                         FALSE, FALSE);
9573       MOVA (l);
9574       emitcode ("rlc", "a");
9575       emitcode ("subb", "a,acc");
9576       while (size--)
9577         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9578     }
9579
9580   /* we are done hurray !!!! */
9581
9582 release:
9583   freeAsmop (right, NULL, ic, TRUE);
9584   freeAsmop (result, NULL, ic, TRUE);
9585
9586 }
9587
9588 /*-----------------------------------------------------------------*/
9589 /* genDjnz - generate decrement & jump if not zero instrucion      */
9590 /*-----------------------------------------------------------------*/
9591 static int
9592 genDjnz (iCode * ic, iCode * ifx)
9593 {
9594   symbol *lbl, *lbl1;
9595   if (!ifx)
9596     return 0;
9597
9598   D(emitcode (";     genDjnz",""));
9599
9600   /* if the if condition has a false label
9601      then we cannot save */
9602   if (IC_FALSE (ifx))
9603     return 0;
9604
9605   /* if the minus is not of the form
9606      a = a - 1 */
9607   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9608       !IS_OP_LITERAL (IC_RIGHT (ic)))
9609     return 0;
9610
9611   if (operandLitValue (IC_RIGHT (ic)) != 1)
9612     return 0;
9613
9614   /* if the size of this greater than one then no
9615      saving */
9616   if (getSize (operandType (IC_RESULT (ic))) > 1)
9617     return 0;
9618
9619   /* otherwise we can save BIG */
9620   lbl = newiTempLabel (NULL);
9621   lbl1 = newiTempLabel (NULL);
9622
9623   aopOp (IC_RESULT (ic), ic, FALSE);
9624
9625   if (AOP_NEEDSACC(IC_RESULT(ic)))
9626   {
9627       /* If the result is accessed indirectly via
9628        * the accumulator, we must explicitly write
9629        * it back after the decrement.
9630        */
9631       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9632
9633       if (strcmp(rByte, "a"))
9634       {
9635            /* Something is hopelessly wrong */
9636            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9637                    __FILE__, __LINE__);
9638            /* We can just give up; the generated code will be inefficient,
9639             * but what the hey.
9640             */
9641            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9642            return 0;
9643       }
9644       emitcode ("dec", "%s", rByte);
9645       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9646       emitcode ("jnz", "%05d$", lbl->key + 100);
9647   }
9648   else if (IS_AOP_PREG (IC_RESULT (ic)))
9649     {
9650       emitcode ("dec", "%s",
9651                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9652       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9653       emitcode ("jnz", "%05d$", lbl->key + 100);
9654     }
9655   else
9656     {
9657       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9658                 lbl->key + 100);
9659     }
9660   emitcode ("sjmp", "%05d$", lbl1->key + 100);
9661   emitcode ("", "%05d$:", lbl->key + 100);
9662   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
9663   emitcode ("", "%05d$:", lbl1->key + 100);
9664
9665   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9666   ifx->generated = 1;
9667   return 1;
9668 }
9669
9670 /*-----------------------------------------------------------------*/
9671 /* genReceive - generate code for a receive iCode                  */
9672 /*-----------------------------------------------------------------*/
9673 static void
9674 genReceive (iCode * ic)
9675 {
9676     int size = getSize (operandType (IC_RESULT (ic)));
9677     int offset = 0;
9678   D(emitcode (";     genReceive",""));
9679
9680   if (ic->argreg == 1) { /* first parameter */
9681       if (isOperandInFarSpace (IC_RESULT (ic)) &&
9682           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
9683            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
9684
9685           regs *tempRegs[4];
9686           int receivingA = 0;
9687           int roffset = 0;
9688
9689           for (offset = 0; offset<size; offset++)
9690             if (!strcmp (fReturn[offset], "a"))
9691               receivingA = 1;
9692
9693           if (!receivingA)
9694             {
9695               if (size==1 || getTempRegs(tempRegs, size-1, ic))
9696                 {
9697                   for (offset = size-1; offset>0; offset--)
9698                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
9699                   emitcode("mov","a,%s", fReturn[0]);
9700                   _G.accInUse++;
9701                   aopOp (IC_RESULT (ic), ic, FALSE);
9702                   _G.accInUse--;
9703                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
9704                           isOperandVolatile (IC_RESULT (ic), FALSE));
9705                   for (offset = 1; offset<size; offset++)
9706                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
9707                             isOperandVolatile (IC_RESULT (ic), FALSE));
9708                   goto release;
9709                 }
9710             }
9711           else
9712             {
9713               if (getTempRegs(tempRegs, size, ic))
9714                 {
9715                   for (offset = 0; offset<size; offset++)
9716                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
9717                   aopOp (IC_RESULT (ic), ic, FALSE);
9718                   for (offset = 0; offset<size; offset++)
9719                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
9720                             isOperandVolatile (IC_RESULT (ic), FALSE));
9721                   goto release;
9722                 }
9723             }
9724
9725           offset = fReturnSizeMCS51 - size;
9726           while (size--) {
9727               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
9728                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
9729               offset++;
9730           }
9731           aopOp (IC_RESULT (ic), ic, FALSE);
9732           size = AOP_SIZE (IC_RESULT (ic));
9733           offset = 0;
9734           while (size--) {
9735               emitcode ("pop", "acc");
9736               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9737           }
9738
9739       } else {
9740           _G.accInUse++;
9741           aopOp (IC_RESULT (ic), ic, FALSE);
9742           _G.accInUse--;
9743           assignResultValue (IC_RESULT (ic));
9744       }
9745   } else { /* second receive onwards */
9746       int rb1off ;
9747       aopOp (IC_RESULT (ic), ic, FALSE);
9748       rb1off = ic->argreg;
9749       while (size--) {
9750           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9751       }
9752   }
9753
9754 release:
9755   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9756 }
9757
9758 /*-----------------------------------------------------------------*/
9759 /* genDummyRead - generate code for dummy read of volatiles        */
9760 /*-----------------------------------------------------------------*/
9761 static void
9762 genDummyRead (iCode * ic)
9763 {
9764   operand *op;
9765   int size, offset;
9766
9767   D(emitcode(";     genDummyRead",""));
9768
9769   op = IC_RIGHT (ic);
9770   if (op && IS_SYMOP (op))
9771     {
9772       aopOp (op, ic, FALSE);
9773
9774       /* if the result is a bit */
9775       if (AOP_TYPE (op) == AOP_CRY)
9776         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9777       else
9778         {
9779           /* bit variables done */
9780           /* general case */
9781           size = AOP_SIZE (op);
9782           offset = 0;
9783           while (size--)
9784           {
9785             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9786             offset++;
9787           }
9788         }
9789
9790       freeAsmop (op, NULL, ic, TRUE);
9791     }
9792
9793   op = IC_LEFT (ic);
9794   if (op && IS_SYMOP (op))
9795     {
9796       aopOp (op, ic, FALSE);
9797
9798       /* if the result is a bit */
9799       if (AOP_TYPE (op) == AOP_CRY)
9800         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9801       else
9802         {
9803           /* bit variables done */
9804           /* general case */
9805           size = AOP_SIZE (op);
9806           offset = 0;
9807           while (size--)
9808           {
9809             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9810             offset++;
9811           }
9812         }
9813
9814       freeAsmop (op, NULL, ic, TRUE);
9815     }
9816 }
9817
9818 /*-----------------------------------------------------------------*/
9819 /* genCritical - generate code for start of a critical sequence    */
9820 /*-----------------------------------------------------------------*/
9821 static void
9822 genCritical (iCode *ic)
9823 {
9824   symbol *tlbl = newiTempLabel (NULL);
9825
9826   D(emitcode(";     genCritical",""));
9827
9828   if (IC_RESULT (ic))
9829     aopOp (IC_RESULT (ic), ic, TRUE);
9830
9831   emitcode ("setb", "c");
9832   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
9833   emitcode ("clr", "c");
9834   emitcode ("", "%05d$:", (tlbl->key + 100));
9835
9836   if (IC_RESULT (ic))
9837     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
9838   else
9839     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
9840
9841   if (IC_RESULT (ic))
9842     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9843 }
9844
9845 /*-----------------------------------------------------------------*/
9846 /* genEndCritical - generate code for end of a critical sequence   */
9847 /*-----------------------------------------------------------------*/
9848 static void
9849 genEndCritical (iCode *ic)
9850 {
9851   D(emitcode(";     genEndCritical",""));
9852
9853   if (IC_RIGHT (ic))
9854     {
9855       aopOp (IC_RIGHT (ic), ic, FALSE);
9856       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
9857         {
9858           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
9859           emitcode ("mov", "ea,c");
9860         }
9861       else
9862         {
9863           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
9864           emitcode ("rrc", "a");
9865           emitcode ("mov", "ea,c");
9866         }
9867       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
9868     }
9869   else
9870     {
9871       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
9872       emitcode ("mov", "ea,c");
9873     }
9874 }
9875
9876 /*-----------------------------------------------------------------*/
9877 /* gen51Code - generate code for 8051 based controllers            */
9878 /*-----------------------------------------------------------------*/
9879 void
9880 gen51Code (iCode * lic)
9881 {
9882   iCode *ic;
9883   int cln = 0;
9884   /* int cseq = 0; */
9885
9886   _G.currentFunc = NULL;
9887   lineHead = lineCurr = NULL;
9888
9889   /* print the allocation information */
9890   if (allocInfo && currFunc)
9891     printAllocInfo (currFunc, codeOutFile);
9892   /* if debug information required */
9893   if (options.debug && currFunc)
9894     {
9895       debugFile->writeFunction(currFunc);
9896       _G.debugLine = 1;
9897       if (IS_STATIC (currFunc->etype))
9898         emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
9899       else
9900         emitcode ("", "G$%s$0$0 ==.", currFunc->name);
9901       _G.debugLine = 0;
9902     }
9903   /* stack pointer name */
9904   if (options.useXstack)
9905     spname = "_spx";
9906   else
9907     spname = "sp";
9908
9909
9910   for (ic = lic; ic; ic = ic->next)
9911     {
9912       _G.current_iCode = ic;
9913
9914       if (ic->lineno && cln != ic->lineno)
9915         {
9916           if (options.debug)
9917             {
9918               _G.debugLine = 1;
9919               emitcode ("", "C$%s$%d$%d$%d ==.",
9920                         FileBaseName (ic->filename), ic->lineno,
9921                         ic->level, ic->block);
9922               _G.debugLine = 0;
9923             }
9924           if (!options.noCcodeInAsm) {
9925             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
9926                       printCLine(ic->filename, ic->lineno));
9927           }
9928           cln = ic->lineno;
9929         }
9930       #if 0
9931       if (ic->seqPoint && ic->seqPoint != cseq)
9932         {
9933           emitcode ("", "; sequence point %d", ic->seqPoint);
9934           cseq = ic->seqPoint;
9935         }
9936       #endif
9937       if (options.iCodeInAsm) {
9938         char regsInUse[80];
9939         int i;
9940
9941         for (i=0; i<8; i++) {
9942           sprintf (&regsInUse[i],
9943                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
9944         }
9945         regsInUse[i]=0;
9946         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
9947       }
9948       /* if the result is marked as
9949          spilt and rematerializable or code for
9950          this has already been generated then
9951          do nothing */
9952       if (resultRemat (ic) || ic->generated)
9953         continue;
9954
9955       /* depending on the operation */
9956       switch (ic->op)
9957         {
9958         case '!':
9959           genNot (ic);
9960           break;
9961
9962         case '~':
9963           genCpl (ic);
9964           break;
9965
9966         case UNARYMINUS:
9967           genUminus (ic);
9968           break;
9969
9970         case IPUSH:
9971           genIpush (ic);
9972           break;
9973
9974         case IPOP:
9975           /* IPOP happens only when trying to restore a
9976              spilt live range, if there is an ifx statement
9977              following this pop then the if statement might
9978              be using some of the registers being popped which
9979              would destory the contents of the register so
9980              we need to check for this condition and handle it */
9981           if (ic->next &&
9982               ic->next->op == IFX &&
9983               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
9984             genIfx (ic->next, ic);
9985           else
9986             genIpop (ic);
9987           break;
9988
9989         case CALL:
9990           genCall (ic);
9991           break;
9992
9993         case PCALL:
9994           genPcall (ic);
9995           break;
9996
9997         case FUNCTION:
9998           genFunction (ic);
9999           break;
10000
10001         case ENDFUNCTION:
10002           genEndFunction (ic);
10003           break;
10004
10005         case RETURN:
10006           genRet (ic);
10007           break;
10008
10009         case LABEL:
10010           genLabel (ic);
10011           break;
10012
10013         case GOTO:
10014           genGoto (ic);
10015           break;
10016
10017         case '+':
10018           genPlus (ic);
10019           break;
10020
10021         case '-':
10022           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10023             genMinus (ic);
10024           break;
10025
10026         case '*':
10027           genMult (ic);
10028           break;
10029
10030         case '/':
10031           genDiv (ic);
10032           break;
10033
10034         case '%':
10035           genMod (ic);
10036           break;
10037
10038         case '>':
10039           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10040           break;
10041
10042         case '<':
10043           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10044           break;
10045
10046         case LE_OP:
10047         case GE_OP:
10048         case NE_OP:
10049
10050           /* note these two are xlated by algebraic equivalence
10051              during parsing SDCC.y */
10052           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10053                   "got '>=' or '<=' shouldn't have come here");
10054           break;
10055
10056         case EQ_OP:
10057           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10058           break;
10059
10060         case AND_OP:
10061           genAndOp (ic);
10062           break;
10063
10064         case OR_OP:
10065           genOrOp (ic);
10066           break;
10067
10068         case '^':
10069           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10070           break;
10071
10072         case '|':
10073           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10074           break;
10075
10076         case BITWISEAND:
10077           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10078           break;
10079
10080         case INLINEASM:
10081           genInline (ic);
10082           break;
10083
10084         case RRC:
10085           genRRC (ic);
10086           break;
10087
10088         case RLC:
10089           genRLC (ic);
10090           break;
10091
10092         case GETHBIT:
10093           genGetHbit (ic);
10094           break;
10095
10096         case LEFT_OP:
10097           genLeftShift (ic);
10098           break;
10099
10100         case RIGHT_OP:
10101           genRightShift (ic);
10102           break;
10103
10104         case GET_VALUE_AT_ADDRESS:
10105           genPointerGet (ic, hasInc(IC_LEFT(ic),ic,getSize(operandType(IC_RESULT(ic)))));
10106           break;
10107
10108         case '=':
10109           if (POINTER_SET (ic))
10110             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10111           else
10112             genAssign (ic);
10113           break;
10114
10115         case IFX:
10116           genIfx (ic, NULL);
10117           break;
10118
10119         case ADDRESS_OF:
10120           genAddrOf (ic);
10121           break;
10122
10123         case JUMPTABLE:
10124           genJumpTab (ic);
10125           break;
10126
10127         case CAST:
10128           genCast (ic);
10129           break;
10130
10131         case RECEIVE:
10132           genReceive (ic);
10133           break;
10134
10135         case SEND:
10136           addSet (&_G.sendSet, ic);
10137           break;
10138
10139         case DUMMY_READ_VOLATILE:
10140           genDummyRead (ic);
10141           break;
10142
10143         case CRITICAL:
10144           genCritical (ic);
10145           break;
10146
10147         case ENDCRITICAL:
10148           genEndCritical (ic);
10149           break;
10150
10151         case SWAP:
10152           genSwap (ic);
10153           break;
10154
10155         default:
10156           ic = ic;
10157         }
10158     }
10159
10160   _G.current_iCode = NULL;
10161
10162   /* now we are ready to call the
10163      peep hole optimizer */
10164   if (!options.nopeep)
10165     peepHole (&lineHead);
10166
10167   /* now do the actual printing */
10168   printLine (lineHead, codeOutFile);
10169   return;
10170 }