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