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