* src/mcs51/gen.c (pushSide, genSignedRightShift, genDjnz, geniPush):
[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           MOVA (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           MOVA (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 = OP_SYMBOL (IC_LEFT (ic));
2365   sym_link *ftype;
2366   bool   switchedPSW = FALSE;
2367   int calleesaves_saved_register = -1;
2368   int stackAdjust = sym->stack;
2369   int accIsFree = sym->recvSize < 4;
2370   iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2371
2372   _G.nRegsSaved = 0;
2373   /* create the function header */
2374   emitcode (";", "-----------------------------------------");
2375   emitcode (";", " function %s", sym->name);
2376   emitcode (";", "-----------------------------------------");
2377
2378   emitcode ("", "%s:", sym->rname);
2379   ftype = operandType (IC_LEFT (ic));
2380   _G.currentFunc = sym;
2381
2382   if (IFFUNC_ISNAKED(ftype))
2383   {
2384       emitcode(";", "naked function: no prologue.");
2385       return;
2386   }
2387   
2388   /* here we need to generate the equates for the
2389      register bank if required */
2390   if (FUNC_REGBANK (ftype) != rbank)
2391     {
2392       int i;
2393
2394       rbank = FUNC_REGBANK (ftype);
2395       for (i = 0; i < mcs51_nRegs; i++)
2396         {
2397           if (strcmp (regs8051[i].base, "0") == 0)
2398             emitcode ("", "%s = 0x%02x",
2399                       regs8051[i].dname,
2400                       8 * rbank + regs8051[i].offset);
2401           else
2402             emitcode ("", "%s = %s + 0x%02x",
2403                       regs8051[i].dname,
2404                       regs8051[i].base,
2405                       8 * rbank + regs8051[i].offset);
2406         }
2407     }
2408
2409   /* if this is an interrupt service routine then
2410      save acc, b, dpl, dph  */
2411   if (IFFUNC_ISISR (sym->type))
2412     {
2413
2414       if (!inExcludeList ("acc"))
2415         emitcode ("push", "acc");
2416       if (!inExcludeList ("b"))
2417         emitcode ("push", "b");
2418       if (!inExcludeList ("dpl"))
2419         emitcode ("push", "dpl");
2420       if (!inExcludeList ("dph"))
2421         emitcode ("push", "dph");
2422       /* if this isr has no bank i.e. is going to
2423          run with bank 0 , then we need to save more
2424          registers :-) */
2425       if (!FUNC_REGBANK (sym->type))
2426         {
2427
2428           /* if this function does not call any other
2429              function then we can be economical and
2430              save only those registers that are used */
2431           if (!IFFUNC_HASFCALL(sym->type))
2432             {
2433               int i;
2434
2435               /* if any registers used */
2436               if (sym->regsUsed)
2437                 {
2438                   /* save the registers used */
2439                   for (i = 0; i < sym->regsUsed->size; i++)
2440                     {
2441                       if (bitVectBitValue (sym->regsUsed, i))
2442                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2443                     }
2444                 }
2445             }
2446           else
2447             {
2448
2449               /* this function has a function call. We cannot
2450                  determines register usage so we will have to push the
2451                  entire bank */
2452                 saveRBank (0, ic, FALSE);
2453                 if (options.parms_in_bank1) {
2454                     int i;
2455                     for (i=0; i < 8 ; i++ ) {
2456                         emitcode ("push","%s",rb1regs[i]);
2457                     }
2458                 }
2459             }
2460         }
2461         else
2462         {
2463             /* This ISR uses a non-zero bank.
2464              *
2465              * We assume that the bank is available for our
2466              * exclusive use.
2467              *
2468              * However, if this ISR calls a function which uses some
2469              * other bank, we must save that bank entirely.
2470              */
2471             unsigned long banksToSave = 0;
2472
2473             if (IFFUNC_HASFCALL(sym->type))
2474             {
2475
2476 #define MAX_REGISTER_BANKS 4
2477
2478                 iCode *i;
2479                 int ix;
2480
2481                 for (i = ic; i; i = i->next)
2482                 {
2483                     if (i->op == ENDFUNCTION)
2484                     {
2485                         /* we got to the end OK. */
2486                         break;
2487                     }
2488
2489                     if (i->op == CALL)
2490                     {
2491                         sym_link *dtype;
2492
2493                         dtype = operandType (IC_LEFT(i));
2494                         if (dtype
2495                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2496                         {
2497                              /* Mark this bank for saving. */
2498                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2499                              {
2500                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2501                              }
2502                              else
2503                              {
2504                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2505                              }
2506
2507                              /* And note that we don't need to do it in
2508                               * genCall.
2509                               */
2510                              i->bankSaved = 1;
2511                         }
2512                     }
2513                     if (i->op == PCALL)
2514                     {
2515                         /* This is a mess; we have no idea what
2516                          * register bank the called function might
2517                          * use.
2518                          *
2519                          * The only thing I can think of to do is
2520                          * throw a warning and hope.
2521                          */
2522                         werror(W_FUNCPTR_IN_USING_ISR);
2523                     }
2524                 }
2525
2526                 if (banksToSave && options.useXstack)
2527                 {
2528                     /* Since we aren't passing it an ic,
2529                      * saveRBank will assume r0 is available to abuse.
2530                      *
2531                      * So switch to our (trashable) bank now, so
2532                      * the caller's R0 isn't trashed.
2533                      */
2534                     emitcode ("push", "psw");
2535                     emitcode ("mov", "psw,#0x%02x",
2536                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2537                     switchedPSW = TRUE;
2538                 }
2539
2540                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2541                 {
2542                      if (banksToSave & (1 << ix))
2543                      {
2544                          saveRBank(ix, NULL, FALSE);
2545                      }
2546                 }
2547             }
2548             // TODO: this needs a closer look
2549             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2550         }
2551       
2552       /* Set the register bank to the desired value if nothing else */
2553       /* has done so yet. */
2554       if (!switchedPSW)
2555         {
2556           emitcode ("push", "psw");
2557           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2558         }
2559     }
2560   else
2561     {
2562       /* This is a non-ISR function. The caller has already switched register */
2563       /* banks, if necessary, so just handle the callee-saves option. */
2564       
2565       /* if callee-save to be used for this function
2566          then save the registers being used in this function */
2567       if (IFFUNC_CALLEESAVES(sym->type))
2568         {
2569           int i;
2570
2571           /* if any registers used */
2572           if (sym->regsUsed)
2573             {
2574               /* save the registers used */
2575               for (i = 0; i < sym->regsUsed->size; i++)
2576                 {
2577                   if (bitVectBitValue (sym->regsUsed, i))
2578                     {
2579                       /* remember one saved register for later usage */
2580                       if (calleesaves_saved_register < 0)
2581                         calleesaves_saved_register = i;
2582                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2583                       _G.nRegsSaved++;
2584                     }
2585                 }
2586             }
2587         }
2588     }
2589
2590
2591   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2592     {
2593
2594       if (options.useXstack)
2595         {
2596           if (!accIsFree)
2597             emitcode ("push", "acc");
2598           emitcode ("mov", "r0,%s", spname);
2599           emitcode ("mov", "a,_bp");
2600           emitcode ("movx", "@r0,a");
2601           emitcode ("inc", "%s", spname);
2602           if (!accIsFree)
2603             emitcode ("pop", "acc");
2604         }
2605       else
2606         {
2607           /* set up the stack */
2608           emitcode ("push", "_bp");     /* save the callers stack  */
2609         }
2610       emitcode ("mov", "_bp,%s", spname);
2611     }
2612   
2613   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2614   /* before setting up the stack frame completely. */
2615   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2616     {
2617       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2618       
2619       if (rsym->isitmp)
2620         {
2621           if (rsym && rsym->regType == REG_CND)
2622             rsym = NULL;
2623           if (rsym && (rsym->accuse || rsym->ruonly))
2624             rsym = NULL;
2625           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2626             rsym = rsym->usl.spillLoc;
2627         }
2628       
2629       /* If the RECEIVE operand immediately spills to the first entry on the */
2630       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2631       /* rather than the usual @r0/r1 machinations. */
2632       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2633         {
2634           int ofs;
2635           
2636           _G.current_iCode = ric;
2637           D(emitcode (";     genReceive",""));
2638           for (ofs=0; ofs < sym->recvSize; ofs++)
2639             {
2640               if (!strcmp (fReturn[ofs], "a"))
2641                 emitcode ("push", "acc");
2642               else
2643                 emitcode ("push", fReturn[ofs]);
2644             }
2645           stackAdjust -= sym->recvSize;
2646           if (stackAdjust<0)
2647             {
2648               assert (stackAdjust>=0);
2649               stackAdjust = 0;
2650             }
2651           _G.current_iCode = ic;
2652           ric->generated = 1;
2653           accIsFree = 1;
2654         }
2655       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2656       /* to free up the accumulator. */
2657       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2658         {
2659           int ofs;
2660           
2661           _G.current_iCode = ric;
2662           D(emitcode (";     genReceive",""));
2663           for (ofs=0; ofs < sym->recvSize; ofs++)
2664             {
2665               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2666             }
2667           _G.current_iCode = ic;
2668           ric->generated = 1;
2669           accIsFree = 1;
2670         }
2671     }
2672   
2673   /* adjust the stack for the function */
2674   if (stackAdjust)
2675     {
2676
2677       int i = stackAdjust;
2678       if (i > 256)
2679         werror (W_STACK_OVERFLOW, sym->name);
2680
2681       if (i > 3 && accIsFree)
2682         {
2683
2684           emitcode ("mov", "a,sp");
2685           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2686           emitcode ("mov", "sp,a");
2687
2688         }
2689       else if (i > 5)
2690         {
2691           /* The accumulator is not free, so we will need another register */
2692           /* to clobber. No need to worry about a possible conflict with */
2693           /* the above early RECEIVE optimizations since they would have */
2694           /* freed the accumulator if they were generated. */
2695           
2696           if (IFFUNC_CALLEESAVES(sym->type))
2697             {
2698               /* if it's a callee-saves function we need a saved register */
2699               if (calleesaves_saved_register >= 0)
2700                 {
2701                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2702                   emitcode ("mov", "a,sp");
2703                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2704                   emitcode ("mov", "sp,a");
2705                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2706                 }
2707               else
2708                 /* do it the hard way */
2709                 while (i--)
2710                   emitcode ("inc", "sp");
2711             }
2712           else
2713             {
2714               /* not callee-saves, we can clobber r0 */
2715               emitcode ("mov", "r0,a");
2716               emitcode ("mov", "a,sp");
2717               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2718               emitcode ("mov", "sp,a");
2719               emitcode ("mov", "a,r0");
2720             }
2721         }
2722       else
2723         while (i--)
2724           emitcode ("inc", "sp");
2725     }
2726
2727   if (sym->xstack)
2728     {
2729
2730       if (!accIsFree)
2731         emitcode ("push", "acc");
2732       emitcode ("mov", "a,_spx");
2733       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
2734       emitcode ("mov", "_spx,a");
2735       if (!accIsFree)
2736         emitcode ("pop", "acc");
2737     }
2738
2739   /* if critical function then turn interrupts off */
2740   if (IFFUNC_ISCRITICAL (ftype))
2741     {
2742       symbol *tlbl = newiTempLabel (NULL);
2743       emitcode ("setb", "c");
2744       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2745       emitcode ("clr", "c");
2746       emitcode ("", "%05d$:", (tlbl->key + 100));
2747       emitcode ("push", "psw"); /* save old ea via c in psw */
2748     }
2749 }
2750
2751 /*-----------------------------------------------------------------*/
2752 /* genEndFunction - generates epilogue for functions               */
2753 /*-----------------------------------------------------------------*/
2754 static void
2755 genEndFunction (iCode * ic)
2756 {
2757   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2758   lineNode *lnp = lineCurr;
2759   bitVect *regsUsed;
2760   bitVect *regsUsedPrologue;
2761   bitVect *regsUnneeded;
2762   int idx;
2763   
2764   _G.currentFunc = NULL;
2765   if (IFFUNC_ISNAKED(sym->type))
2766   {
2767       emitcode(";", "naked function: no epilogue.");
2768       return;
2769   }
2770
2771   if (IFFUNC_ISCRITICAL (sym->type))
2772     {
2773       emitcode ("pop", "psw"); /* restore ea via c in psw */
2774       emitcode ("mov", "ea,c");
2775     }
2776
2777   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2778     {
2779       emitcode ("mov", "%s,_bp", spname);
2780     }
2781
2782   /* if use external stack but some variables were
2783      added to the local stack then decrement the
2784      local stack */
2785   if (options.useXstack && sym->stack)
2786     {
2787       emitcode ("mov", "a,sp");
2788       emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
2789       emitcode ("mov", "sp,a");
2790     }
2791
2792
2793   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
2794     {
2795       if (options.useXstack)
2796         {
2797           emitcode ("mov", "r0,%s", spname);
2798           emitcode ("movx", "a,@r0");
2799           emitcode ("mov", "_bp,a");
2800           emitcode ("dec", "%s", spname);
2801         }
2802       else
2803         {
2804           emitcode ("pop", "_bp");
2805         }
2806     }
2807
2808   /* restore the register bank  */
2809   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
2810   {
2811     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
2812      || !options.useXstack)
2813     {
2814         /* Special case of ISR using non-zero bank with useXstack
2815          * is handled below.
2816          */
2817         emitcode ("pop", "psw");
2818     }
2819   }
2820
2821   if (IFFUNC_ISISR (sym->type))
2822     {
2823
2824       /* now we need to restore the registers */
2825       /* if this isr has no bank i.e. is going to
2826          run with bank 0 , then we need to save more
2827          registers :-) */
2828       if (!FUNC_REGBANK (sym->type))
2829         {
2830           /* if this function does not call any other
2831              function then we can be economical and
2832              save only those registers that are used */
2833           if (!IFFUNC_HASFCALL(sym->type))
2834             {
2835               int i;
2836
2837               /* if any registers used */
2838               if (sym->regsUsed)
2839                 {
2840                   /* save the registers used */
2841                   for (i = sym->regsUsed->size; i >= 0; i--)
2842                     {
2843                       if (bitVectBitValue (sym->regsUsed, i))
2844                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2845                     }
2846                 }
2847             }
2848           else
2849             {
2850               if (options.parms_in_bank1) {
2851                   int i;
2852                   for (i = 7 ; i >= 0 ; i-- ) {
2853                       emitcode ("pop","%s",rb1regs[i]);
2854                   }
2855               }
2856               /* this function has  a function call cannot
2857                  determines register usage so we will have to pop the
2858                  entire bank */
2859               unsaveRBank (0, ic, FALSE);
2860             }
2861         }
2862         else
2863         {
2864             /* This ISR uses a non-zero bank.
2865              *
2866              * Restore any register banks saved by genFunction
2867              * in reverse order.
2868              */
2869             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
2870             int ix;
2871
2872             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
2873             {
2874                 if (savedBanks & (1 << ix))
2875                 {
2876                     unsaveRBank(ix, NULL, FALSE);
2877                 }
2878             }
2879
2880             if (options.useXstack)
2881             {
2882                 /* Restore bank AFTER calling unsaveRBank,
2883                  * since it can trash r0.
2884                  */
2885                 emitcode ("pop", "psw");
2886             }
2887         }
2888
2889       if (!inExcludeList ("dph"))
2890         emitcode ("pop", "dph");
2891       if (!inExcludeList ("dpl"))
2892         emitcode ("pop", "dpl");
2893       if (!inExcludeList ("b"))
2894         emitcode ("pop", "b");
2895       if (!inExcludeList ("acc"))
2896         emitcode ("pop", "acc");
2897
2898       /* if debug then send end of function */
2899       if (options.debug && currFunc)
2900         {
2901           _G.debugLine = 1;
2902           emitcode ("", "C$%s$%d$%d$%d ==.",
2903                     FileBaseName (ic->filename), currFunc->lastLine,
2904                     ic->level, ic->block);
2905           if (IS_STATIC (currFunc->etype))
2906             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
2907           else
2908             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
2909           _G.debugLine = 0;
2910         }
2911
2912       emitcode ("reti", "");
2913     }
2914   else
2915     {
2916       if (IFFUNC_CALLEESAVES(sym->type))
2917         {
2918           int i;
2919
2920           /* if any registers used */
2921           if (sym->regsUsed)
2922             {
2923               /* save the registers used */
2924               for (i = sym->regsUsed->size; i >= 0; i--)
2925                 {
2926                   if (bitVectBitValue (sym->regsUsed, i) ||
2927                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
2928                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2929                 }
2930             }
2931           else if (mcs51_ptrRegReq)
2932             {
2933               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
2934               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2935             }
2936
2937         }
2938
2939       /* if debug then send end of function */
2940       if (options.debug && currFunc)
2941         {
2942           _G.debugLine = 1;
2943           emitcode ("", "C$%s$%d$%d$%d ==.",
2944                     FileBaseName (ic->filename), currFunc->lastLine,
2945                     ic->level, ic->block);
2946           if (IS_STATIC (currFunc->etype))
2947             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
2948           else
2949             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
2950           _G.debugLine = 0;
2951         }
2952
2953       emitcode ("ret", "");
2954     }
2955
2956   if (!port->peep.getRegsRead || !port->peep.getRegsWritten)
2957     return;
2958   
2959   /* If this was an interrupt handler using bank 0 that called another */
2960   /* function, then all registers must be saved; nothing to optimized. */
2961   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
2962       && !FUNC_REGBANK(sym->type))
2963     return;
2964
2965   /* There are no push/pops to optimize if not callee-saves or ISR */
2966   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
2967     return;
2968   
2969   /* If there were stack parameters, we cannot optimize without also    */
2970   /* fixing all of the stack offsets; this is too dificult to consider. */
2971   if (FUNC_HASSTACKPARM(sym->type))
2972     return;
2973     
2974   /* Compute the registers actually used */
2975   regsUsed = newBitVect (mcs51_nRegs);
2976   regsUsedPrologue = newBitVect (mcs51_nRegs);
2977   while (lnp)
2978     {
2979       if (lnp->ic && lnp->ic->op == FUNCTION)
2980         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
2981       else
2982         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
2983       
2984       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
2985           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
2986         break;
2987       if (!lnp->prev)
2988         break;
2989       lnp = lnp->prev;
2990     }
2991
2992   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
2993       && !bitVectBitValue (regsUsed, CND_IDX))
2994     {
2995       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
2996       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK(sym->type)
2997           && !sym->stack)
2998         bitVectUnSetBit (regsUsed, CND_IDX);
2999     }
3000   else
3001     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3002     
3003   /* If this was an interrupt handler that called another function */
3004   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3005   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3006     {
3007       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3008       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3009       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3010       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3011       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3012     }
3013
3014   /* Remove the unneeded push/pops */
3015   regsUnneeded = newBitVect (mcs51_nRegs);
3016   while (lnp)
3017     {
3018       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3019         {
3020           if (!strncmp(lnp->line, "push", 4))
3021             {
3022               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3023               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3024                 {
3025                   connectLine (lnp->prev, lnp->next);
3026                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3027                 }
3028             }
3029           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3030             {
3031               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3032               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3033                 {
3034                   connectLine (lnp->prev, lnp->next);
3035                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3036                 }
3037             }
3038         }
3039       lnp = lnp->next;
3040     }  
3041   
3042   for (idx = 0; idx < regsUnneeded->size; idx++)
3043     if (bitVectBitValue (regsUnneeded, idx))
3044       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3045   
3046   freeBitVect (regsUnneeded);
3047   freeBitVect (regsUsed);
3048   freeBitVect (regsUsedPrologue);
3049 }
3050
3051 /*-----------------------------------------------------------------*/
3052 /* genRet - generate code for return statement                     */
3053 /*-----------------------------------------------------------------*/
3054 static void
3055 genRet (iCode * ic)
3056 {
3057   int size, offset = 0, pushed = 0;
3058
3059   D(emitcode (";     genRet",""));
3060
3061   /* if we have no return value then
3062      just generate the "ret" */
3063   if (!IC_LEFT (ic))
3064     goto jumpret;
3065
3066   /* we have something to return then
3067      move the return value into place */
3068   aopOp (IC_LEFT (ic), ic, FALSE);
3069   size = AOP_SIZE (IC_LEFT (ic));
3070
3071   while (size--)
3072     {
3073       char *l;
3074       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3075         {
3076           /* #NOCHANGE */
3077           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3078                       FALSE, TRUE);
3079           emitcode ("push", "%s", l);
3080           pushed++;
3081         }
3082       else
3083         {
3084           l = aopGet (AOP (IC_LEFT (ic)), offset,
3085                       FALSE, FALSE);
3086           if (strcmp (fReturn[offset], l))
3087             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3088         }
3089     }
3090
3091   if (pushed)
3092     {
3093       while (pushed)
3094         {
3095           pushed--;
3096           if (strcmp (fReturn[pushed], "a"))
3097             emitcode ("pop", fReturn[pushed]);
3098           else
3099             emitcode ("pop", "acc");
3100         }
3101     }
3102   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3103
3104 jumpret:
3105   /* generate a jump to the return label
3106      if the next is not the return statement */
3107   if (!(ic->next && ic->next->op == LABEL &&
3108         IC_LABEL (ic->next) == returnLabel))
3109
3110     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3111
3112 }
3113
3114 /*-----------------------------------------------------------------*/
3115 /* genLabel - generates a label                                    */
3116 /*-----------------------------------------------------------------*/
3117 static void
3118 genLabel (iCode * ic)
3119 {
3120   /* special case never generate */
3121   if (IC_LABEL (ic) == entryLabel)
3122     return;
3123
3124   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3125 }
3126
3127 /*-----------------------------------------------------------------*/
3128 /* genGoto - generates a ljmp                                      */
3129 /*-----------------------------------------------------------------*/
3130 static void
3131 genGoto (iCode * ic)
3132 {
3133   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3134 }
3135
3136 /*-----------------------------------------------------------------*/
3137 /* findLabelBackwards: walks back through the iCode chain looking  */
3138 /* for the given label. Returns number of iCode instructions     */
3139 /* between that label and given ic.          */
3140 /* Returns zero if label not found.          */
3141 /*-----------------------------------------------------------------*/
3142 static int
3143 findLabelBackwards (iCode * ic, int key)
3144 {
3145   int count = 0;
3146
3147   while (ic->prev)
3148     {
3149       ic = ic->prev;
3150       count++;
3151
3152       /* If we have any pushes or pops, we cannot predict the distance.
3153          I don't like this at all, this should be dealt with in the
3154          back-end */
3155       if (ic->op == IPUSH || ic->op == IPOP) {
3156         return 0;
3157       }
3158
3159       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3160         {
3161           return count;
3162         }
3163     }
3164
3165   return 0;
3166 }
3167
3168 /*-----------------------------------------------------------------*/
3169 /* genPlusIncr :- does addition with increment if possible         */
3170 /*-----------------------------------------------------------------*/
3171 static bool
3172 genPlusIncr (iCode * ic)
3173 {
3174   unsigned int icount;
3175   unsigned int size = getDataSize (IC_RESULT (ic));
3176
3177   /* will try to generate an increment */
3178   /* if the right side is not a literal
3179      we cannot */
3180   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3181     return FALSE;
3182
3183   /* if the literal value of the right hand side
3184      is greater than 4 then it is not worth it */
3185   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3186     return FALSE;
3187
3188   D(emitcode (";     genPlusIncr",""));
3189
3190   /* if increment >=16 bits in register or direct space */
3191   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3192       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3193       (size > 1) &&
3194       (icount == 1))
3195     {
3196       symbol *tlbl;
3197       int emitTlbl;
3198       int labelRange;
3199
3200       /* If the next instruction is a goto and the goto target
3201        * is < 10 instructions previous to this, we can generate
3202        * jumps straight to that target.
3203        */
3204       if (ic->next && ic->next->op == GOTO
3205           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3206           && labelRange <= 10)
3207         {
3208           emitcode (";", "tail increment optimized");
3209           tlbl = IC_LABEL (ic->next);
3210           emitTlbl = 0;
3211         }
3212       else
3213         {
3214           tlbl = newiTempLabel (NULL);
3215           emitTlbl = 1;
3216         }
3217       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3218       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3219           IS_AOP_PREG (IC_RESULT (ic)))
3220         emitcode ("cjne", "%s,#0x00,%05d$",
3221                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3222                   tlbl->key + 100);
3223       else
3224         {
3225           emitcode ("clr", "a");
3226           emitcode ("cjne", "a,%s,%05d$",
3227                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3228                     tlbl->key + 100);
3229         }
3230
3231       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3232       if (size > 2)
3233         {
3234           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3235               IS_AOP_PREG (IC_RESULT (ic)))
3236             emitcode ("cjne", "%s,#0x00,%05d$",
3237                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3238                       tlbl->key + 100);
3239           else
3240             emitcode ("cjne", "a,%s,%05d$",
3241                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3242                       tlbl->key + 100);
3243
3244           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3245         }
3246       if (size > 3)
3247         {
3248           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3249               IS_AOP_PREG (IC_RESULT (ic)))
3250             emitcode ("cjne", "%s,#0x00,%05d$",
3251                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3252                       tlbl->key + 100);
3253           else
3254             {
3255               emitcode ("cjne", "a,%s,%05d$",
3256                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3257                         tlbl->key + 100);
3258             }
3259           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3260         }
3261
3262       if (emitTlbl)
3263         {
3264           emitcode ("", "%05d$:", tlbl->key + 100);
3265         }
3266       return TRUE;
3267     }
3268
3269   /* if the sizes are greater than 1 then we cannot */
3270   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3271       AOP_SIZE (IC_LEFT (ic)) > 1)
3272     return FALSE;
3273
3274   /* we can if the aops of the left & result match or
3275      if they are in registers and the registers are the
3276      same */
3277   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3278     {
3279
3280       if (icount > 3)
3281         {
3282           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3283           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3284           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3285         }
3286       else
3287         {
3288
3289           while (icount--)
3290             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3291         }
3292
3293       return TRUE;
3294     }
3295
3296   return FALSE;
3297 }
3298
3299 /*-----------------------------------------------------------------*/
3300 /* outBitAcc - output a bit in acc                                 */
3301 /*-----------------------------------------------------------------*/
3302 static void
3303 outBitAcc (operand * result)
3304 {
3305   symbol *tlbl = newiTempLabel (NULL);
3306   /* if the result is a bit */
3307   if (AOP_TYPE (result) == AOP_CRY)
3308     {
3309       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3310     }
3311   else
3312     {
3313       emitcode ("jz", "%05d$", tlbl->key + 100);
3314       emitcode ("mov", "a,%s", one);
3315       emitcode ("", "%05d$:", tlbl->key + 100);
3316       outAcc (result);
3317     }
3318 }
3319
3320 /*-----------------------------------------------------------------*/
3321 /* genPlusBits - generates code for addition of two bits           */
3322 /*-----------------------------------------------------------------*/
3323 static void
3324 genPlusBits (iCode * ic)
3325 {
3326   D(emitcode (";     genPlusBits",""));
3327
3328   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3329     {
3330       symbol *lbl = newiTempLabel (NULL);
3331       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3332       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3333       emitcode ("cpl", "c");
3334       emitcode ("", "%05d$:", (lbl->key + 100));
3335       outBitC (IC_RESULT (ic));
3336     }
3337   else
3338     {
3339       emitcode ("clr", "a");
3340       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3341       emitcode ("rlc", "a");
3342       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3343       emitcode ("addc", "a,#0x00");
3344       outAcc (IC_RESULT (ic));
3345     }
3346 }
3347
3348 #if 0
3349 /* This is the original version of this code.
3350
3351  * This is being kept around for reference,
3352  * because I am not entirely sure I got it right...
3353  */
3354 static void
3355 adjustArithmeticResult (iCode * ic)
3356 {
3357   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3358       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3359       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3360     aopPut (AOP (IC_RESULT (ic)),
3361             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3362             2,
3363             isOperandVolatile (IC_RESULT (ic), FALSE));
3364
3365   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3366       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3367       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3368     aopPut (AOP (IC_RESULT (ic)),
3369             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3370             2,
3371             isOperandVolatile (IC_RESULT (ic), FALSE));
3372
3373   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3374       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3375       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3376       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3377       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3378     {
3379       char buffer[5];
3380       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3381       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3382     }
3383 }
3384 #else
3385 /* This is the pure and virtuous version of this code.
3386  * I'm pretty certain it's right, but not enough to toss the old
3387  * code just yet...
3388  */
3389 static void
3390 adjustArithmeticResult (iCode * ic)
3391 {
3392   if (opIsGptr (IC_RESULT (ic)) &&
3393       opIsGptr (IC_LEFT (ic)) &&
3394       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3395     {
3396       aopPut (AOP (IC_RESULT (ic)),
3397               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3398               GPTRSIZE - 1,
3399               isOperandVolatile (IC_RESULT (ic), FALSE));
3400     }
3401
3402   if (opIsGptr (IC_RESULT (ic)) &&
3403       opIsGptr (IC_RIGHT (ic)) &&
3404       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3405     {
3406       aopPut (AOP (IC_RESULT (ic)),
3407               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3408               GPTRSIZE - 1,
3409               isOperandVolatile (IC_RESULT (ic), FALSE));
3410     }
3411
3412   if (opIsGptr (IC_RESULT (ic)) &&
3413       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3414       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3416       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3417     {
3418       char buffer[5];
3419       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3420       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3421     }
3422 }
3423 #endif
3424
3425 /*-----------------------------------------------------------------*/
3426 /* genPlus - generates code for addition                           */
3427 /*-----------------------------------------------------------------*/
3428 static void
3429 genPlus (iCode * ic)
3430 {
3431   int size, offset = 0;
3432   int skip_bytes = 0;
3433   char *add = "add";
3434   asmop *leftOp, *rightOp;
3435   operand * op;
3436
3437   /* special cases :- */
3438
3439   D(emitcode (";     genPlus",""));
3440
3441   aopOp (IC_LEFT (ic), ic, FALSE);
3442   aopOp (IC_RIGHT (ic), ic, FALSE);
3443   aopOp (IC_RESULT (ic), ic, TRUE);
3444
3445   /* if literal, literal on the right or
3446      if left requires ACC or right is already
3447      in ACC */
3448   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3449       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3450       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3451     {
3452       operand *t = IC_RIGHT (ic);
3453       IC_RIGHT (ic) = IC_LEFT (ic);
3454       IC_LEFT (ic) = t;
3455     }
3456
3457   /* if both left & right are in bit
3458      space */
3459   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3460       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3461     {
3462       genPlusBits (ic);
3463       goto release;
3464     }
3465
3466   /* if left in bit space & right literal */
3467   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3468       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3469     {
3470       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3471       /* if result in bit space */
3472       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3473         {
3474           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3475             emitcode ("cpl", "c");
3476           outBitC (IC_RESULT (ic));
3477         }
3478       else
3479         {
3480           size = getDataSize (IC_RESULT (ic));
3481           while (size--)
3482             {
3483               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3484               emitcode ("addc", "a,#00");
3485               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3486             }
3487         }
3488       goto release;
3489     }
3490
3491   /* if I can do an increment instead
3492      of add then GOOD for ME */
3493   if (genPlusIncr (ic) == TRUE)
3494     goto release;
3495
3496   size = getDataSize (IC_RESULT (ic));
3497   leftOp = AOP(IC_LEFT(ic));
3498   rightOp = AOP(IC_RIGHT(ic));
3499   op=IC_LEFT(ic);
3500
3501   /* if this is an add for an array access
3502      at a 256 byte boundary */
3503   if ( 2 == size
3504        && AOP_TYPE (op) == AOP_IMMD
3505        && IS_SYMOP (op)
3506        && IS_SPEC (OP_SYM_ETYPE (op))
3507        && SPEC_ABSA (OP_SYM_ETYPE (op))
3508        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3509      )
3510     {
3511       D(emitcode (";     genPlus aligned array",""));
3512       aopPut (AOP (IC_RESULT (ic)),
3513               aopGet (rightOp, 0, FALSE, FALSE),
3514               0,
3515               isOperandVolatile (IC_RESULT (ic), FALSE));
3516
3517       if( 1 == getDataSize (IC_RIGHT (ic)) )
3518         {
3519           aopPut (AOP (IC_RESULT (ic)),
3520                   aopGet (leftOp, 1, FALSE, FALSE),
3521                   1,
3522                   isOperandVolatile (IC_RESULT (ic), FALSE));
3523         }
3524       else
3525         {
3526           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3527           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3528           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3529         }
3530       goto release;
3531     }
3532
3533   /* if the lower bytes of a literal are zero skip the addition */
3534   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3535     {
3536        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3537               (skip_bytes+1 < size))
3538          {
3539            skip_bytes++;
3540          }
3541        if (skip_bytes)
3542          D(emitcode (";     genPlus shortcut",""));
3543     }
3544
3545   while (size--)
3546     {
3547       if( offset >= skip_bytes )
3548         {
3549           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3550             {
3551               emitcode("mov", "b,a");
3552               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3553               emitcode("xch", "a,b");
3554               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3555               emitcode (add, "a,b");
3556             }
3557           else if (aopGetUsesAcc (leftOp, offset))
3558             {
3559               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3560               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3561             }
3562           else
3563             {
3564               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3565               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3566             }
3567           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3568           add = "addc";  /* further adds must propagate carry */
3569         }
3570       else
3571         {
3572           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3573               isOperandVolatile (IC_RESULT (ic), FALSE))
3574             {
3575               /* just move */
3576               aopPut (AOP (IC_RESULT (ic)),
3577                       aopGet (leftOp, offset, FALSE, FALSE),
3578                       offset,
3579                       isOperandVolatile (IC_RESULT (ic), FALSE));
3580             }
3581         }
3582       offset++;
3583     }
3584
3585   adjustArithmeticResult (ic);
3586
3587 release:
3588   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3589   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3590   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3591 }
3592
3593 /*-----------------------------------------------------------------*/
3594 /* genMinusDec :- does subtraction with deccrement if possible     */
3595 /*-----------------------------------------------------------------*/
3596 static bool
3597 genMinusDec (iCode * ic)
3598 {
3599   unsigned int icount;
3600   unsigned int size = getDataSize (IC_RESULT (ic));
3601
3602   /* will try to generate an increment */
3603   /* if the right side is not a literal
3604      we cannot */
3605   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3606     return FALSE;
3607
3608   /* if the literal value of the right hand side
3609      is greater than 4 then it is not worth it */
3610   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3611     return FALSE;
3612
3613   D(emitcode (";     genMinusDec",""));
3614
3615   /* if decrement >=16 bits in register or direct space */
3616   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3617       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3618       (size > 1) &&
3619       (icount == 1))
3620     {
3621       symbol *tlbl;
3622       int emitTlbl;
3623       int labelRange;
3624
3625       /* If the next instruction is a goto and the goto target
3626        * is <= 10 instructions previous to this, we can generate
3627        * jumps straight to that target.
3628        */
3629       if (ic->next && ic->next->op == GOTO
3630           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3631           && labelRange <= 10)
3632         {
3633           emitcode (";", "tail decrement optimized");
3634           tlbl = IC_LABEL (ic->next);
3635           emitTlbl = 0;
3636         }
3637       else
3638         {
3639           tlbl = newiTempLabel (NULL);
3640           emitTlbl = 1;
3641         }
3642
3643       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3644       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3645           IS_AOP_PREG (IC_RESULT (ic)))
3646         emitcode ("cjne", "%s,#0xff,%05d$"
3647                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3648                   ,tlbl->key + 100);
3649       else
3650         {
3651           emitcode ("mov", "a,#0xff");
3652           emitcode ("cjne", "a,%s,%05d$"
3653                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3654                     ,tlbl->key + 100);
3655         }
3656       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3657       if (size > 2)
3658         {
3659           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3660               IS_AOP_PREG (IC_RESULT (ic)))
3661             emitcode ("cjne", "%s,#0xff,%05d$"
3662                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3663                       ,tlbl->key + 100);
3664           else
3665             {
3666               emitcode ("cjne", "a,%s,%05d$"
3667                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3668                         ,tlbl->key + 100);
3669             }
3670           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3671         }
3672       if (size > 3)
3673         {
3674           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3675               IS_AOP_PREG (IC_RESULT (ic)))
3676             emitcode ("cjne", "%s,#0xff,%05d$"
3677                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3678                       ,tlbl->key + 100);
3679           else
3680             {
3681               emitcode ("cjne", "a,%s,%05d$"
3682                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3683                         ,tlbl->key + 100);
3684             }
3685           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3686         }
3687       if (emitTlbl)
3688         {
3689           emitcode ("", "%05d$:", tlbl->key + 100);
3690         }
3691       return TRUE;
3692     }
3693
3694   /* if the sizes are greater than 1 then we cannot */
3695   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3696       AOP_SIZE (IC_LEFT (ic)) > 1)
3697     return FALSE;
3698
3699   /* we can if the aops of the left & result match or
3700      if they are in registers and the registers are the
3701      same */
3702   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3703     {
3704
3705       while (icount--)
3706         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3707
3708       return TRUE;
3709     }
3710
3711   return FALSE;
3712 }
3713
3714 /*-----------------------------------------------------------------*/
3715 /* addSign - complete with sign                                    */
3716 /*-----------------------------------------------------------------*/
3717 static void
3718 addSign (operand * result, int offset, int sign)
3719 {
3720   int size = (getDataSize (result) - offset);
3721   if (size > 0)
3722     {
3723       if (sign)
3724         {
3725           emitcode ("rlc", "a");
3726           emitcode ("subb", "a,acc");
3727           while (size--)
3728             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3729         }
3730       else
3731         while (size--)
3732           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3733     }
3734 }
3735
3736 /*-----------------------------------------------------------------*/
3737 /* genMinusBits - generates code for subtraction  of two bits      */
3738 /*-----------------------------------------------------------------*/
3739 static void
3740 genMinusBits (iCode * ic)
3741 {
3742   symbol *lbl = newiTempLabel (NULL);
3743
3744   D(emitcode (";     genMinusBits",""));
3745
3746   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3747     {
3748       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3749       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3750       emitcode ("cpl", "c");
3751       emitcode ("", "%05d$:", (lbl->key + 100));
3752       outBitC (IC_RESULT (ic));
3753     }
3754   else
3755     {
3756       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3757       emitcode ("subb", "a,acc");
3758       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
3759       emitcode ("inc", "a");
3760       emitcode ("", "%05d$:", (lbl->key + 100));
3761       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3762       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
3763     }
3764 }
3765
3766 /*-----------------------------------------------------------------*/
3767 /* genMinus - generates code for subtraction                       */
3768 /*-----------------------------------------------------------------*/
3769 static void
3770 genMinus (iCode * ic)
3771 {
3772   int size, offset = 0;
3773
3774   D(emitcode (";     genMinus",""));
3775
3776   aopOp (IC_LEFT (ic), ic, FALSE);
3777   aopOp (IC_RIGHT (ic), ic, FALSE);
3778   aopOp (IC_RESULT (ic), ic, TRUE);
3779
3780   /* special cases :- */
3781   /* if both left & right are in bit space */
3782   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3783       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3784     {
3785       genMinusBits (ic);
3786       goto release;
3787     }
3788
3789   /* if I can do an decrement instead
3790      of subtract then GOOD for ME */
3791   if (genMinusDec (ic) == TRUE)
3792     goto release;
3793
3794   size = getDataSize (IC_RESULT (ic));
3795
3796   /* if literal, add a,#-lit, else normal subb */
3797   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3798     {
3799       unsigned long lit = 0L;
3800
3801       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3802       lit = -(long) lit;
3803
3804       while (size--)
3805         {
3806           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
3807           /* first add without previous c */
3808           if (!offset) {
3809             if (!size && lit== (unsigned long) -1) {
3810               emitcode ("dec", "a");
3811             } else {
3812               emitcode ("add", "a,#0x%02x",
3813                         (unsigned int) (lit & 0x0FFL));
3814             }
3815           } else {
3816             emitcode ("addc", "a,#0x%02x",
3817                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3818           }
3819           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3820         }
3821     }
3822   else
3823     {
3824       asmop *leftOp, *rightOp;
3825
3826       leftOp = AOP(IC_LEFT(ic));
3827       rightOp = AOP(IC_RIGHT(ic));
3828
3829       while (size--)
3830         {
3831           if (aopGetUsesAcc(rightOp, offset)) {
3832             wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
3833             MOVA (aopGet(rightOp, offset, FALSE, TRUE));
3834             if (offset == 0) {
3835               emitcode( "setb", "c");
3836             }
3837             emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
3838             emitcode("cpl", "a");
3839           } else {
3840             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
3841             if (offset == 0)
3842               CLRC;
3843             emitcode ("subb", "a,%s",
3844                       aopGet(rightOp, offset, FALSE, TRUE));
3845           }
3846
3847           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3848         }
3849     }
3850
3851
3852   adjustArithmeticResult (ic);
3853
3854 release:
3855   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3856   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3857   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3858 }
3859
3860
3861 /*-----------------------------------------------------------------*/
3862 /* genMultbits :- multiplication of bits                           */
3863 /*-----------------------------------------------------------------*/
3864 static void
3865 genMultbits (operand * left,
3866              operand * right,
3867              operand * result)
3868 {
3869   D(emitcode (";     genMultbits",""));
3870
3871   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
3872   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
3873   outBitC (result);
3874 }
3875
3876 /*-----------------------------------------------------------------*/
3877 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
3878 /*-----------------------------------------------------------------*/
3879 static void
3880 genMultOneByte (operand * left,
3881                 operand * right,
3882                 operand * result)
3883 {
3884   symbol *lbl;
3885   int size = AOP_SIZE (result);
3886   bool runtimeSign, compiletimeSign;
3887   bool lUnsigned, rUnsigned;
3888
3889   D(emitcode (";     genMultOneByte",""));
3890
3891   if (size < 1 || size > 2)
3892     {
3893       /* this should never happen */
3894       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
3895                AOP_SIZE(result), __FILE__, lineno);
3896       exit (1);
3897     }
3898
3899   /* (if two literals: the value is computed before) */
3900   /* if one literal, literal on the right */
3901   if (AOP_TYPE (left) == AOP_LIT)
3902     {
3903       operand *t = right;
3904       right = left;
3905       left = t;
3906       /* emitcode (";", "swapped left and right"); */
3907     }
3908   /* if no literal, unsigned on the right: shorter code */
3909   if (   AOP_TYPE (right) != AOP_LIT
3910       && SPEC_USIGN (getSpec (operandType (left))))
3911     {
3912       operand *t = right;
3913       right = left;
3914       left = t;
3915     }
3916
3917   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
3918   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
3919
3920   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
3921                    no need to take care about the signedness! */
3922       || (lUnsigned && rUnsigned))
3923     {
3924       /* just an unsigned 8 * 8 = 8 multiply
3925          or 8u * 8u = 16u */
3926       /* emitcode (";","unsigned"); */
3927       /* TODO: check for accumulator clash between left & right aops? */
3928
3929       if (AOP_TYPE (right) == AOP_LIT)
3930         {
3931           /* moving to accumulator first helps peepholes */
3932           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
3933           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
3934         }
3935       else
3936         {
3937           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
3938           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
3939         }
3940
3941       emitcode ("mul", "ab");
3942       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3943       if (size == 2)
3944         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
3945       return;
3946     }
3947
3948   /* we have to do a signed multiply */
3949   /* emitcode (";", "signed"); */
3950
3951   /* now sign adjust for both left & right */
3952
3953   /* let's see what's needed: */
3954   /* apply negative sign during runtime */
3955   runtimeSign = FALSE;
3956   /* negative sign from literals */
3957   compiletimeSign = FALSE;
3958
3959   if (!lUnsigned)
3960     {
3961       if (AOP_TYPE(left) == AOP_LIT)
3962         {
3963           /* signed literal */
3964           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
3965           if (val < 0)
3966             compiletimeSign = TRUE;
3967         }
3968       else
3969         /* signed but not literal */
3970         runtimeSign = TRUE;
3971     }
3972
3973   if (!rUnsigned)
3974     {
3975       if (AOP_TYPE(right) == AOP_LIT)
3976         {
3977           /* signed literal */
3978           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
3979           if (val < 0)
3980             compiletimeSign ^= TRUE;
3981         }
3982       else
3983         /* signed but not literal */
3984         runtimeSign = TRUE;
3985     }
3986
3987   /* initialize F0, which stores the runtime sign */
3988   if (runtimeSign)
3989     {
3990       if (compiletimeSign)
3991         emitcode ("setb", "F0"); /* set sign flag */
3992       else
3993         emitcode ("clr", "F0"); /* reset sign flag */
3994     }
3995
3996   /* save the signs of the operands */
3997   if (AOP_TYPE(right) == AOP_LIT)
3998     {
3999       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4000
4001       if (!rUnsigned && val < 0)
4002         emitcode ("mov", "b,#0x%02x", -val);
4003       else
4004         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4005     }
4006   else /* ! literal */
4007     {
4008       if (rUnsigned)  /* emitcode (";", "signed"); */
4009
4010         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4011       else
4012         {
4013           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4014           lbl = newiTempLabel (NULL);
4015           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4016           emitcode ("cpl", "F0"); /* complement sign flag */
4017           emitcode ("cpl", "a");  /* 2's complement */
4018           emitcode ("inc", "a");
4019           emitcode ("", "%05d$:", (lbl->key + 100));
4020           emitcode ("mov", "b,a");
4021         }
4022     }
4023
4024   if (AOP_TYPE(left) == AOP_LIT)
4025     {
4026       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4027
4028       if (!lUnsigned && val < 0)
4029         emitcode ("mov", "a,#0x%02x", -val);
4030       else
4031         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4032     }
4033   else /* ! literal */
4034     {
4035       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4036
4037       if (!lUnsigned)
4038         {
4039           lbl = newiTempLabel (NULL);
4040           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4041           emitcode ("cpl", "F0"); /* complement sign flag */
4042           emitcode ("cpl", "a"); /* 2's complement */
4043           emitcode ("inc", "a");
4044           emitcode ("", "%05d$:", (lbl->key + 100));
4045         }
4046     }
4047
4048   /* now the multiplication */
4049   emitcode ("mul", "ab");
4050   if (runtimeSign || compiletimeSign)
4051     {
4052       lbl = newiTempLabel (NULL);
4053       if (runtimeSign)
4054         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4055       emitcode ("cpl", "a"); /* lsb 2's complement */
4056       if (size != 2)
4057         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4058       else
4059         {
4060           emitcode ("add", "a,#1"); /* this sets carry flag */
4061           emitcode ("xch", "a,b");
4062           emitcode ("cpl", "a"); /* msb 2's complement */
4063           emitcode ("addc", "a,#0");
4064           emitcode ("xch", "a,b");
4065         }
4066       emitcode ("", "%05d$:", (lbl->key + 100));
4067     }
4068   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4069   if (size == 2)
4070     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4071 }
4072
4073 /*-----------------------------------------------------------------*/
4074 /* genMult - generates code for multiplication                     */
4075 /*-----------------------------------------------------------------*/
4076 static void
4077 genMult (iCode * ic)
4078 {
4079   operand *left = IC_LEFT (ic);
4080   operand *right = IC_RIGHT (ic);
4081   operand *result = IC_RESULT (ic);
4082
4083   D(emitcode (";     genMult",""));
4084
4085   /* assign the amsops */
4086   aopOp (left, ic, FALSE);
4087   aopOp (right, ic, FALSE);
4088   aopOp (result, ic, TRUE);
4089
4090   /* special cases first */
4091   /* both are bits */
4092   if (AOP_TYPE (left) == AOP_CRY &&
4093       AOP_TYPE (right) == AOP_CRY)
4094     {
4095       genMultbits (left, right, result);
4096       goto release;
4097     }
4098
4099   /* if both are of size == 1 */
4100 #if 0 // one of them can be a sloc shared with the result
4101     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4102 #else
4103   if (getSize(operandType(left)) == 1 &&
4104       getSize(operandType(right)) == 1)
4105 #endif
4106     {
4107       genMultOneByte (left, right, result);
4108       goto release;
4109     }
4110
4111   /* should have been converted to function call */
4112     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4113              getSize(OP_SYMBOL(right)->type));
4114   assert (0);
4115
4116 release:
4117   freeAsmop (result, NULL, ic, TRUE);
4118   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4119   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4120 }
4121
4122 /*-----------------------------------------------------------------*/
4123 /* genDivbits :- division of bits                                  */
4124 /*-----------------------------------------------------------------*/
4125 static void
4126 genDivbits (operand * left,
4127             operand * right,
4128             operand * result)
4129 {
4130
4131   char *l;
4132
4133   D(emitcode (";     genDivbits",""));
4134
4135   /* the result must be bit */
4136   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4137   l = aopGet (AOP (left), 0, FALSE, FALSE);
4138
4139   MOVA (l);
4140
4141   emitcode ("div", "ab");
4142   emitcode ("rrc", "a");
4143   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4144 }
4145
4146 /*-----------------------------------------------------------------*/
4147 /* genDivOneByte : 8 bit division                                  */
4148 /*-----------------------------------------------------------------*/
4149 static void
4150 genDivOneByte (operand * left,
4151                operand * right,
4152                operand * result)
4153 {
4154   bool lUnsigned, rUnsigned;
4155   bool runtimeSign, compiletimeSign;
4156   symbol *lbl;
4157   int size, offset;
4158
4159   D(emitcode (";     genDivOneByte",""));
4160
4161   /* Why is it necessary that genDivOneByte() can return an int result?
4162      Have a look at:
4163      
4164         volatile unsigned char uc;
4165         volatile signed char sc1, sc2;
4166         volatile int i;
4167      
4168         uc  = 255;
4169         sc1 = -1;
4170         i = uc / sc1;
4171
4172      Or:
4173   
4174         sc1 = -128;
4175         sc2 = -1;
4176         i = sc1 / sc2;
4177
4178      In all cases a one byte result would overflow, the following cast to int
4179      would return the wrong result.
4180   
4181      Two possible solution:
4182         a) cast operands to int, if ((unsigned) / (signed)) or
4183            ((signed) / (signed))
4184         b) return an 16 bit signed int; this is what we're doing here!
4185   */
4186   
4187   size = AOP_SIZE (result) - 1;
4188   offset = 1;
4189   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4190   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4191
4192   /* signed or unsigned */
4193   if (lUnsigned && rUnsigned)
4194     {
4195       /* unsigned is easy */
4196       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4197       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4198       emitcode ("div", "ab");
4199       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4200       while (size--)
4201         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4202       return;
4203     }
4204   
4205   /* signed is a little bit more difficult */
4206
4207   /* now sign adjust for both left & right */
4208
4209   /* let's see what's needed: */
4210   /* apply negative sign during runtime */
4211   runtimeSign = FALSE;
4212   /* negative sign from literals */
4213   compiletimeSign = FALSE;
4214
4215   if (!lUnsigned)
4216     {
4217       if (AOP_TYPE(left) == AOP_LIT)
4218         {
4219           /* signed literal */
4220           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4221           if (val < 0)
4222             compiletimeSign = TRUE;
4223         }
4224       else
4225         /* signed but not literal */
4226         runtimeSign = TRUE;
4227     }
4228
4229   if (!rUnsigned)
4230     {
4231       if (AOP_TYPE(right) == AOP_LIT)
4232         {
4233           /* signed literal */
4234           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4235           if (val < 0)
4236             compiletimeSign ^= TRUE;
4237         }
4238       else
4239         /* signed but not literal */
4240         runtimeSign = TRUE;
4241     }
4242
4243   /* initialize F0, which stores the runtime sign */
4244   if (runtimeSign)
4245     {
4246       if (compiletimeSign)
4247         emitcode ("setb", "F0"); /* set sign flag */
4248       else
4249         emitcode ("clr", "F0"); /* reset sign flag */
4250     }
4251
4252   /* save the signs of the operands */
4253   if (AOP_TYPE(right) == AOP_LIT)
4254     {
4255       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4256
4257       if (!rUnsigned && val < 0)
4258         emitcode ("mov", "b,#0x%02x", -val);
4259       else
4260         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4261     }
4262   else /* ! literal */
4263     {
4264       if (rUnsigned)
4265         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4266       else
4267         {
4268           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4269           lbl = newiTempLabel (NULL);
4270           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4271           emitcode ("cpl", "F0"); /* complement sign flag */
4272           emitcode ("cpl", "a");  /* 2's complement */
4273           emitcode ("inc", "a");
4274           emitcode ("", "%05d$:", (lbl->key + 100));
4275           emitcode ("mov", "b,a");
4276         }
4277     }
4278
4279   if (AOP_TYPE(left) == AOP_LIT)
4280     {
4281       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4282
4283       if (!lUnsigned && val < 0)
4284         emitcode ("mov", "a,#0x%02x", -val);
4285       else
4286         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4287     }
4288   else /* ! literal */
4289     {
4290       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4291
4292       if (!lUnsigned)
4293         {
4294           lbl = newiTempLabel (NULL);
4295           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4296           emitcode ("cpl", "F0"); /* complement sign flag */
4297           emitcode ("cpl", "a");  /* 2's complement */
4298           emitcode ("inc", "a");
4299           emitcode ("", "%05d$:", (lbl->key + 100));
4300         }
4301     }
4302
4303   /* now the division */
4304   emitcode ("div", "ab");
4305
4306   if (runtimeSign || compiletimeSign)
4307     {
4308       lbl = newiTempLabel (NULL);
4309       if (runtimeSign)
4310         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4311       emitcode ("cpl", "a"); /* lsb 2's complement */
4312       emitcode ("inc", "a");
4313       emitcode ("", "%05d$:", (lbl->key + 100));
4314
4315       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4316       if (size > 0)
4317         {
4318           /* msb is 0x00 or 0xff depending on the sign */
4319           if (runtimeSign)
4320             {
4321               emitcode ("mov", "c,F0");
4322               emitcode ("subb", "a,acc");
4323               while (size--)
4324                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4325             }
4326           else /* compiletimeSign */
4327             while (size--)
4328               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4329         }
4330     }
4331   else
4332     {
4333       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4334       while (size--)
4335         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4336     }
4337 }
4338
4339 /*-----------------------------------------------------------------*/
4340 /* genDiv - generates code for division                            */
4341 /*-----------------------------------------------------------------*/
4342 static void
4343 genDiv (iCode * ic)
4344 {
4345   operand *left = IC_LEFT (ic);
4346   operand *right = IC_RIGHT (ic);
4347   operand *result = IC_RESULT (ic);
4348
4349   D(emitcode (";     genDiv",""));
4350
4351   /* assign the amsops */
4352   aopOp (left, ic, FALSE);
4353   aopOp (right, ic, FALSE);
4354   aopOp (result, ic, TRUE);
4355
4356   /* special cases first */
4357   /* both are bits */
4358   if (AOP_TYPE (left) == AOP_CRY &&
4359       AOP_TYPE (right) == AOP_CRY)
4360     {
4361       genDivbits (left, right, result);
4362       goto release;
4363     }
4364
4365   /* if both are of size == 1 */
4366   if (AOP_SIZE (left) == 1 &&
4367       AOP_SIZE (right) == 1)
4368     {
4369       genDivOneByte (left, right, result);
4370       goto release;
4371     }
4372
4373   /* should have been converted to function call */
4374   assert (0);
4375 release:
4376   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4377   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4378   freeAsmop (result, NULL, ic, TRUE);
4379 }
4380
4381 /*-----------------------------------------------------------------*/
4382 /* genModbits :- modulus of bits                                   */
4383 /*-----------------------------------------------------------------*/
4384 static void
4385 genModbits (operand * left,
4386             operand * right,
4387             operand * result)
4388 {
4389
4390   char *l;
4391
4392   D(emitcode (";     genModbits",""));
4393
4394   /* the result must be bit */
4395   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4396   l = aopGet (AOP (left), 0, FALSE, FALSE);
4397
4398   MOVA (l);
4399
4400   emitcode ("div", "ab");
4401   emitcode ("mov", "a,b");
4402   emitcode ("rrc", "a");
4403   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4404 }
4405
4406 /*-----------------------------------------------------------------*/
4407 /* genModOneByte : 8 bit modulus                                   */
4408 /*-----------------------------------------------------------------*/
4409 static void
4410 genModOneByte (operand * left,
4411                operand * right,
4412                operand * result)
4413 {
4414   bool lUnsigned, rUnsigned;
4415   bool runtimeSign, compiletimeSign;
4416   symbol *lbl;
4417   int size, offset;
4418
4419   D(emitcode (";     genModOneByte",""));
4420
4421   size = AOP_SIZE (result) - 1;
4422   offset = 1;
4423   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4424   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4425   
4426   /* signed or unsigned */
4427   if (lUnsigned && rUnsigned)
4428     {
4429       /* unsigned is easy */
4430       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4431       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4432       emitcode ("div", "ab");
4433       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4434       while (size--)
4435         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4436       return;
4437     }
4438
4439   /* signed is a little bit more difficult */
4440
4441   /* now sign adjust for both left & right */
4442
4443   /* modulus: sign of the right operand has no influence on the result! */
4444   if (AOP_TYPE(right) == AOP_LIT)
4445     {
4446       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4447
4448       if (!rUnsigned && val < 0)
4449         emitcode ("mov", "b,#0x%02x", -val);
4450       else
4451         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4452     }
4453   else /* not literal */
4454     {
4455       if (rUnsigned)
4456         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4457       else
4458         {
4459           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4460           lbl = newiTempLabel (NULL);
4461           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4462           emitcode ("cpl", "a"); /* 2's complement */
4463           emitcode ("inc", "a");
4464           emitcode ("", "%05d$:", (lbl->key + 100));
4465           emitcode ("mov", "b,a");
4466         }
4467     }
4468
4469   /* let's see what's needed: */
4470   /* apply negative sign during runtime */
4471   runtimeSign = FALSE;
4472   /* negative sign from literals */
4473   compiletimeSign = FALSE;
4474   
4475   /* sign adjust left side */
4476   if (AOP_TYPE(left) == AOP_LIT)
4477     {
4478       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4479
4480       if (!lUnsigned && val < 0)
4481         {
4482           compiletimeSign = TRUE; /* set sign flag */
4483           emitcode ("mov", "a,#0x%02x", -val);
4484         }
4485       else
4486         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4487     }
4488   else /* ! literal */
4489     {
4490       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4491
4492       if (!lUnsigned)
4493         {
4494           runtimeSign = TRUE;
4495           emitcode ("clr", "F0"); /* clear sign flag */
4496
4497           lbl = newiTempLabel (NULL);
4498           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4499           emitcode ("setb", "F0"); /* set sign flag */
4500           emitcode ("cpl", "a");   /* 2's complement */
4501           emitcode ("inc", "a");
4502           emitcode ("", "%05d$:", (lbl->key + 100));
4503         }
4504     }
4505
4506   /* now the modulus */
4507   emitcode ("div", "ab");
4508   
4509   if (runtimeSign || compiletimeSign)
4510     {
4511       emitcode ("mov", "a,b");
4512       lbl = newiTempLabel (NULL);
4513       if (runtimeSign)
4514         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4515       emitcode ("cpl", "a"); /* 2's complement */
4516       emitcode ("inc", "a");
4517       emitcode ("", "%05d$:", (lbl->key + 100));
4518      
4519       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4520       if (size > 0)
4521         {
4522           /* msb is 0x00 or 0xff depending on the sign */
4523           if (runtimeSign)
4524             {
4525               emitcode ("mov", "c,F0");
4526               emitcode ("subb", "a,acc");
4527               while (size--)
4528                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4529             }
4530           else /* compiletimeSign */
4531             while (size--)
4532               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4533         }
4534     }
4535   else
4536     {
4537       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4538       while (size--)
4539         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4540     }
4541 }
4542
4543 /*-----------------------------------------------------------------*/
4544 /* genMod - generates code for division                            */
4545 /*-----------------------------------------------------------------*/
4546 static void
4547 genMod (iCode * ic)
4548 {
4549   operand *left = IC_LEFT (ic);
4550   operand *right = IC_RIGHT (ic);
4551   operand *result = IC_RESULT (ic);
4552
4553   D(emitcode (";     genMod",""));
4554
4555   /* assign the amsops */
4556   aopOp (left, ic, FALSE);
4557   aopOp (right, ic, FALSE);
4558   aopOp (result, ic, TRUE);
4559
4560   /* special cases first */
4561   /* both are bits */
4562   if (AOP_TYPE (left) == AOP_CRY &&
4563       AOP_TYPE (right) == AOP_CRY)
4564     {
4565       genModbits (left, right, result);
4566       goto release;
4567     }
4568
4569   /* if both are of size == 1 */
4570   if (AOP_SIZE (left) == 1 &&
4571       AOP_SIZE (right) == 1)
4572     {
4573       genModOneByte (left, right, result);
4574       goto release;
4575     }
4576
4577   /* should have been converted to function call */
4578   assert (0);
4579
4580 release:
4581   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4582   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4583   freeAsmop (result, NULL, ic, TRUE);
4584 }
4585
4586 /*-----------------------------------------------------------------*/
4587 /* genIfxJump :- will create a jump depending on the ifx           */
4588 /*-----------------------------------------------------------------*/
4589 static void
4590 genIfxJump (iCode * ic, char *jval)
4591 {
4592   symbol *jlbl;
4593   symbol *tlbl = newiTempLabel (NULL);
4594   char *inst;
4595
4596   D(emitcode (";     genIfxJump",""));
4597
4598   /* if true label then we jump if condition
4599      supplied is true */
4600   if (IC_TRUE (ic))
4601     {
4602       jlbl = IC_TRUE (ic);
4603       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4604                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4605     }
4606   else
4607     {
4608       /* false label is present */
4609       jlbl = IC_FALSE (ic);
4610       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4611                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4612     }
4613   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4614     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4615   else
4616     emitcode (inst, "%05d$", tlbl->key + 100);
4617   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4618   emitcode ("", "%05d$:", tlbl->key + 100);
4619
4620   /* mark the icode as generated */
4621   ic->generated = 1;
4622 }
4623
4624 /*-----------------------------------------------------------------*/
4625 /* genCmp :- greater or less than comparison                       */
4626 /*-----------------------------------------------------------------*/
4627 static void
4628 genCmp (operand * left, operand * right,
4629         operand * result, iCode * ifx, int sign, iCode *ic)
4630 {
4631   int size, offset = 0;
4632   unsigned long lit = 0L;
4633   bool rightInB;
4634
4635   D(emitcode (";     genCmp",""));
4636
4637   /* if left & right are bit variables */
4638   if (AOP_TYPE (left) == AOP_CRY &&
4639       AOP_TYPE (right) == AOP_CRY)
4640     {
4641       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4642       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4643     }
4644   else
4645     {
4646       /* subtract right from left if at the
4647          end the carry flag is set then we know that
4648          left is greater than right */
4649       size = max (AOP_SIZE (left), AOP_SIZE (right));
4650
4651       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4652       if ((size == 1) && !sign &&
4653           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4654         {
4655           symbol *lbl = newiTempLabel (NULL);
4656           emitcode ("cjne", "%s,%s,%05d$",
4657                     aopGet (AOP (left), offset, FALSE, FALSE),
4658                     aopGet (AOP (right), offset, FALSE, FALSE),
4659                     lbl->key + 100);
4660           emitcode ("", "%05d$:", lbl->key + 100);
4661         }
4662       else
4663         {
4664           if (AOP_TYPE (right) == AOP_LIT)
4665             {
4666               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4667               /* optimize if(x < 0) or if(x >= 0) */
4668               if (lit == 0L)
4669                 {
4670                   if (!sign)
4671                     {
4672                       CLRC;
4673                     }
4674                   else
4675                     {
4676                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
4677                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4678                         {
4679                           genIfxJump (ifx, "acc.7");
4680                           return;
4681                         }
4682                       else
4683                         emitcode ("rlc", "a");
4684                     }
4685                   goto release;
4686                 }
4687             }
4688           CLRC;
4689           while (size--)
4690             {
4691               rightInB = aopGetUsesAcc(AOP (right), offset);
4692               if (rightInB)
4693                 emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4694               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4695               if (sign && size == 0)
4696                 {
4697                   emitcode ("xrl", "a,#0x80");
4698                   if (AOP_TYPE (right) == AOP_LIT)
4699                     {
4700                       unsigned long lit = (unsigned long)
4701                       floatFromVal (AOP (right)->aopu.aop_lit);
4702                       emitcode ("subb", "a,#0x%02x",
4703                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4704                     }
4705                   else
4706                     {
4707                       if (!rightInB)
4708                         emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4709                       emitcode ("xrl", "b,#0x80");
4710                       emitcode ("subb", "a,b");
4711                     }
4712                 }
4713               else
4714                 {
4715                   if (rightInB)
4716                     emitcode ("subb", "a,b");
4717                   else
4718                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4719                 }
4720               offset++;
4721             }
4722         }
4723     }
4724
4725 release:
4726   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4727   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4728   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4729     {
4730       outBitC (result);
4731     }
4732   else
4733     {
4734       /* if the result is used in the next
4735          ifx conditional branch then generate
4736          code a little differently */
4737       if (ifx)
4738         genIfxJump (ifx, "c");
4739       else
4740         outBitC (result);
4741       /* leave the result in acc */
4742     }
4743 }
4744
4745 /*-----------------------------------------------------------------*/
4746 /* genCmpGt :- greater than comparison                             */
4747 /*-----------------------------------------------------------------*/
4748 static void
4749 genCmpGt (iCode * ic, iCode * ifx)
4750 {
4751   operand *left, *right, *result;
4752   sym_link *letype, *retype;
4753   int sign;
4754
4755   D(emitcode (";     genCmpGt",""));
4756
4757   left = IC_LEFT (ic);
4758   right = IC_RIGHT (ic);
4759   result = IC_RESULT (ic);
4760
4761   letype = getSpec (operandType (left));
4762   retype = getSpec (operandType (right));
4763   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4764            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4765   /* assign the amsops */
4766   aopOp (left, ic, FALSE);
4767   aopOp (right, ic, FALSE);
4768   aopOp (result, ic, TRUE);
4769
4770   genCmp (right, left, result, ifx, sign,ic);
4771
4772   freeAsmop (result, NULL, ic, TRUE);
4773 }
4774
4775 /*-----------------------------------------------------------------*/
4776 /* genCmpLt - less than comparisons                                */
4777 /*-----------------------------------------------------------------*/
4778 static void
4779 genCmpLt (iCode * ic, iCode * ifx)
4780 {
4781   operand *left, *right, *result;
4782   sym_link *letype, *retype;
4783   int sign;
4784
4785   D(emitcode (";     genCmpLt",""));
4786
4787   left = IC_LEFT (ic);
4788   right = IC_RIGHT (ic);
4789   result = IC_RESULT (ic);
4790
4791   letype = getSpec (operandType (left));
4792   retype = getSpec (operandType (right));
4793   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4794            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4795   /* assign the amsops */
4796   aopOp (left, ic, FALSE);
4797   aopOp (right, ic, FALSE);
4798   aopOp (result, ic, TRUE);
4799
4800   genCmp (left, right, result, ifx, sign,ic);
4801
4802   freeAsmop (result, NULL, ic, TRUE);
4803 }
4804
4805 /*-----------------------------------------------------------------*/
4806 /* gencjneshort - compare and jump if not equal                    */
4807 /*-----------------------------------------------------------------*/
4808 static void
4809 gencjneshort (operand * left, operand * right, symbol * lbl)
4810 {
4811   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4812   int offset = 0;
4813   unsigned long lit = 0L;
4814
4815   /* if the left side is a literal or
4816      if the right is in a pointer register and left
4817      is not */
4818   if ((AOP_TYPE (left) == AOP_LIT) ||
4819       (AOP_TYPE (left) == AOP_IMMD) ||
4820       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4821     {
4822       operand *t = right;
4823       right = left;
4824       left = t;
4825     }
4826
4827   if (AOP_TYPE (right) == AOP_LIT)
4828     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4829
4830   /* if the right side is a literal then anything goes */
4831   if (AOP_TYPE (right) == AOP_LIT &&
4832       AOP_TYPE (left) != AOP_DIR  &&
4833       AOP_TYPE (left) != AOP_IMMD)
4834     {
4835       while (size--)
4836         {
4837           emitcode ("cjne", "%s,%s,%05d$",
4838                     aopGet (AOP (left), offset, FALSE, FALSE),
4839                     aopGet (AOP (right), offset, FALSE, FALSE),
4840                     lbl->key + 100);
4841           offset++;
4842         }
4843     }
4844
4845   /* if the right side is in a register or in direct space or
4846      if the left is a pointer register & right is not */
4847   else if (AOP_TYPE (right) == AOP_REG ||
4848            AOP_TYPE (right) == AOP_DIR ||
4849            AOP_TYPE (right) == AOP_LIT ||
4850            AOP_TYPE (right) == AOP_IMMD ||
4851            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
4852            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
4853     {
4854       while (size--)
4855         {
4856           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4857           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4858               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4859             emitcode ("jnz", "%05d$", lbl->key + 100);
4860           else
4861             emitcode ("cjne", "a,%s,%05d$",
4862                       aopGet (AOP (right), offset, FALSE, TRUE),
4863                       lbl->key + 100);
4864           offset++;
4865         }
4866     }
4867   else
4868     {
4869       /* right is a pointer reg need both a & b */
4870       while (size--)
4871         {
4872           char *l = aopGet (AOP (left), offset, FALSE, FALSE);
4873           if (strcmp (l, "b"))
4874             emitcode ("mov", "b,%s", l);
4875           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
4876           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
4877           offset++;
4878         }
4879     }
4880 }
4881
4882 /*-----------------------------------------------------------------*/
4883 /* gencjne - compare and jump if not equal                         */
4884 /*-----------------------------------------------------------------*/
4885 static void
4886 gencjne (operand * left, operand * right, symbol * lbl)
4887 {
4888   symbol *tlbl = newiTempLabel (NULL);
4889
4890   gencjneshort (left, right, lbl);
4891
4892   emitcode ("mov", "a,%s", one);
4893   emitcode ("sjmp", "%05d$", tlbl->key + 100);
4894   emitcode ("", "%05d$:", lbl->key + 100);
4895   emitcode ("clr", "a");
4896   emitcode ("", "%05d$:", tlbl->key + 100);
4897 }
4898
4899 /*-----------------------------------------------------------------*/
4900 /* genCmpEq - generates code for equal to                          */
4901 /*-----------------------------------------------------------------*/
4902 static void
4903 genCmpEq (iCode * ic, iCode * ifx)
4904 {
4905   operand *left, *right, *result;
4906
4907   D(emitcode (";     genCmpEq",""));
4908
4909   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
4910   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
4911   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
4912
4913   /* if literal, literal on the right or
4914      if the right is in a pointer register and left
4915      is not */
4916   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4917       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4918     {
4919       operand *t = IC_RIGHT (ic);
4920       IC_RIGHT (ic) = IC_LEFT (ic);
4921       IC_LEFT (ic) = t;
4922     }
4923
4924   if (ifx && !AOP_SIZE (result))
4925     {
4926       symbol *tlbl;
4927       /* if they are both bit variables */
4928       if (AOP_TYPE (left) == AOP_CRY &&
4929           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4930         {
4931           if (AOP_TYPE (right) == AOP_LIT)
4932             {
4933               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4934               if (lit == 0L)
4935                 {
4936                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4937                   emitcode ("cpl", "c");
4938                 }
4939               else if (lit == 1L)
4940                 {
4941                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4942                 }
4943               else
4944                 {
4945                   emitcode ("clr", "c");
4946                 }
4947               /* AOP_TYPE(right) == AOP_CRY */
4948             }
4949           else
4950             {
4951               symbol *lbl = newiTempLabel (NULL);
4952               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4953               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
4954               emitcode ("cpl", "c");
4955               emitcode ("", "%05d$:", (lbl->key + 100));
4956             }
4957           /* if true label then we jump if condition
4958              supplied is true */
4959           tlbl = newiTempLabel (NULL);
4960           if (IC_TRUE (ifx))
4961             {
4962               emitcode ("jnc", "%05d$", tlbl->key + 100);
4963               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
4964             }
4965           else
4966             {
4967               emitcode ("jc", "%05d$", tlbl->key + 100);
4968               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
4969             }
4970           emitcode ("", "%05d$:", tlbl->key + 100);
4971         }
4972       else
4973         {
4974           tlbl = newiTempLabel (NULL);
4975           gencjneshort (left, right, tlbl);
4976           if (IC_TRUE (ifx))
4977             {
4978               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
4979               emitcode ("", "%05d$:", tlbl->key + 100);
4980             }
4981           else
4982             {
4983               symbol *lbl = newiTempLabel (NULL);
4984               emitcode ("sjmp", "%05d$", lbl->key + 100);
4985               emitcode ("", "%05d$:", tlbl->key + 100);
4986               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
4987               emitcode ("", "%05d$:", lbl->key + 100);
4988             }
4989         }
4990       /* mark the icode as generated */
4991       ifx->generated = 1;
4992       goto release;
4993     }
4994
4995   /* if they are both bit variables */
4996   if (AOP_TYPE (left) == AOP_CRY &&
4997       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4998     {
4999       if (AOP_TYPE (right) == AOP_LIT)
5000         {
5001           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5002           if (lit == 0L)
5003             {
5004               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5005               emitcode ("cpl", "c");
5006             }
5007           else if (lit == 1L)
5008             {
5009               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5010             }
5011           else
5012             {
5013               emitcode ("clr", "c");
5014             }
5015           /* AOP_TYPE(right) == AOP_CRY */
5016         }
5017       else
5018         {
5019           symbol *lbl = newiTempLabel (NULL);
5020           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5021           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5022           emitcode ("cpl", "c");
5023           emitcode ("", "%05d$:", (lbl->key + 100));
5024         }
5025       /* c = 1 if egal */
5026       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5027         {
5028           outBitC (result);
5029           goto release;
5030         }
5031       if (ifx)
5032         {
5033           genIfxJump (ifx, "c");
5034           goto release;
5035         }
5036       /* if the result is used in an arithmetic operation
5037          then put the result in place */
5038       outBitC (result);
5039     }
5040   else
5041     {
5042       gencjne (left, right, newiTempLabel (NULL));
5043       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5044         {
5045           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5046           goto release;
5047         }
5048       if (ifx)
5049         {
5050           genIfxJump (ifx, "a");
5051           goto release;
5052         }
5053       /* if the result is used in an arithmetic operation
5054          then put the result in place */
5055       if (AOP_TYPE (result) != AOP_CRY)
5056         outAcc (result);
5057       /* leave the result in acc */
5058     }
5059
5060 release:
5061   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5062   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5063   freeAsmop (result, NULL, ic, TRUE);
5064 }
5065
5066 /*-----------------------------------------------------------------*/
5067 /* ifxForOp - returns the icode containing the ifx for operand     */
5068 /*-----------------------------------------------------------------*/
5069 static iCode *
5070 ifxForOp (operand * op, iCode * ic)
5071 {
5072   /* if true symbol then needs to be assigned */
5073   if (IS_TRUE_SYMOP (op))
5074     return NULL;
5075
5076   /* if this has register type condition and
5077      the next instruction is ifx with the same operand
5078      and live to of the operand is upto the ifx only then */
5079   if (ic->next &&
5080       ic->next->op == IFX &&
5081       IC_COND (ic->next)->key == op->key &&
5082       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5083     return ic->next;
5084
5085   return NULL;
5086 }
5087
5088 /*-----------------------------------------------------------------*/
5089 /* hasInc - operand is incremented before any other use            */
5090 /*-----------------------------------------------------------------*/
5091 static iCode *
5092 hasInc (operand *op, iCode *ic,int osize)
5093 {
5094   sym_link *type = operandType(op);
5095   sym_link *retype = getSpec (type);
5096   iCode *lic = ic->next;
5097   int isize ;
5098
5099   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5100   if (!IS_SYMOP(op)) return NULL;
5101
5102   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5103   if (IS_AGGREGATE(type->next)) return NULL;
5104   if (osize != (isize = getSize(type->next))) return NULL;
5105
5106   while (lic) {
5107     /* if operand of the form op = op + <sizeof *op> */
5108     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5109         isOperandEqual(IC_RESULT(lic),op) &&
5110         isOperandLiteral(IC_RIGHT(lic)) &&
5111         operandLitValue(IC_RIGHT(lic)) == isize) {
5112       return lic;
5113     }
5114     /* if the operand used or deffed */
5115     if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
5116       return NULL;
5117     }
5118     /* if GOTO or IFX */
5119     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5120     lic = lic->next;
5121   }
5122   return NULL;
5123 }
5124
5125 /*-----------------------------------------------------------------*/
5126 /* genAndOp - for && operation                                     */
5127 /*-----------------------------------------------------------------*/
5128 static void
5129 genAndOp (iCode * ic)
5130 {
5131   operand *left, *right, *result;
5132   symbol *tlbl;
5133
5134   D(emitcode (";     genAndOp",""));
5135
5136   /* note here that && operations that are in an
5137      if statement are taken away by backPatchLabels
5138      only those used in arthmetic operations remain */
5139   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5140   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5141   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5142
5143   /* if both are bit variables */
5144   if (AOP_TYPE (left) == AOP_CRY &&
5145       AOP_TYPE (right) == AOP_CRY)
5146     {
5147       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5148       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5149       outBitC (result);
5150     }
5151   else
5152     {
5153       tlbl = newiTempLabel (NULL);
5154       toBoolean (left);
5155       emitcode ("jz", "%05d$", tlbl->key + 100);
5156       toBoolean (right);
5157       emitcode ("", "%05d$:", tlbl->key + 100);
5158       outBitAcc (result);
5159     }
5160
5161   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5162   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5163   freeAsmop (result, NULL, ic, TRUE);
5164 }
5165
5166
5167 /*-----------------------------------------------------------------*/
5168 /* genOrOp - for || operation                                      */
5169 /*-----------------------------------------------------------------*/
5170 static void
5171 genOrOp (iCode * ic)
5172 {
5173   operand *left, *right, *result;
5174   symbol *tlbl;
5175
5176   D(emitcode (";     genOrOp",""));
5177
5178   /* note here that || operations that are in an
5179      if statement are taken away by backPatchLabels
5180      only those used in arthmetic operations remain */
5181   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5182   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5183   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5184
5185   /* if both are bit variables */
5186   if (AOP_TYPE (left) == AOP_CRY &&
5187       AOP_TYPE (right) == AOP_CRY)
5188     {
5189       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5190       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5191       outBitC (result);
5192     }
5193   else
5194     {
5195       tlbl = newiTempLabel (NULL);
5196       toBoolean (left);
5197       emitcode ("jnz", "%05d$", tlbl->key + 100);
5198       toBoolean (right);
5199       emitcode ("", "%05d$:", tlbl->key + 100);
5200       outBitAcc (result);
5201     }
5202
5203   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5204   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5205   freeAsmop (result, NULL, ic, TRUE);
5206 }
5207
5208 /*-----------------------------------------------------------------*/
5209 /* isLiteralBit - test if lit == 2^n                               */
5210 /*-----------------------------------------------------------------*/
5211 static int
5212 isLiteralBit (unsigned long lit)
5213 {
5214   unsigned long pw[32] =
5215   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5216    0x100L, 0x200L, 0x400L, 0x800L,
5217    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5218    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5219    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5220    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5221    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5222   int idx;
5223
5224   for (idx = 0; idx < 32; idx++)
5225     if (lit == pw[idx])
5226       return idx + 1;
5227   return 0;
5228 }
5229
5230 /*-----------------------------------------------------------------*/
5231 /* continueIfTrue -                                                */
5232 /*-----------------------------------------------------------------*/
5233 static void
5234 continueIfTrue (iCode * ic)
5235 {
5236   if (IC_TRUE (ic))
5237     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5238   ic->generated = 1;
5239 }
5240
5241 /*-----------------------------------------------------------------*/
5242 /* jmpIfTrue -                                                     */
5243 /*-----------------------------------------------------------------*/
5244 static void
5245 jumpIfTrue (iCode * ic)
5246 {
5247   if (!IC_TRUE (ic))
5248     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5249   ic->generated = 1;
5250 }
5251
5252 /*-----------------------------------------------------------------*/
5253 /* jmpTrueOrFalse -                                                */
5254 /*-----------------------------------------------------------------*/
5255 static void
5256 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5257 {
5258   // ugly but optimized by peephole
5259   if (IC_TRUE (ic))
5260     {
5261       symbol *nlbl = newiTempLabel (NULL);
5262       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5263       emitcode ("", "%05d$:", tlbl->key + 100);
5264       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5265       emitcode ("", "%05d$:", nlbl->key + 100);
5266     }
5267   else
5268     {
5269       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5270       emitcode ("", "%05d$:", tlbl->key + 100);
5271     }
5272   ic->generated = 1;
5273 }
5274
5275 /*-----------------------------------------------------------------*/
5276 /* genAnd  - code for and                                          */
5277 /*-----------------------------------------------------------------*/
5278 static void
5279 genAnd (iCode * ic, iCode * ifx)
5280 {
5281   operand *left, *right, *result;
5282   int size, offset = 0;
5283   unsigned long lit = 0L;
5284   int bytelit = 0;
5285   char buffer[10];
5286
5287   D(emitcode (";     genAnd",""));
5288
5289   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5290   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5291   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5292
5293 #ifdef DEBUG_TYPE
5294   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5295             AOP_TYPE (result),
5296             AOP_TYPE (left), AOP_TYPE (right));
5297   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5298             AOP_SIZE (result),
5299             AOP_SIZE (left), AOP_SIZE (right));
5300 #endif
5301
5302   /* if left is a literal & right is not then exchange them */
5303   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5304       AOP_NEEDSACC (left))
5305     {
5306       operand *tmp = right;
5307       right = left;
5308       left = tmp;
5309     }
5310
5311   /* if result = right then exchange them */
5312   if (sameRegs (AOP (result), AOP (right)))
5313     {
5314       operand *tmp = right;
5315       right = left;
5316       left = tmp;
5317     }
5318
5319   /* if right is bit then exchange them */
5320   if (AOP_TYPE (right) == AOP_CRY &&
5321       AOP_TYPE (left) != AOP_CRY)
5322     {
5323       operand *tmp = right;
5324       right = left;
5325       left = tmp;
5326     }
5327   if (AOP_TYPE (right) == AOP_LIT)
5328     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5329
5330   size = AOP_SIZE (result);
5331
5332   // if(bit & yy)
5333   // result = bit & yy;
5334   if (AOP_TYPE (left) == AOP_CRY)
5335     {
5336       // c = bit & literal;
5337       if (AOP_TYPE (right) == AOP_LIT)
5338         {
5339           if (lit & 1)
5340             {
5341               if (size && sameRegs (AOP (result), AOP (left)))
5342                 // no change
5343                 goto release;
5344               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5345             }
5346           else
5347             {
5348               // bit(result) = 0;
5349               if (size && (AOP_TYPE (result) == AOP_CRY))
5350                 {
5351                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5352                   goto release;
5353                 }
5354               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5355                 {
5356                   jumpIfTrue (ifx);
5357                   goto release;
5358                 }
5359               emitcode ("clr", "c");
5360             }
5361         }
5362       else
5363         {
5364           if (AOP_TYPE (right) == AOP_CRY)
5365             {
5366               // c = bit & bit;
5367               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5368               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5369             }
5370           else
5371             {
5372               // c = bit & val;
5373               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5374               // c = lsb
5375               emitcode ("rrc", "a");
5376               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5377             }
5378         }
5379       // bit = c
5380       // val = c
5381       if (size)
5382         outBitC (result);
5383       // if(bit & ...)
5384       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5385         genIfxJump (ifx, "c");
5386       goto release;
5387     }
5388
5389   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5390   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5391   if ((AOP_TYPE (right) == AOP_LIT) &&
5392       (AOP_TYPE (result) == AOP_CRY) &&
5393       (AOP_TYPE (left) != AOP_CRY))
5394     {
5395       int posbit = isLiteralBit (lit);
5396       /* left &  2^n */
5397       if (posbit)
5398         {
5399           posbit--;
5400           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5401           // bit = left & 2^n
5402           if (size)
5403             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5404           // if(left &  2^n)
5405           else
5406             {
5407               if (ifx)
5408                 {
5409                   sprintf (buffer, "acc.%d", posbit & 0x07);
5410                   genIfxJump (ifx, buffer);
5411                 }
5412               goto release;
5413             }
5414         }
5415       else
5416         {
5417           symbol *tlbl = newiTempLabel (NULL);
5418           int sizel = AOP_SIZE (left);
5419           if (size)
5420             emitcode ("setb", "c");
5421           while (sizel--)
5422             {
5423               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5424                 {
5425                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5426                   // byte ==  2^n ?
5427                   if ((posbit = isLiteralBit (bytelit)) != 0)
5428                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5429                   else
5430                     {
5431                       if (bytelit != 0x0FFL)
5432                         emitcode ("anl", "a,%s",
5433                                   aopGet (AOP (right), offset, FALSE, TRUE));
5434                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5435                     }
5436                 }
5437               offset++;
5438             }
5439           // bit = left & literal
5440           if (size)
5441             {
5442               emitcode ("clr", "c");
5443               emitcode ("", "%05d$:", tlbl->key + 100);
5444             }
5445           // if(left & literal)
5446           else
5447             {
5448               if (ifx)
5449                 jmpTrueOrFalse (ifx, tlbl);
5450               else
5451                 emitcode ("", "%05d$:", tlbl->key + 100);
5452               goto release;
5453             }
5454         }
5455       outBitC (result);
5456       goto release;
5457     }
5458
5459   /* if left is same as result */
5460   if (sameRegs (AOP (result), AOP (left)))
5461     {
5462       for (; size--; offset++)
5463         {
5464           if (AOP_TYPE (right) == AOP_LIT)
5465             {
5466               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5467                 continue;
5468               else if (bytelit == 0)
5469                 {
5470                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5471                 }
5472               else if (IS_AOP_PREG (result))
5473                 {
5474                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5475                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5476                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5477                 }
5478               else
5479                 emitcode ("anl", "%s,%s",
5480                           aopGet (AOP (left), offset, FALSE, TRUE),
5481                           aopGet (AOP (right), offset, FALSE, FALSE));
5482             }
5483           else
5484             {
5485               if (AOP_TYPE (left) == AOP_ACC)
5486                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5487               else
5488                 {
5489                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5490                   if (IS_AOP_PREG (result))
5491                     {
5492                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5493                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5494
5495                     }
5496                   else
5497                     emitcode ("anl", "%s,a",
5498                               aopGet (AOP (left), offset, FALSE, TRUE));
5499                 }
5500             }
5501         }
5502     }
5503   else
5504     {
5505       // left & result in different registers
5506       if (AOP_TYPE (result) == AOP_CRY)
5507         {
5508           // result = bit
5509           // if(size), result in bit
5510           // if(!size && ifx), conditional oper: if(left & right)
5511           symbol *tlbl = newiTempLabel (NULL);
5512           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5513           if (size)
5514             emitcode ("setb", "c");
5515           while (sizer--)
5516             {
5517               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5518                 emitcode ("anl", "a,%s",
5519                           aopGet (AOP (right), offset, FALSE, FALSE));
5520               } else {
5521                 if (AOP_TYPE(left)==AOP_ACC) {
5522                   emitcode("mov", "b,a");
5523                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5524                   emitcode("anl", "a,b");
5525                 }else {
5526                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5527                   emitcode ("anl", "a,%s",
5528                             aopGet (AOP (left), offset, FALSE, FALSE));
5529                 }
5530               }
5531               emitcode ("jnz", "%05d$", tlbl->key + 100);
5532               offset++;
5533             }
5534           if (size)
5535             {
5536               CLRC;
5537               emitcode ("", "%05d$:", tlbl->key + 100);
5538               outBitC (result);
5539             }
5540           else if (ifx)
5541             jmpTrueOrFalse (ifx, tlbl);
5542           else
5543             emitcode ("", "%05d$:", tlbl->key + 100);
5544         }
5545       else
5546         {
5547           for (; (size--); offset++)
5548             {
5549               // normal case
5550               // result = left & right
5551               if (AOP_TYPE (right) == AOP_LIT)
5552                 {
5553                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5554                     {
5555                       aopPut (AOP (result),
5556                               aopGet (AOP (left), offset, FALSE, FALSE),
5557                               offset,
5558                               isOperandVolatile (result, FALSE));
5559                       continue;
5560                     }
5561                   else if (bytelit == 0)
5562                     {
5563                       /* dummy read of volatile operand */
5564                       if (isOperandVolatile (left, FALSE))
5565                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5566                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5567                       continue;
5568                     }
5569                 }
5570               // faster than result <- left, anl result,right
5571               // and better if result is SFR
5572               if (AOP_TYPE (left) == AOP_ACC)
5573                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5574               else
5575                 {
5576                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5577                   emitcode ("anl", "a,%s",
5578                             aopGet (AOP (left), offset, FALSE, FALSE));
5579                 }
5580               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5581             }
5582         }
5583     }
5584
5585 release:
5586   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5587   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5588   freeAsmop (result, NULL, ic, TRUE);
5589 }
5590
5591 /*-----------------------------------------------------------------*/
5592 /* genOr  - code for or                                            */
5593 /*-----------------------------------------------------------------*/
5594 static void
5595 genOr (iCode * ic, iCode * ifx)
5596 {
5597   operand *left, *right, *result;
5598   int size, offset = 0;
5599   unsigned long lit = 0L;
5600
5601   D(emitcode (";     genOr",""));
5602
5603   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5604   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5605   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5606
5607 #ifdef DEBUG_TYPE
5608   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5609             AOP_TYPE (result),
5610             AOP_TYPE (left), AOP_TYPE (right));
5611   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5612             AOP_SIZE (result),
5613             AOP_SIZE (left), AOP_SIZE (right));
5614 #endif
5615
5616   /* if left is a literal & right is not then exchange them */
5617   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5618       AOP_NEEDSACC (left))
5619     {
5620       operand *tmp = right;
5621       right = left;
5622       left = tmp;
5623     }
5624
5625   /* if result = right then exchange them */
5626   if (sameRegs (AOP (result), AOP (right)))
5627     {
5628       operand *tmp = right;
5629       right = left;
5630       left = tmp;
5631     }
5632
5633   /* if right is bit then exchange them */
5634   if (AOP_TYPE (right) == AOP_CRY &&
5635       AOP_TYPE (left) != AOP_CRY)
5636     {
5637       operand *tmp = right;
5638       right = left;
5639       left = tmp;
5640     }
5641   if (AOP_TYPE (right) == AOP_LIT)
5642     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5643
5644   size = AOP_SIZE (result);
5645
5646   // if(bit | yy)
5647   // xx = bit | yy;
5648   if (AOP_TYPE (left) == AOP_CRY)
5649     {
5650       if (AOP_TYPE (right) == AOP_LIT)
5651         {
5652           // c = bit | literal;
5653           if (lit)
5654             {
5655               // lit != 0 => result = 1
5656               if (AOP_TYPE (result) == AOP_CRY)
5657                 {
5658                   if (size)
5659                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5660                   else if (ifx)
5661                     continueIfTrue (ifx);
5662                   goto release;
5663                 }
5664               emitcode ("setb", "c");
5665             }
5666           else
5667             {
5668               // lit == 0 => result = left
5669               if (size && sameRegs (AOP (result), AOP (left)))
5670                 goto release;
5671               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5672             }
5673         }
5674       else
5675         {
5676           if (AOP_TYPE (right) == AOP_CRY)
5677             {
5678               // c = bit | bit;
5679               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5680               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5681             }
5682           else
5683             {
5684               // c = bit | val;
5685               symbol *tlbl = newiTempLabel (NULL);
5686               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5687                 emitcode ("setb", "c");
5688               emitcode ("jb", "%s,%05d$",
5689                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5690               toBoolean (right);
5691               emitcode ("jnz", "%05d$", tlbl->key + 100);
5692               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5693                 {
5694                   jmpTrueOrFalse (ifx, tlbl);
5695                   goto release;
5696                 }
5697               else
5698                 {
5699                   CLRC;
5700                   emitcode ("", "%05d$:", tlbl->key + 100);
5701                 }
5702             }
5703         }
5704       // bit = c
5705       // val = c
5706       if (size)
5707         outBitC (result);
5708       // if(bit | ...)
5709       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5710         genIfxJump (ifx, "c");
5711       goto release;
5712     }
5713
5714   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5715   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5716   if ((AOP_TYPE (right) == AOP_LIT) &&
5717       (AOP_TYPE (result) == AOP_CRY) &&
5718       (AOP_TYPE (left) != AOP_CRY))
5719     {
5720       if (lit)
5721         {
5722           // result = 1
5723           if (size)
5724             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5725           else
5726             continueIfTrue (ifx);
5727           goto release;
5728         }
5729       else
5730         {
5731           // lit = 0, result = boolean(left)
5732           if (size)
5733             emitcode ("setb", "c");
5734           toBoolean (right);
5735           if (size)
5736             {
5737               symbol *tlbl = newiTempLabel (NULL);
5738               emitcode ("jnz", "%05d$", tlbl->key + 100);
5739               CLRC;
5740               emitcode ("", "%05d$:", tlbl->key + 100);
5741             }
5742           else
5743             {
5744               genIfxJump (ifx, "a");
5745               goto release;
5746             }
5747         }
5748       outBitC (result);
5749       goto release;
5750     }
5751
5752   /* if left is same as result */
5753   if (sameRegs (AOP (result), AOP (left)))
5754     {
5755       for (; size--; offset++)
5756         {
5757           if (AOP_TYPE (right) == AOP_LIT)
5758             {
5759               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5760                 {
5761                   /* dummy read of volatile operand */
5762                   if (isOperandVolatile (left, FALSE))
5763                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5764                   else
5765                     continue;
5766                 }
5767               else if (IS_AOP_PREG (left))
5768                 {
5769                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5770                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5771                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5772                 }
5773               else
5774                 emitcode ("orl", "%s,%s",
5775                           aopGet (AOP (left), offset, FALSE, TRUE),
5776                           aopGet (AOP (right), offset, FALSE, FALSE));
5777             }
5778           else
5779             {
5780               if (AOP_TYPE (left) == AOP_ACC)
5781                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5782               else
5783                 {
5784                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5785                   if (IS_AOP_PREG (left))
5786                     {
5787                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5788                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5789                     }
5790                   else
5791                     emitcode ("orl", "%s,a",
5792                               aopGet (AOP (left), offset, FALSE, TRUE));
5793                 }
5794             }
5795         }
5796     }
5797   else
5798     {
5799       // left & result in different registers
5800       if (AOP_TYPE (result) == AOP_CRY)
5801         {
5802           // result = bit
5803           // if(size), result in bit
5804           // if(!size && ifx), conditional oper: if(left | right)
5805           symbol *tlbl = newiTempLabel (NULL);
5806           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
5807           if (size)
5808             emitcode ("setb", "c");
5809           while (sizer--)
5810             {
5811               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5812                 emitcode ("orl", "a,%s",
5813                           aopGet (AOP (right), offset, FALSE, FALSE));
5814               } else {
5815                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5816                 emitcode ("orl", "a,%s",
5817                           aopGet (AOP (left), offset, FALSE, FALSE));
5818               }
5819               emitcode ("jnz", "%05d$", tlbl->key + 100);
5820               offset++;
5821             }
5822           if (size)
5823             {
5824               CLRC;
5825               emitcode ("", "%05d$:", tlbl->key + 100);
5826               outBitC (result);
5827             }
5828           else if (ifx)
5829             jmpTrueOrFalse (ifx, tlbl);
5830           else
5831             emitcode ("", "%05d$:", tlbl->key + 100);
5832         }
5833       else
5834         for (; (size--); offset++)
5835           {
5836             // normal case
5837             // result = left & right
5838             if (AOP_TYPE (right) == AOP_LIT)
5839               {
5840                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5841                   {
5842                     aopPut (AOP (result),
5843                             aopGet (AOP (left), offset, FALSE, FALSE),
5844                             offset,
5845                             isOperandVolatile (result, FALSE));
5846                     continue;
5847                   }
5848               }
5849             // faster than result <- left, anl result,right
5850             // and better if result is SFR
5851             if (AOP_TYPE (left) == AOP_ACC)
5852               emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5853             else
5854               {
5855                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5856                 emitcode ("orl", "a,%s",
5857                           aopGet (AOP (left), offset, FALSE, FALSE));
5858               }
5859             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5860           }
5861     }
5862
5863 release:
5864   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5865   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5866   freeAsmop (result, NULL, ic, TRUE);
5867 }
5868
5869 /*-----------------------------------------------------------------*/
5870 /* genXor - code for xclusive or                                   */
5871 /*-----------------------------------------------------------------*/
5872 static void
5873 genXor (iCode * ic, iCode * ifx)
5874 {
5875   operand *left, *right, *result;
5876   int size, offset = 0;
5877   unsigned long lit = 0L;
5878
5879   D(emitcode (";     genXor",""));
5880
5881   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5882   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5883   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5884
5885 #ifdef DEBUG_TYPE
5886   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5887             AOP_TYPE (result),
5888             AOP_TYPE (left), AOP_TYPE (right));
5889   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5890             AOP_SIZE (result),
5891             AOP_SIZE (left), AOP_SIZE (right));
5892 #endif
5893
5894   /* if left is a literal & right is not ||
5895      if left needs acc & right does not */
5896   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5897       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
5898     {
5899       operand *tmp = right;
5900       right = left;
5901       left = tmp;
5902     }
5903
5904   /* if result = right then exchange them */
5905   if (sameRegs (AOP (result), AOP (right)))
5906     {
5907       operand *tmp = right;
5908       right = left;
5909       left = tmp;
5910     }
5911
5912   /* if right is bit then exchange them */
5913   if (AOP_TYPE (right) == AOP_CRY &&
5914       AOP_TYPE (left) != AOP_CRY)
5915     {
5916       operand *tmp = right;
5917       right = left;
5918       left = tmp;
5919     }
5920   if (AOP_TYPE (right) == AOP_LIT)
5921     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5922
5923   size = AOP_SIZE (result);
5924
5925   // if(bit ^ yy)
5926   // xx = bit ^ yy;
5927   if (AOP_TYPE (left) == AOP_CRY)
5928     {
5929       if (AOP_TYPE (right) == AOP_LIT)
5930         {
5931           // c = bit & literal;
5932           if (lit >> 1)
5933             {
5934               // lit>>1  != 0 => result = 1
5935               if (AOP_TYPE (result) == AOP_CRY)
5936                 {
5937                   if (size)
5938                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5939                   else if (ifx)
5940                     continueIfTrue (ifx);
5941                   goto release;
5942                 }
5943               emitcode ("setb", "c");
5944             }
5945           else
5946             {
5947               // lit == (0 or 1)
5948               if (lit == 0)
5949                 {
5950                   // lit == 0, result = left
5951                   if (size && sameRegs (AOP (result), AOP (left)))
5952                     goto release;
5953                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5954                 }
5955               else
5956                 {
5957                   // lit == 1, result = not(left)
5958                   if (size && sameRegs (AOP (result), AOP (left)))
5959                     {
5960                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
5961                       goto release;
5962                     }
5963                   else
5964                     {
5965                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5966                       emitcode ("cpl", "c");
5967                     }
5968                 }
5969             }
5970
5971         }
5972       else
5973         {
5974           // right != literal
5975           symbol *tlbl = newiTempLabel (NULL);
5976           if (AOP_TYPE (right) == AOP_CRY)
5977             {
5978               // c = bit ^ bit;
5979               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5980             }
5981           else
5982             {
5983               int sizer = AOP_SIZE (right);
5984               // c = bit ^ val
5985               // if val>>1 != 0, result = 1
5986               emitcode ("setb", "c");
5987               while (sizer)
5988                 {
5989                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
5990                   if (sizer == 1)
5991                     // test the msb of the lsb
5992                     emitcode ("anl", "a,#0xfe");
5993                   emitcode ("jnz", "%05d$", tlbl->key + 100);
5994                   sizer--;
5995                 }
5996               // val = (0,1)
5997               emitcode ("rrc", "a");
5998             }
5999           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6000           emitcode ("cpl", "c");
6001           emitcode ("", "%05d$:", (tlbl->key + 100));
6002         }
6003       // bit = c
6004       // val = c
6005       if (size)
6006         outBitC (result);
6007       // if(bit | ...)
6008       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6009         genIfxJump (ifx, "c");
6010       goto release;
6011     }
6012
6013   if (sameRegs (AOP (result), AOP (left)))
6014     {
6015       /* if left is same as result */
6016       for (; size--; offset++)
6017         {
6018           if (AOP_TYPE (right) == AOP_LIT)
6019             {
6020               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6021                 continue;
6022               else if (IS_AOP_PREG (left))
6023                 {
6024                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6025                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6026                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6027                 }
6028               else
6029                 emitcode ("xrl", "%s,%s",
6030                           aopGet (AOP (left), offset, FALSE, TRUE),
6031                           aopGet (AOP (right), offset, FALSE, FALSE));
6032             }
6033           else
6034             {
6035               if (AOP_TYPE (left) == AOP_ACC)
6036                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6037               else
6038                 {
6039                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6040                   if (IS_AOP_PREG (left))
6041                     {
6042                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6043                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6044                     }
6045                   else
6046                     emitcode ("xrl", "%s,a",
6047                               aopGet (AOP (left), offset, FALSE, TRUE));
6048                 }
6049             }
6050         }
6051     }
6052   else
6053     {
6054       // left & result in different registers
6055       if (AOP_TYPE (result) == AOP_CRY)
6056         {
6057           // result = bit
6058           // if(size), result in bit
6059           // if(!size && ifx), conditional oper: if(left ^ right)
6060           symbol *tlbl = newiTempLabel (NULL);
6061           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6062           if (size)
6063             emitcode ("setb", "c");
6064           while (sizer--)
6065             {
6066               if ((AOP_TYPE (right) == AOP_LIT) &&
6067                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6068                 {
6069                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6070                 }
6071               else
6072                 {
6073                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6074                     emitcode ("xrl", "a,%s",
6075                               aopGet (AOP (right), offset, FALSE, FALSE));
6076                   } else {
6077                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6078                     emitcode ("xrl", "a,%s",
6079                               aopGet (AOP (left), offset, FALSE, FALSE));
6080                   }
6081                 }
6082               emitcode ("jnz", "%05d$", tlbl->key + 100);
6083               offset++;
6084             }
6085           if (size)
6086             {
6087               CLRC;
6088               emitcode ("", "%05d$:", tlbl->key + 100);
6089               outBitC (result);
6090             }
6091           else if (ifx)
6092             jmpTrueOrFalse (ifx, tlbl);
6093         }
6094       else
6095         for (; (size--); offset++)
6096           {
6097             // normal case
6098             // result = left & right
6099             if (AOP_TYPE (right) == AOP_LIT)
6100               {
6101                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6102                   {
6103                     aopPut (AOP (result),
6104                             aopGet (AOP (left), offset, FALSE, FALSE),
6105                             offset,
6106                             isOperandVolatile (result, FALSE));
6107                     continue;
6108                   }
6109               }
6110             // faster than result <- left, anl result,right
6111             // and better if result is SFR
6112             if (AOP_TYPE (left) == AOP_ACC)
6113               emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6114             else
6115               {
6116                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6117                 emitcode ("xrl", "a,%s",
6118                           aopGet (AOP (left), offset, FALSE, TRUE));
6119               }
6120             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6121           }
6122     }
6123
6124 release:
6125   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6126   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6127   freeAsmop (result, NULL, ic, TRUE);
6128 }
6129
6130 /*-----------------------------------------------------------------*/
6131 /* genInline - write the inline code out                           */
6132 /*-----------------------------------------------------------------*/
6133 static void
6134 genInline (iCode * ic)
6135 {
6136   char *buffer, *bp, *bp1;
6137
6138   D(emitcode (";     genInline",""));
6139
6140   _G.inLine += (!options.asmpeep);
6141
6142   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6143   strcpy (buffer, IC_INLINE (ic));
6144
6145   /* emit each line as a code */
6146   while (*bp)
6147     {
6148       if (*bp == '\n')
6149         {
6150           *bp++ = '\0';
6151           emitcode (bp1, "");
6152           bp1 = bp;
6153         }
6154       else
6155         {
6156           if (*bp == ':')
6157             {
6158               bp++;
6159               *bp = '\0';
6160               bp++;
6161               emitcode (bp1, "");
6162               bp1 = bp;
6163             }
6164           else
6165             bp++;
6166         }
6167     }
6168   if (bp1 != bp)
6169     emitcode (bp1, "");
6170   /*     emitcode("",buffer); */
6171   _G.inLine -= (!options.asmpeep);
6172 }
6173
6174 /*-----------------------------------------------------------------*/
6175 /* genRRC - rotate right with carry                                */
6176 /*-----------------------------------------------------------------*/
6177 static void
6178 genRRC (iCode * ic)
6179 {
6180   operand *left, *result;
6181   int size, offset = 0;
6182   char *l;
6183
6184   D(emitcode (";     genRRC",""));
6185
6186   /* rotate right with carry */
6187   left = IC_LEFT (ic);
6188   result = IC_RESULT (ic);
6189   aopOp (left, ic, FALSE);
6190   aopOp (result, ic, FALSE);
6191
6192   /* move it to the result */
6193   size = AOP_SIZE (result);
6194   offset = size - 1;
6195   if (size == 1) { /* special case for 1 byte */
6196       l = aopGet (AOP (left), offset, FALSE, FALSE);
6197       MOVA (l);
6198       emitcode ("rr", "a");
6199       goto release;
6200   }
6201   CLRC;
6202   while (size--)
6203     {
6204       l = aopGet (AOP (left), offset, FALSE, FALSE);
6205       MOVA (l);
6206       emitcode ("rrc", "a");
6207       if (AOP_SIZE (result) > 1)
6208         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6209     }
6210   /* now we need to put the carry into the
6211      highest order byte of the result */
6212   if (AOP_SIZE (result) > 1)
6213     {
6214       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6215       MOVA (l);
6216     }
6217   emitcode ("mov", "acc.7,c");
6218  release:
6219   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6220   freeAsmop (left, NULL, ic, TRUE);
6221   freeAsmop (result, NULL, ic, TRUE);
6222 }
6223
6224 /*-----------------------------------------------------------------*/
6225 /* genRLC - generate code for rotate left with carry               */
6226 /*-----------------------------------------------------------------*/
6227 static void
6228 genRLC (iCode * ic)
6229 {
6230   operand *left, *result;
6231   int size, offset = 0;
6232   char *l;
6233
6234   D(emitcode (";     genRLC",""));
6235
6236   /* rotate right with carry */
6237   left = IC_LEFT (ic);
6238   result = IC_RESULT (ic);
6239   aopOp (left, ic, FALSE);
6240   aopOp (result, ic, FALSE);
6241
6242   /* move it to the result */
6243   size = AOP_SIZE (result);
6244   offset = 0;
6245   if (size--)
6246     {
6247       l = aopGet (AOP (left), offset, FALSE, FALSE);
6248       MOVA (l);
6249       if (size == 0) { /* special case for 1 byte */
6250               emitcode("rl","a");
6251               goto release;
6252       }
6253       emitcode ("add", "a,acc");
6254       if (AOP_SIZE (result) > 1)
6255         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6256       while (size--)
6257         {
6258           l = aopGet (AOP (left), offset, FALSE, FALSE);
6259           MOVA (l);
6260           emitcode ("rlc", "a");
6261           if (AOP_SIZE (result) > 1)
6262             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6263         }
6264     }
6265   /* now we need to put the carry into the
6266      highest order byte of the result */
6267   if (AOP_SIZE (result) > 1)
6268     {
6269       l = aopGet (AOP (result), 0, FALSE, FALSE);
6270       MOVA (l);
6271     }
6272   emitcode ("mov", "acc.0,c");
6273  release:
6274   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6275   freeAsmop (left, NULL, ic, TRUE);
6276   freeAsmop (result, NULL, ic, TRUE);
6277 }
6278
6279 /*-----------------------------------------------------------------*/
6280 /* genGetHbit - generates code get highest order bit               */
6281 /*-----------------------------------------------------------------*/
6282 static void
6283 genGetHbit (iCode * ic)
6284 {
6285   operand *left, *result;
6286
6287   D(emitcode (";     genGetHbit",""));
6288
6289   left = IC_LEFT (ic);
6290   result = IC_RESULT (ic);
6291   aopOp (left, ic, FALSE);
6292   aopOp (result, ic, FALSE);
6293
6294   /* get the highest order byte into a */
6295   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6296   if (AOP_TYPE (result) == AOP_CRY)
6297     {
6298       emitcode ("rlc", "a");
6299       outBitC (result);
6300     }
6301   else
6302     {
6303       emitcode ("rl", "a");
6304       emitcode ("anl", "a,#0x01");
6305       outAcc (result);
6306     }
6307
6308
6309   freeAsmop (left, NULL, ic, TRUE);
6310   freeAsmop (result, NULL, ic, TRUE);
6311 }
6312
6313 /*-----------------------------------------------------------------*/
6314 /* genSwap - generates code to swap nibbles or bytes               */
6315 /*-----------------------------------------------------------------*/
6316 static void
6317 genSwap (iCode * ic)
6318 {
6319   operand *left, *result;
6320
6321   D(emitcode (";     genSwap",""));
6322
6323   left = IC_LEFT (ic);
6324   result = IC_RESULT (ic);
6325   aopOp (left, ic, FALSE);
6326   aopOp (result, ic, FALSE);
6327
6328   switch (AOP_SIZE (left))
6329     {
6330     case 1: /* swap nibbles in byte */
6331       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6332       emitcode ("swap", "a");
6333       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6334       break;
6335     case 2: /* swap bytes in word */
6336       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6337         {
6338           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6339           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6340                   0, isOperandVolatile (result, FALSE));
6341           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6342         }
6343       else if (operandsEqu (left, result))
6344         {
6345           char * reg = "a";
6346           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6347           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6348             {
6349               emitcode ("mov", "b,a");
6350               reg = "b";
6351             }
6352           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6353                   0, isOperandVolatile (result, FALSE));
6354           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6355         }
6356       else
6357         {
6358           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6359                   0, isOperandVolatile (result, FALSE));
6360           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6361                   1, isOperandVolatile (result, FALSE));
6362         }
6363       break;
6364     default:
6365       wassertl(FALSE, "unsupported SWAP operand size");
6366     }
6367
6368   freeAsmop (left, NULL, ic, TRUE);
6369   freeAsmop (result, NULL, ic, TRUE);
6370 }
6371
6372
6373 /*-----------------------------------------------------------------*/
6374 /* AccRol - rotate left accumulator by known count                 */
6375 /*-----------------------------------------------------------------*/
6376 static void
6377 AccRol (int shCount)
6378 {
6379   shCount &= 0x0007;            // shCount : 0..7
6380
6381   switch (shCount)
6382     {
6383     case 0:
6384       break;
6385     case 1:
6386       emitcode ("rl", "a");
6387       break;
6388     case 2:
6389       emitcode ("rl", "a");
6390       emitcode ("rl", "a");
6391       break;
6392     case 3:
6393       emitcode ("swap", "a");
6394       emitcode ("rr", "a");
6395       break;
6396     case 4:
6397       emitcode ("swap", "a");
6398       break;
6399     case 5:
6400       emitcode ("swap", "a");
6401       emitcode ("rl", "a");
6402       break;
6403     case 6:
6404       emitcode ("rr", "a");
6405       emitcode ("rr", "a");
6406       break;
6407     case 7:
6408       emitcode ("rr", "a");
6409       break;
6410     }
6411 }
6412
6413 /*-----------------------------------------------------------------*/
6414 /* AccLsh - left shift accumulator by known count                  */
6415 /*-----------------------------------------------------------------*/
6416 static void
6417 AccLsh (int shCount)
6418 {
6419   if (shCount != 0)
6420     {
6421       if (shCount == 1)
6422         emitcode ("add", "a,acc");
6423       else if (shCount == 2)
6424         {
6425           emitcode ("add", "a,acc");
6426           emitcode ("add", "a,acc");
6427         }
6428       else
6429         {
6430           /* rotate left accumulator */
6431           AccRol (shCount);
6432           /* and kill the lower order bits */
6433           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6434         }
6435     }
6436 }
6437
6438 /*-----------------------------------------------------------------*/
6439 /* AccRsh - right shift accumulator by known count                 */
6440 /*-----------------------------------------------------------------*/
6441 static void
6442 AccRsh (int shCount)
6443 {
6444   if (shCount != 0)
6445     {
6446       if (shCount == 1)
6447         {
6448           CLRC;
6449           emitcode ("rrc", "a");
6450         }
6451       else
6452         {
6453           /* rotate right accumulator */
6454           AccRol (8 - shCount);
6455           /* and kill the higher order bits */
6456           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6457         }
6458     }
6459 }
6460
6461 /*-----------------------------------------------------------------*/
6462 /* AccSRsh - signed right shift accumulator by known count                 */
6463 /*-----------------------------------------------------------------*/
6464 static void
6465 AccSRsh (int shCount)
6466 {
6467   symbol *tlbl;
6468   if (shCount != 0)
6469     {
6470       if (shCount == 1)
6471         {
6472           emitcode ("mov", "c,acc.7");
6473           emitcode ("rrc", "a");
6474         }
6475       else if (shCount == 2)
6476         {
6477           emitcode ("mov", "c,acc.7");
6478           emitcode ("rrc", "a");
6479           emitcode ("mov", "c,acc.7");
6480           emitcode ("rrc", "a");
6481         }
6482       else
6483         {
6484           tlbl = newiTempLabel (NULL);
6485           /* rotate right accumulator */
6486           AccRol (8 - shCount);
6487           /* and kill the higher order bits */
6488           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6489           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6490           emitcode ("orl", "a,#0x%02x",
6491                     (unsigned char) ~SRMask[shCount]);
6492           emitcode ("", "%05d$:", tlbl->key + 100);
6493         }
6494     }
6495 }
6496
6497 /*-----------------------------------------------------------------*/
6498 /* shiftR1Left2Result - shift right one byte from left to result   */
6499 /*-----------------------------------------------------------------*/
6500 static void
6501 shiftR1Left2Result (operand * left, int offl,
6502                     operand * result, int offr,
6503                     int shCount, int sign)
6504 {
6505   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6506   /* shift right accumulator */
6507   if (sign)
6508     AccSRsh (shCount);
6509   else
6510     AccRsh (shCount);
6511   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6512 }
6513
6514 /*-----------------------------------------------------------------*/
6515 /* shiftL1Left2Result - shift left one byte from left to result    */
6516 /*-----------------------------------------------------------------*/
6517 static void
6518 shiftL1Left2Result (operand * left, int offl,
6519                     operand * result, int offr, int shCount)
6520 {
6521   char *l;
6522   l = aopGet (AOP (left), offl, FALSE, FALSE);
6523   MOVA (l);
6524   /* shift left accumulator */
6525   AccLsh (shCount);
6526   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6527 }
6528
6529 /*-----------------------------------------------------------------*/
6530 /* movLeft2Result - move byte from left to result                  */
6531 /*-----------------------------------------------------------------*/
6532 static void
6533 movLeft2Result (operand * left, int offl,
6534                 operand * result, int offr, int sign)
6535 {
6536   char *l;
6537   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6538     {
6539       l = aopGet (AOP (left), offl, FALSE, FALSE);
6540
6541       if (*l == '@' && (IS_AOP_PREG (result)))
6542         {
6543           emitcode ("mov", "a,%s", l);
6544           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6545         }
6546       else
6547         {
6548           if (!sign)
6549             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6550           else
6551             {
6552               /* MSB sign in acc.7 ! */
6553               if (getDataSize (left) == offl + 1)
6554                 {
6555                   emitcode ("mov", "a,%s", l);
6556                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6557                 }
6558             }
6559         }
6560     }
6561 }
6562
6563 /*-----------------------------------------------------------------*/
6564 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6565 /*-----------------------------------------------------------------*/
6566 static void
6567 AccAXRrl1 (char *x)
6568 {
6569   emitcode ("rrc", "a");
6570   emitcode ("xch", "a,%s", x);
6571   emitcode ("rrc", "a");
6572   emitcode ("xch", "a,%s", x);
6573 }
6574
6575 /*-----------------------------------------------------------------*/
6576 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6577 /*-----------------------------------------------------------------*/
6578 static void
6579 AccAXLrl1 (char *x)
6580 {
6581   emitcode ("xch", "a,%s", x);
6582   emitcode ("rlc", "a");
6583   emitcode ("xch", "a,%s", x);
6584   emitcode ("rlc", "a");
6585 }
6586
6587 /*-----------------------------------------------------------------*/
6588 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6589 /*-----------------------------------------------------------------*/
6590 static void
6591 AccAXLsh1 (char *x)
6592 {
6593   emitcode ("xch", "a,%s", x);
6594   emitcode ("add", "a,acc");
6595   emitcode ("xch", "a,%s", x);
6596   emitcode ("rlc", "a");
6597 }
6598
6599 /*-----------------------------------------------------------------*/
6600 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6601 /*-----------------------------------------------------------------*/
6602 static void
6603 AccAXLsh (char *x, int shCount)
6604 {
6605   switch (shCount)
6606     {
6607     case 0:
6608       break;
6609     case 1:
6610       AccAXLsh1 (x);
6611       break;
6612     case 2:
6613       AccAXLsh1 (x);
6614       AccAXLsh1 (x);
6615       break;
6616     case 3:
6617     case 4:
6618     case 5:                     // AAAAABBB:CCCCCDDD
6619
6620       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6621
6622       emitcode ("anl", "a,#0x%02x",
6623                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6624
6625       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6626
6627       AccRol (shCount);         // DDDCCCCC:BBB00000
6628
6629       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6630
6631       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6632
6633       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6634
6635       emitcode ("anl", "a,#0x%02x",
6636                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6637
6638       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6639
6640       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6641
6642       break;
6643     case 6:                     // AAAAAABB:CCCCCCDD
6644       emitcode ("anl", "a,#0x%02x",
6645                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6646       emitcode ("mov", "c,acc.0");      // c = B
6647       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6648 #if 0 // REMOVE ME
6649       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6650       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6651 #else
6652       emitcode("rrc","a");
6653       emitcode("xch","a,%s", x);
6654       emitcode("rrc","a");
6655       emitcode("mov","c,acc.0"); //<< get correct bit
6656       emitcode("xch","a,%s", x);
6657
6658       emitcode("rrc","a");
6659       emitcode("xch","a,%s", x);
6660       emitcode("rrc","a");
6661       emitcode("xch","a,%s", x);
6662 #endif
6663       break;
6664     case 7:                     // a:x <<= 7
6665
6666       emitcode ("anl", "a,#0x%02x",
6667                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6668
6669       emitcode ("mov", "c,acc.0");      // c = B
6670
6671       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6672
6673       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6674
6675       break;
6676     default:
6677       break;
6678     }
6679 }
6680
6681 /*-----------------------------------------------------------------*/
6682 /* AccAXRsh - right shift a:x known count (0..7)                   */
6683 /*-----------------------------------------------------------------*/
6684 static void
6685 AccAXRsh (char *x, int shCount)
6686 {
6687   switch (shCount)
6688     {
6689     case 0:
6690       break;
6691     case 1:
6692       CLRC;
6693       AccAXRrl1 (x);            // 0->a:x
6694
6695       break;
6696     case 2:
6697       CLRC;
6698       AccAXRrl1 (x);            // 0->a:x
6699
6700       CLRC;
6701       AccAXRrl1 (x);            // 0->a:x
6702
6703       break;
6704     case 3:
6705     case 4:
6706     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6707
6708       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
6709
6710       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6711
6712       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6713
6714       emitcode ("anl", "a,#0x%02x",
6715                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6716
6717       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6718
6719       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6720
6721       emitcode ("anl", "a,#0x%02x",
6722                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6723
6724       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6725
6726       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6727
6728       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
6729
6730       break;
6731     case 6:                     // AABBBBBB:CCDDDDDD
6732
6733       emitcode ("mov", "c,acc.7");
6734       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6735
6736       emitcode ("mov", "c,acc.7");
6737       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6738
6739       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6740
6741       emitcode ("anl", "a,#0x%02x",
6742                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6743
6744       break;
6745     case 7:                     // ABBBBBBB:CDDDDDDD
6746
6747       emitcode ("mov", "c,acc.7");      // c = A
6748
6749       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6750
6751       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6752
6753       emitcode ("anl", "a,#0x%02x",
6754                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6755
6756       break;
6757     default:
6758       break;
6759     }
6760 }
6761
6762 /*-----------------------------------------------------------------*/
6763 /* AccAXRshS - right shift signed a:x known count (0..7)           */
6764 /*-----------------------------------------------------------------*/
6765 static void
6766 AccAXRshS (char *x, int shCount)
6767 {
6768   symbol *tlbl;
6769   switch (shCount)
6770     {
6771     case 0:
6772       break;
6773     case 1:
6774       emitcode ("mov", "c,acc.7");
6775       AccAXRrl1 (x);            // s->a:x
6776
6777       break;
6778     case 2:
6779       emitcode ("mov", "c,acc.7");
6780       AccAXRrl1 (x);            // s->a:x
6781
6782       emitcode ("mov", "c,acc.7");
6783       AccAXRrl1 (x);            // s->a:x
6784
6785       break;
6786     case 3:
6787     case 4:
6788     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6789
6790       tlbl = newiTempLabel (NULL);
6791       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
6792
6793       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6794
6795       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6796
6797       emitcode ("anl", "a,#0x%02x",
6798                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6799
6800       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6801
6802       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6803
6804       emitcode ("anl", "a,#0x%02x",
6805                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6806
6807       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6808
6809       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6810
6811       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
6812
6813       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6814       emitcode ("orl", "a,#0x%02x",
6815                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
6816
6817       emitcode ("", "%05d$:", tlbl->key + 100);
6818       break;                    // SSSSAAAA:BBBCCCCC
6819
6820     case 6:                     // AABBBBBB:CCDDDDDD
6821
6822       tlbl = newiTempLabel (NULL);
6823       emitcode ("mov", "c,acc.7");
6824       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6825
6826       emitcode ("mov", "c,acc.7");
6827       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6828
6829       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6830
6831       emitcode ("anl", "a,#0x%02x",
6832                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6833
6834       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6835       emitcode ("orl", "a,#0x%02x",
6836                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
6837
6838       emitcode ("", "%05d$:", tlbl->key + 100);
6839       break;
6840     case 7:                     // ABBBBBBB:CDDDDDDD
6841
6842       tlbl = newiTempLabel (NULL);
6843       emitcode ("mov", "c,acc.7");      // c = A
6844
6845       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6846
6847       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6848
6849       emitcode ("anl", "a,#0x%02x",
6850                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6851
6852       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6853       emitcode ("orl", "a,#0x%02x",
6854                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
6855
6856       emitcode ("", "%05d$:", tlbl->key + 100);
6857       break;
6858     default:
6859       break;
6860     }
6861 }
6862
6863 /*-----------------------------------------------------------------*/
6864 /* shiftL2Left2Result - shift left two bytes from left to result   */
6865 /*-----------------------------------------------------------------*/
6866 static void
6867 shiftL2Left2Result (operand * left, int offl,
6868                     operand * result, int offr, int shCount)
6869 {
6870   if (sameRegs (AOP (result), AOP (left)) &&
6871       ((offl + MSB16) == offr))
6872     {
6873       /* don't crash result[offr] */
6874       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6875       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6876     }
6877   else
6878     {
6879       movLeft2Result (left, offl, result, offr, 0);
6880       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6881     }
6882   /* ax << shCount (x = lsb(result)) */
6883   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
6884   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
6885 }
6886
6887
6888 /*-----------------------------------------------------------------*/
6889 /* shiftR2Left2Result - shift right two bytes from left to result  */
6890 /*-----------------------------------------------------------------*/
6891 static void
6892 shiftR2Left2Result (operand * left, int offl,
6893                     operand * result, int offr,
6894                     int shCount, int sign)
6895 {
6896   if (sameRegs (AOP (result), AOP (left)) &&
6897       ((offl + MSB16) == offr))
6898     {
6899       /* don't crash result[offr] */
6900       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6901       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6902     }
6903   else
6904     {
6905       movLeft2Result (left, offl, result, offr, 0);
6906       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6907     }
6908   /* a:x >> shCount (x = lsb(result)) */
6909   if (sign)
6910     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
6911   else
6912     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
6913   if (getDataSize (result) > 1)
6914     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
6915 }
6916
6917 /*-----------------------------------------------------------------*/
6918 /* shiftLLeftOrResult - shift left one byte from left, or to result */
6919 /*-----------------------------------------------------------------*/
6920 static void
6921 shiftLLeftOrResult (operand * left, int offl,
6922                     operand * result, int offr, int shCount)
6923 {
6924   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6925   /* shift left accumulator */
6926   AccLsh (shCount);
6927   /* or with result */
6928   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
6929   /* back to result */
6930   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6931 }
6932
6933 /*-----------------------------------------------------------------*/
6934 /* shiftRLeftOrResult - shift right one byte from left,or to result */
6935 /*-----------------------------------------------------------------*/
6936 static void
6937 shiftRLeftOrResult (operand * left, int offl,
6938                     operand * result, int offr, int shCount)
6939 {
6940   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6941   /* shift right accumulator */
6942   AccRsh (shCount);
6943   /* or with result */
6944   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
6945   /* back to result */
6946   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6947 }
6948
6949 /*-----------------------------------------------------------------*/
6950 /* genlshOne - left shift a one byte quantity by known count       */
6951 /*-----------------------------------------------------------------*/
6952 static void
6953 genlshOne (operand * result, operand * left, int shCount)
6954 {
6955   D(emitcode (";     genlshOne",""));
6956
6957   shiftL1Left2Result (left, LSB, result, LSB, shCount);
6958 }
6959
6960 /*-----------------------------------------------------------------*/
6961 /* genlshTwo - left shift two bytes by known amount != 0           */
6962 /*-----------------------------------------------------------------*/
6963 static void
6964 genlshTwo (operand * result, operand * left, int shCount)
6965 {
6966   int size;
6967
6968   D(emitcode (";     genlshTwo",""));
6969
6970   size = getDataSize (result);
6971
6972   /* if shCount >= 8 */
6973   if (shCount >= 8)
6974     {
6975       shCount -= 8;
6976
6977       if (size > 1)
6978         {
6979           if (shCount)
6980             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6981           else
6982             movLeft2Result (left, LSB, result, MSB16, 0);
6983         }
6984       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
6985     }
6986
6987   /*  1 <= shCount <= 7 */
6988   else
6989     {
6990       if (size == 1)
6991         shiftL1Left2Result (left, LSB, result, LSB, shCount);
6992       else
6993         shiftL2Left2Result (left, LSB, result, LSB, shCount);
6994     }
6995 }
6996
6997 /*-----------------------------------------------------------------*/
6998 /* shiftLLong - shift left one long from left to result            */
6999 /* offl = LSB or MSB16                                             */
7000 /*-----------------------------------------------------------------*/
7001 static void
7002 shiftLLong (operand * left, operand * result, int offr)
7003 {
7004   char *l;
7005   int size = AOP_SIZE (result);
7006
7007   if (size >= LSB + offr)
7008     {
7009       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7010       MOVA (l);
7011       emitcode ("add", "a,acc");
7012       if (sameRegs (AOP (left), AOP (result)) &&
7013           size >= MSB16 + offr && offr != LSB)
7014         emitcode ("xch", "a,%s",
7015                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7016       else
7017         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7018     }
7019
7020   if (size >= MSB16 + offr)
7021     {
7022       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7023         {
7024           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7025           MOVA (l);
7026         }
7027       emitcode ("rlc", "a");
7028       if (sameRegs (AOP (left), AOP (result)) &&
7029           size >= MSB24 + offr && offr != LSB)
7030         emitcode ("xch", "a,%s",
7031                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7032       else
7033         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7034     }
7035
7036   if (size >= MSB24 + offr)
7037     {
7038       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7039         {
7040           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7041           MOVA (l);
7042         }
7043       emitcode ("rlc", "a");
7044       if (sameRegs (AOP (left), AOP (result)) &&
7045           size >= MSB32 + offr && offr != LSB)
7046         emitcode ("xch", "a,%s",
7047                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7048       else
7049         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7050     }
7051
7052   if (size > MSB32 + offr)
7053     {
7054       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7055         {
7056           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7057           MOVA (l);
7058         }
7059       emitcode ("rlc", "a");
7060       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7061     }
7062   if (offr != LSB)
7063     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7064 }
7065
7066 /*-----------------------------------------------------------------*/
7067 /* genlshFour - shift four byte by a known amount != 0             */
7068 /*-----------------------------------------------------------------*/
7069 static void
7070 genlshFour (operand * result, operand * left, int shCount)
7071 {
7072   int size;
7073
7074   D(emitcode (";     genlshFour",""));
7075
7076   size = AOP_SIZE (result);
7077
7078   /* if shifting more that 3 bytes */
7079   if (shCount >= 24)
7080     {
7081       shCount -= 24;
7082       if (shCount)
7083         /* lowest order of left goes to the highest
7084            order of the destination */
7085         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7086       else
7087         movLeft2Result (left, LSB, result, MSB32, 0);
7088       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7089       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7090       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7091       return;
7092     }
7093
7094   /* more than two bytes */
7095   else if (shCount >= 16)
7096     {
7097       /* lower order two bytes goes to higher order two bytes */
7098       shCount -= 16;
7099       /* if some more remaining */
7100       if (shCount)
7101         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7102       else
7103         {
7104           movLeft2Result (left, MSB16, result, MSB32, 0);
7105           movLeft2Result (left, LSB, result, MSB24, 0);
7106         }
7107       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7108       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7109       return;
7110     }
7111
7112   /* if more than 1 byte */
7113   else if (shCount >= 8)
7114     {
7115       /* lower order three bytes goes to higher order  three bytes */
7116       shCount -= 8;
7117       if (size == 2)
7118         {
7119           if (shCount)
7120             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7121           else
7122             movLeft2Result (left, LSB, result, MSB16, 0);
7123         }
7124       else
7125         {                       /* size = 4 */
7126           if (shCount == 0)
7127             {
7128               movLeft2Result (left, MSB24, result, MSB32, 0);
7129               movLeft2Result (left, MSB16, result, MSB24, 0);
7130               movLeft2Result (left, LSB, result, MSB16, 0);
7131               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7132             }
7133           else if (shCount == 1)
7134             shiftLLong (left, result, MSB16);
7135           else
7136             {
7137               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7138               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7139               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7140               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7141             }
7142         }
7143     }
7144
7145   /* 1 <= shCount <= 7 */
7146   else if (shCount <= 2)
7147     {
7148       shiftLLong (left, result, LSB);
7149       if (shCount == 2)
7150         shiftLLong (result, result, LSB);
7151     }
7152   /* 3 <= shCount <= 7, optimize */
7153   else
7154     {
7155       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7156       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7157       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7158     }
7159 }
7160
7161 /*-----------------------------------------------------------------*/
7162 /* genLeftShiftLiteral - left shifting by known count              */
7163 /*-----------------------------------------------------------------*/
7164 static void
7165 genLeftShiftLiteral (operand * left,
7166                      operand * right,
7167                      operand * result,
7168                      iCode * ic)
7169 {
7170   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7171   int size;
7172
7173   D(emitcode (";     genLeftShiftLiteral",""));
7174
7175   freeAsmop (right, NULL, ic, TRUE);
7176
7177   aopOp (left, ic, FALSE);
7178   aopOp (result, ic, FALSE);
7179
7180   size = getSize (operandType (result));
7181
7182 #if VIEW_SIZE
7183   emitcode ("; shift left ", "result %d, left %d", size,
7184             AOP_SIZE (left));
7185 #endif
7186
7187   /* I suppose that the left size >= result size */
7188   if (shCount == 0)
7189     {
7190       while (size--)
7191         {
7192           movLeft2Result (left, size, result, size, 0);
7193         }
7194     }
7195
7196   else if (shCount >= (size * 8))
7197     while (size--)
7198       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7199   else
7200     {
7201       switch (size)
7202         {
7203         case 1:
7204           genlshOne (result, left, shCount);
7205           break;
7206
7207         case 2:
7208           genlshTwo (result, left, shCount);
7209           break;
7210
7211         case 4:
7212           genlshFour (result, left, shCount);
7213           break;
7214         default:
7215           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7216                   "*** ack! mystery literal shift!\n");
7217           break;
7218         }
7219     }
7220   freeAsmop (left, NULL, ic, TRUE);
7221   freeAsmop (result, NULL, ic, TRUE);
7222 }
7223
7224 /*-----------------------------------------------------------------*/
7225 /* genLeftShift - generates code for left shifting                 */
7226 /*-----------------------------------------------------------------*/
7227 static void
7228 genLeftShift (iCode * ic)
7229 {
7230   operand *left, *right, *result;
7231   int size, offset;
7232   char *l;
7233   symbol *tlbl, *tlbl1;
7234
7235   D(emitcode (";     genLeftShift",""));
7236
7237   right = IC_RIGHT (ic);
7238   left = IC_LEFT (ic);
7239   result = IC_RESULT (ic);
7240
7241   aopOp (right, ic, FALSE);
7242
7243   /* if the shift count is known then do it
7244      as efficiently as possible */
7245   if (AOP_TYPE (right) == AOP_LIT)
7246     {
7247       genLeftShiftLiteral (left, right, result, ic);
7248       return;
7249     }
7250
7251   /* shift count is unknown then we have to form
7252      a loop get the loop count in B : Note: we take
7253      only the lower order byte since shifting
7254      more that 32 bits make no sense anyway, ( the
7255      largest size of an object can be only 32 bits ) */
7256
7257   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7258   emitcode ("inc", "b");
7259   freeAsmop (right, NULL, ic, TRUE);
7260   aopOp (left, ic, FALSE);
7261   aopOp (result, ic, FALSE);
7262
7263   /* now move the left to the result if they are not the
7264      same */
7265   if (!sameRegs (AOP (left), AOP (result)) &&
7266       AOP_SIZE (result) > 1)
7267     {
7268
7269       size = AOP_SIZE (result);
7270       offset = 0;
7271       while (size--)
7272         {
7273           l = aopGet (AOP (left), offset, FALSE, TRUE);
7274           if (*l == '@' && (IS_AOP_PREG (result)))
7275             {
7276
7277               emitcode ("mov", "a,%s", l);
7278               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7279             }
7280           else
7281             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7282           offset++;
7283         }
7284     }
7285
7286   tlbl = newiTempLabel (NULL);
7287   size = AOP_SIZE (result);
7288   offset = 0;
7289   tlbl1 = newiTempLabel (NULL);
7290
7291   /* if it is only one byte then */
7292   if (size == 1)
7293     {
7294       symbol *tlbl1 = newiTempLabel (NULL);
7295
7296       l = aopGet (AOP (left), 0, FALSE, FALSE);
7297       MOVA (l);
7298       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7299       emitcode ("", "%05d$:", tlbl->key + 100);
7300       emitcode ("add", "a,acc");
7301       emitcode ("", "%05d$:", tlbl1->key + 100);
7302       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7303       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7304       goto release;
7305     }
7306
7307   reAdjustPreg (AOP (result));
7308
7309   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7310   emitcode ("", "%05d$:", tlbl->key + 100);
7311   l = aopGet (AOP (result), offset, FALSE, FALSE);
7312   MOVA (l);
7313   emitcode ("add", "a,acc");
7314   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7315   while (--size)
7316     {
7317       l = aopGet (AOP (result), offset, FALSE, FALSE);
7318       MOVA (l);
7319       emitcode ("rlc", "a");
7320       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7321     }
7322   reAdjustPreg (AOP (result));
7323
7324   emitcode ("", "%05d$:", tlbl1->key + 100);
7325   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7326 release:
7327   freeAsmop (left, NULL, ic, TRUE);
7328   freeAsmop (result, NULL, ic, TRUE);
7329 }
7330
7331 /*-----------------------------------------------------------------*/
7332 /* genrshOne - right shift a one byte quantity by known count      */
7333 /*-----------------------------------------------------------------*/
7334 static void
7335 genrshOne (operand * result, operand * left,
7336            int shCount, int sign)
7337 {
7338   D(emitcode (";     genrshOne",""));
7339
7340   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7341 }
7342
7343 /*-----------------------------------------------------------------*/
7344 /* genrshTwo - right shift two bytes by known amount != 0          */
7345 /*-----------------------------------------------------------------*/
7346 static void
7347 genrshTwo (operand * result, operand * left,
7348            int shCount, int sign)
7349 {
7350   D(emitcode (";     genrshTwo",""));
7351
7352   /* if shCount >= 8 */
7353   if (shCount >= 8)
7354     {
7355       shCount -= 8;
7356       if (shCount)
7357         shiftR1Left2Result (left, MSB16, result, LSB,
7358                             shCount, sign);
7359       else
7360         movLeft2Result (left, MSB16, result, LSB, sign);
7361       addSign (result, MSB16, sign);
7362     }
7363
7364   /*  1 <= shCount <= 7 */
7365   else
7366     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7367 }
7368
7369 /*-----------------------------------------------------------------*/
7370 /* shiftRLong - shift right one long from left to result           */
7371 /* offl = LSB or MSB16                                             */
7372 /*-----------------------------------------------------------------*/
7373 static void
7374 shiftRLong (operand * left, int offl,
7375             operand * result, int sign)
7376 {
7377   int isSameRegs=sameRegs(AOP(left),AOP(result));
7378
7379   if (isSameRegs && offl>1) {
7380     // we are in big trouble, but this shouldn't happen
7381     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7382   }
7383
7384   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7385
7386   if (offl==MSB16) {
7387     // shift is > 8
7388     if (sign) {
7389       emitcode ("rlc", "a");
7390       emitcode ("subb", "a,acc");
7391       if (isSameRegs)
7392         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7393       else {
7394         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7395         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7396       }
7397     } else {
7398       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7399     }
7400   }
7401
7402   if (!sign) {
7403     emitcode ("clr", "c");
7404   } else {
7405     emitcode ("mov", "c,acc.7");
7406   }
7407
7408   emitcode ("rrc", "a");
7409
7410   if (isSameRegs && offl==MSB16) {
7411     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7412   } else {
7413     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7414     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7415   }
7416
7417   emitcode ("rrc", "a");
7418   if (isSameRegs && offl==1) {
7419     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7420   } else {
7421     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7422     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7423   }
7424   emitcode ("rrc", "a");
7425   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7426
7427   if (offl == LSB)
7428     {
7429       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7430       emitcode ("rrc", "a");
7431       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7432     }
7433 }
7434
7435 /*-----------------------------------------------------------------*/
7436 /* genrshFour - shift four byte by a known amount != 0             */
7437 /*-----------------------------------------------------------------*/
7438 static void
7439 genrshFour (operand * result, operand * left,
7440             int shCount, int sign)
7441 {
7442   D(emitcode (";     genrshFour",""));
7443
7444   /* if shifting more that 3 bytes */
7445   if (shCount >= 24)
7446     {
7447       shCount -= 24;
7448       if (shCount)
7449         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7450       else
7451         movLeft2Result (left, MSB32, result, LSB, sign);
7452       addSign (result, MSB16, sign);
7453     }
7454   else if (shCount >= 16)
7455     {
7456       shCount -= 16;
7457       if (shCount)
7458         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7459       else
7460         {
7461           movLeft2Result (left, MSB24, result, LSB, 0);
7462           movLeft2Result (left, MSB32, result, MSB16, sign);
7463         }
7464       addSign (result, MSB24, sign);
7465     }
7466   else if (shCount >= 8)
7467     {
7468       shCount -= 8;
7469       if (shCount == 1)
7470         shiftRLong (left, MSB16, result, sign);
7471       else if (shCount == 0)
7472         {
7473           movLeft2Result (left, MSB16, result, LSB, 0);
7474           movLeft2Result (left, MSB24, result, MSB16, 0);
7475           movLeft2Result (left, MSB32, result, MSB24, sign);
7476           addSign (result, MSB32, sign);
7477         }
7478       else
7479         {
7480           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7481           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7482           /* the last shift is signed */
7483           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7484           addSign (result, MSB32, sign);
7485         }
7486     }
7487   else
7488     {                           /* 1 <= shCount <= 7 */
7489       if (shCount <= 2)
7490         {
7491           shiftRLong (left, LSB, result, sign);
7492           if (shCount == 2)
7493             shiftRLong (result, LSB, result, sign);
7494         }
7495       else
7496         {
7497           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7498           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7499           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7500         }
7501     }
7502 }
7503
7504 /*-----------------------------------------------------------------*/
7505 /* genRightShiftLiteral - right shifting by known count            */
7506 /*-----------------------------------------------------------------*/
7507 static void
7508 genRightShiftLiteral (operand * left,
7509                       operand * right,
7510                       operand * result,
7511                       iCode * ic,
7512                       int sign)
7513 {
7514   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7515   int size;
7516
7517   D(emitcode (";     genRightShiftLiteral",""));
7518
7519   freeAsmop (right, NULL, ic, TRUE);
7520
7521   aopOp (left, ic, FALSE);
7522   aopOp (result, ic, FALSE);
7523
7524 #if VIEW_SIZE
7525   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7526             AOP_SIZE (left));
7527 #endif
7528
7529   size = getDataSize (left);
7530   /* test the LEFT size !!! */
7531
7532   /* I suppose that the left size >= result size */
7533   if (shCount == 0)
7534     {
7535       size = getDataSize (result);
7536       while (size--)
7537         movLeft2Result (left, size, result, size, 0);
7538     }
7539
7540   else if (shCount >= (size * 8))
7541     {
7542       if (sign) {
7543         /* get sign in acc.7 */
7544         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7545       }
7546       addSign (result, LSB, sign);
7547     }
7548   else
7549     {
7550       switch (size)
7551         {
7552         case 1:
7553           genrshOne (result, left, shCount, sign);
7554           break;
7555
7556         case 2:
7557           genrshTwo (result, left, shCount, sign);
7558           break;
7559
7560         case 4:
7561           genrshFour (result, left, shCount, sign);
7562           break;
7563         default:
7564           break;
7565         }
7566     }
7567   freeAsmop (left, NULL, ic, TRUE);
7568   freeAsmop (result, NULL, ic, TRUE);
7569 }
7570
7571 /*-----------------------------------------------------------------*/
7572 /* genSignedRightShift - right shift of signed number              */
7573 /*-----------------------------------------------------------------*/
7574 static void
7575 genSignedRightShift (iCode * ic)
7576 {
7577   operand *right, *left, *result;
7578   int size, offset;
7579   char *l;
7580   symbol *tlbl, *tlbl1;
7581
7582   D(emitcode (";     genSignedRightShift",""));
7583
7584   /* we do it the hard way put the shift count in b
7585      and loop thru preserving the sign */
7586
7587   right = IC_RIGHT (ic);
7588   left = IC_LEFT (ic);
7589   result = IC_RESULT (ic);
7590
7591   aopOp (right, ic, FALSE);
7592
7593
7594   if (AOP_TYPE (right) == AOP_LIT)
7595     {
7596       genRightShiftLiteral (left, right, result, ic, 1);
7597       return;
7598     }
7599   /* shift count is unknown then we have to form
7600      a loop get the loop count in B : Note: we take
7601      only the lower order byte since shifting
7602      more that 32 bits make no sense anyway, ( the
7603      largest size of an object can be only 32 bits ) */
7604
7605   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7606   emitcode ("inc", "b");
7607   freeAsmop (right, NULL, ic, TRUE);
7608   aopOp (left, ic, FALSE);
7609   aopOp (result, ic, FALSE);
7610
7611   /* now move the left to the result if they are not the
7612      same */
7613   if (!sameRegs (AOP (left), AOP (result)) &&
7614       AOP_SIZE (result) > 1)
7615     {
7616
7617       size = AOP_SIZE (result);
7618       offset = 0;
7619       while (size--)
7620         {
7621           l = aopGet (AOP (left), offset, FALSE, TRUE);
7622           if (*l == '@' && IS_AOP_PREG (result))
7623             {
7624
7625               emitcode ("mov", "a,%s", l);
7626               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7627             }
7628           else
7629             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7630           offset++;
7631         }
7632     }
7633
7634   /* mov the highest order bit to OVR */
7635   tlbl = newiTempLabel (NULL);
7636   tlbl1 = newiTempLabel (NULL);
7637
7638   size = AOP_SIZE (result);
7639   offset = size - 1;
7640   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7641   emitcode ("rlc", "a");
7642   emitcode ("mov", "ov,c");
7643   /* if it is only one byte then */
7644   if (size == 1)
7645     {
7646       l = aopGet (AOP (left), 0, FALSE, FALSE);
7647       MOVA (l);
7648       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7649       emitcode ("", "%05d$:", tlbl->key + 100);
7650       emitcode ("mov", "c,ov");
7651       emitcode ("rrc", "a");
7652       emitcode ("", "%05d$:", tlbl1->key + 100);
7653       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7654       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7655       goto release;
7656     }
7657
7658   reAdjustPreg (AOP (result));
7659   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7660   emitcode ("", "%05d$:", tlbl->key + 100);
7661   emitcode ("mov", "c,ov");
7662   while (size--)
7663     {
7664       l = aopGet (AOP (result), offset, FALSE, FALSE);
7665       MOVA (l);
7666       emitcode ("rrc", "a");
7667       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7668     }
7669   reAdjustPreg (AOP (result));
7670   emitcode ("", "%05d$:", tlbl1->key + 100);
7671   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7672
7673 release:
7674   freeAsmop (left, NULL, ic, TRUE);
7675   freeAsmop (result, NULL, ic, TRUE);
7676 }
7677
7678 /*-----------------------------------------------------------------*/
7679 /* genRightShift - generate code for right shifting                */
7680 /*-----------------------------------------------------------------*/
7681 static void
7682 genRightShift (iCode * ic)
7683 {
7684   operand *right, *left, *result;
7685   sym_link *letype;
7686   int size, offset;
7687   char *l;
7688   symbol *tlbl, *tlbl1;
7689
7690   D(emitcode (";     genRightShift",""));
7691
7692   /* if signed then we do it the hard way preserve the
7693      sign bit moving it inwards */
7694   letype = getSpec (operandType (IC_LEFT (ic)));
7695
7696   if (!SPEC_USIGN (letype))
7697     {
7698       genSignedRightShift (ic);
7699       return;
7700     }
7701
7702   /* signed & unsigned types are treated the same : i.e. the
7703      signed is NOT propagated inwards : quoting from the
7704      ANSI - standard : "for E1 >> E2, is equivalent to division
7705      by 2**E2 if unsigned or if it has a non-negative value,
7706      otherwise the result is implementation defined ", MY definition
7707      is that the sign does not get propagated */
7708
7709   right = IC_RIGHT (ic);
7710   left = IC_LEFT (ic);
7711   result = IC_RESULT (ic);
7712
7713   aopOp (right, ic, FALSE);
7714
7715   /* if the shift count is known then do it
7716      as efficiently as possible */
7717   if (AOP_TYPE (right) == AOP_LIT)
7718     {
7719       genRightShiftLiteral (left, right, result, ic, 0);
7720       return;
7721     }
7722
7723   /* shift count is unknown then we have to form
7724      a loop get the loop count in B : Note: we take
7725      only the lower order byte since shifting
7726      more that 32 bits make no sense anyway, ( the
7727      largest size of an object can be only 32 bits ) */
7728
7729   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7730   emitcode ("inc", "b");
7731   freeAsmop (right, NULL, ic, TRUE);
7732   aopOp (left, ic, FALSE);
7733   aopOp (result, ic, FALSE);
7734
7735   /* now move the left to the result if they are not the
7736      same */
7737   if (!sameRegs (AOP (left), AOP (result)) &&
7738       AOP_SIZE (result) > 1)
7739     {
7740
7741       size = AOP_SIZE (result);
7742       offset = 0;
7743       while (size--)
7744         {
7745           l = aopGet (AOP (left), offset, FALSE, TRUE);
7746           if (*l == '@' && IS_AOP_PREG (result))
7747             {
7748
7749               emitcode ("mov", "a,%s", l);
7750               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7751             }
7752           else
7753             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7754           offset++;
7755         }
7756     }
7757
7758   tlbl = newiTempLabel (NULL);
7759   tlbl1 = newiTempLabel (NULL);
7760   size = AOP_SIZE (result);
7761   offset = size - 1;
7762
7763   /* if it is only one byte then */
7764   if (size == 1)
7765     {
7766       l = aopGet (AOP (left), 0, FALSE, FALSE);
7767       MOVA (l);
7768       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7769       emitcode ("", "%05d$:", tlbl->key + 100);
7770       CLRC;
7771       emitcode ("rrc", "a");
7772       emitcode ("", "%05d$:", tlbl1->key + 100);
7773       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7774       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7775       goto release;
7776     }
7777
7778   reAdjustPreg (AOP (result));
7779   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7780   emitcode ("", "%05d$:", tlbl->key + 100);
7781   CLRC;
7782   while (size--)
7783     {
7784       l = aopGet (AOP (result), offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rrc", "a");
7787       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7788     }
7789   reAdjustPreg (AOP (result));
7790
7791   emitcode ("", "%05d$:", tlbl1->key + 100);
7792   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7793
7794 release:
7795   freeAsmop (left, NULL, ic, TRUE);
7796   freeAsmop (result, NULL, ic, TRUE);
7797 }
7798
7799 /*-----------------------------------------------------------------*/
7800 /* emitPtrByteGet - emits code to get a byte into A through a      */
7801 /*                  pointer register (R0, R1, or DPTR). The        */
7802 /*                  original value of A can be preserved in B.     */
7803 /*-----------------------------------------------------------------*/
7804 static void
7805 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
7806 {
7807   switch (p_type)
7808     {
7809     case IPOINTER:
7810     case POINTER:
7811       if (preserveAinB)
7812         emitcode ("mov", "b,a");
7813       emitcode ("mov", "a,@%s", rname);
7814       break;
7815
7816     case PPOINTER:
7817       if (preserveAinB)
7818         emitcode ("mov", "b,a");
7819       emitcode ("movx", "a,@%s", rname);
7820       break;
7821
7822     case FPOINTER:
7823       if (preserveAinB)
7824         emitcode ("mov", "b,a");
7825       emitcode ("movx", "a,@dptr");
7826       break;
7827
7828     case CPOINTER:
7829       if (preserveAinB)
7830         emitcode ("mov", "b,a");
7831       emitcode ("clr", "a");
7832       emitcode ("movc", "a,@a+dptr");
7833       break;
7834
7835     case GPOINTER:
7836       if (preserveAinB)
7837         {
7838           emitcode ("push", "b");
7839           emitcode ("push", "acc");
7840         }
7841       emitcode ("lcall", "__gptrget");
7842       if (preserveAinB)
7843         emitcode ("pop", "b");
7844       break;
7845     }
7846 }
7847
7848 /*-----------------------------------------------------------------*/
7849 /* emitPtrByteSet - emits code to set a byte from src through a    */
7850 /*                  pointer register (R0, R1, or DPTR).            */
7851 /*-----------------------------------------------------------------*/
7852 static void
7853 emitPtrByteSet (char *rname, int p_type, char *src)
7854 {
7855   switch (p_type)
7856     {
7857     case IPOINTER:
7858     case POINTER:
7859       if (*src=='@')
7860         {
7861           MOVA (src);
7862           emitcode ("mov", "@%s,a", rname);
7863         }
7864       else
7865         emitcode ("mov", "@%s,%s", rname, src);
7866       break;
7867
7868     case PPOINTER:
7869       MOVA (src);
7870       emitcode ("movx", "@%s,a", rname);
7871       break;
7872
7873     case FPOINTER:
7874       MOVA (src);
7875       emitcode ("movx", "@dptr,a");
7876       break;
7877
7878     case GPOINTER:
7879       MOVA (src);
7880       emitcode ("lcall", "__gptrput");
7881       break;
7882     }
7883 }
7884
7885 /*-----------------------------------------------------------------*/
7886 /* genUnpackBits - generates code for unpacking bits               */
7887 /*-----------------------------------------------------------------*/
7888 static void
7889 genUnpackBits (operand * result, char *rname, int ptype)
7890 {
7891   int offset = 0;       /* result byte offset */
7892   int rsize;            /* result size */
7893   int rlen = 0;         /* remaining bitfield length */
7894   sym_link *etype;      /* bitfield type information */
7895   int blen;             /* bitfield length */
7896   int bstr;             /* bitfield starting bit within byte */
7897
7898   D(emitcode (";     genUnpackBits",""));
7899
7900   etype = getSpec (operandType (result));
7901   rsize = getSize (operandType (result));
7902   blen = SPEC_BLEN (etype);
7903   bstr = SPEC_BSTR (etype);
7904
7905   /* If the bitfield length is less than a byte */
7906   if (blen < 8)
7907     {
7908       emitPtrByteGet (rname, ptype, FALSE);
7909       AccRsh (bstr);
7910       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
7911       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7912       goto finish;
7913     }
7914
7915   /* Bit field did not fit in a byte. Copy all
7916      but the partial byte at the end.  */
7917   for (rlen=blen;rlen>=8;rlen-=8)
7918     {
7919       emitPtrByteGet (rname, ptype, FALSE);
7920       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7921       if (rlen>8)
7922         emitcode ("inc", "%s", rname);
7923     }
7924
7925   /* Handle the partial byte at the end */
7926   if (rlen)
7927     {
7928       emitPtrByteGet (rname, ptype, FALSE);
7929       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
7930       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7931     }
7932
7933 finish:
7934   if (offset < rsize)
7935     {
7936       rsize -= offset;
7937       while (rsize--)
7938         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
7939     }
7940 }
7941
7942
7943 /*-----------------------------------------------------------------*/
7944 /* genDataPointerGet - generates code when ptr offset is known     */
7945 /*-----------------------------------------------------------------*/
7946 static void
7947 genDataPointerGet (operand * left,
7948                    operand * result,
7949                    iCode * ic)
7950 {
7951   char *l;
7952   char buffer[256];
7953   int size, offset = 0;
7954
7955   D(emitcode (";     genDataPointerGet",""));
7956
7957   aopOp (result, ic, TRUE);
7958
7959   /* get the string representation of the name */
7960   l = aopGet (AOP (left), 0, FALSE, TRUE);
7961   size = AOP_SIZE (result);
7962   while (size--)
7963     {
7964       if (offset)
7965         sprintf (buffer, "(%s + %d)", l + 1, offset);
7966       else
7967         sprintf (buffer, "%s", l + 1);
7968       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
7969     }
7970
7971   freeAsmop (left, NULL, ic, TRUE);
7972   freeAsmop (result, NULL, ic, TRUE);
7973 }
7974
7975 /*-----------------------------------------------------------------*/
7976 /* genNearPointerGet - emitcode for near pointer fetch             */
7977 /*-----------------------------------------------------------------*/
7978 static void
7979 genNearPointerGet (operand * left,
7980                    operand * result,
7981                    iCode * ic,
7982                    iCode * pi)
7983 {
7984   asmop *aop = NULL;
7985   regs *preg = NULL;
7986   char *rname;
7987   sym_link *rtype, *retype;
7988   sym_link *ltype = operandType (left);
7989   char buffer[80];
7990
7991   D(emitcode (";     genNearPointerGet",""));
7992
7993   rtype = operandType (result);
7994   retype = getSpec (rtype);
7995
7996   aopOp (left, ic, FALSE);
7997
7998   /* if left is rematerialisable and
7999      result is not bitfield variable type and
8000      the left is pointer to data space i.e
8001      lower 128 bytes of space */
8002   if (AOP_TYPE (left) == AOP_IMMD &&
8003       !IS_BITFIELD (retype) &&
8004       DCL_TYPE (ltype) == POINTER)
8005     {
8006       genDataPointerGet (left, result, ic);
8007       return;
8008     }
8009
8010  /* if the value is already in a pointer register
8011      then don't need anything more */
8012   if (!AOP_INPREG (AOP (left)))
8013     {
8014       if (IS_AOP_PREG (left))
8015         {
8016           // Aha, it is a pointer, just in disguise.
8017           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8018           if (*rname != '@')
8019             {
8020               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8021                       __FILE__, __LINE__);
8022             }
8023           else
8024             {
8025               // Expected case.
8026               emitcode ("mov", "a%s,%s", rname + 1, rname);
8027               rname++;  // skip the '@'.
8028             }
8029         }
8030       else
8031         {
8032           /* otherwise get a free pointer register */
8033           aop = newAsmop (0);
8034           preg = getFreePtr (ic, &aop, FALSE);
8035           emitcode ("mov", "%s,%s",
8036                     preg->name,
8037                     aopGet (AOP (left), 0, FALSE, TRUE));
8038           rname = preg->name;
8039         }
8040     }
8041   else
8042     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8043
8044   //aopOp (result, ic, FALSE);
8045   aopOp (result, ic, result?TRUE:FALSE);
8046
8047   /* if bitfield then unpack the bits */
8048   if (IS_BITFIELD (retype))
8049     genUnpackBits (result, rname, POINTER);
8050   else
8051     {
8052       /* we have can just get the values */
8053       int size = AOP_SIZE (result);
8054       int offset = 0;
8055
8056       while (size--)
8057         {
8058           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8059             {
8060
8061               emitcode ("mov", "a,@%s", rname);
8062               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8063             }
8064           else
8065             {
8066               sprintf (buffer, "@%s", rname);
8067               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8068             }
8069           offset++;
8070           if (size || pi)
8071             emitcode ("inc", "%s", rname);
8072         }
8073     }
8074
8075   /* now some housekeeping stuff */
8076   if (aop)       /* we had to allocate for this iCode */
8077     {
8078       if (pi) { /* post increment present */
8079         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8080       }
8081       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8082     }
8083   else
8084     {
8085       /* we did not allocate which means left
8086          already in a pointer register, then
8087          if size > 0 && this could be used again
8088          we have to point it back to where it
8089          belongs */
8090       if ((AOP_SIZE (result) > 1 &&
8091            !OP_SYMBOL (left)->remat &&
8092            (OP_SYMBOL (left)->liveTo > ic->seq ||
8093             ic->depth)) &&
8094           !pi)
8095         {
8096           int size = AOP_SIZE (result) - 1;
8097           while (size--)
8098             emitcode ("dec", "%s", rname);
8099         }
8100     }
8101
8102   /* done */
8103   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8104   freeAsmop (left, NULL, ic, TRUE);
8105   if (pi) pi->generated = 1;
8106 }
8107
8108 /*-----------------------------------------------------------------*/
8109 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8110 /*-----------------------------------------------------------------*/
8111 static void
8112 genPagedPointerGet (operand * left,
8113                     operand * result,
8114                     iCode * ic,
8115                     iCode *pi)
8116 {
8117   asmop *aop = NULL;
8118   regs *preg = NULL;
8119   char *rname;
8120   sym_link *rtype, *retype;
8121
8122   D(emitcode (";     genPagedPointerGet",""));
8123
8124   rtype = operandType (result);
8125   retype = getSpec (rtype);
8126
8127   aopOp (left, ic, FALSE);
8128
8129   /* if the value is already in a pointer register
8130      then don't need anything more */
8131   if (!AOP_INPREG (AOP (left)))
8132     {
8133       /* otherwise get a free pointer register */
8134       aop = newAsmop (0);
8135       preg = getFreePtr (ic, &aop, FALSE);
8136       emitcode ("mov", "%s,%s",
8137                 preg->name,
8138                 aopGet (AOP (left), 0, FALSE, TRUE));
8139       rname = preg->name;
8140     }
8141   else
8142     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8143
8144   aopOp (result, ic, FALSE);
8145
8146   /* if bitfield then unpack the bits */
8147   if (IS_BITFIELD (retype))
8148     genUnpackBits (result, rname, PPOINTER);
8149   else
8150     {
8151       /* we have can just get the values */
8152       int size = AOP_SIZE (result);
8153       int offset = 0;
8154
8155       while (size--)
8156         {
8157
8158           emitcode ("movx", "a,@%s", rname);
8159           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8160
8161           offset++;
8162
8163           if (size || pi)
8164             emitcode ("inc", "%s", rname);
8165         }
8166     }
8167
8168   /* now some housekeeping stuff */
8169   if (aop) /* we had to allocate for this iCode */
8170     {
8171       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8172       freeAsmop (NULL, aop, ic, TRUE);
8173     }
8174   else
8175     {
8176       /* we did not allocate which means left
8177          already in a pointer register, then
8178          if size > 0 && this could be used again
8179          we have to point it back to where it
8180          belongs */
8181       if ((AOP_SIZE (result) > 1 &&
8182            !OP_SYMBOL (left)->remat &&
8183            (OP_SYMBOL (left)->liveTo > ic->seq ||
8184             ic->depth)) &&
8185           !pi)
8186         {
8187           int size = AOP_SIZE (result) - 1;
8188           while (size--)
8189             emitcode ("dec", "%s", rname);
8190         }
8191     }
8192
8193   /* done */
8194   freeAsmop (left, NULL, ic, TRUE);
8195   freeAsmop (result, NULL, ic, TRUE);
8196   if (pi) pi->generated = 1;
8197
8198 }
8199
8200 /*--------------------------------------------------------------------*/
8201 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8202 /*--------------------------------------------------------------------*/
8203 static void
8204 loadDptrFromOperand (operand *op, bool loadBToo)
8205 {
8206   if (AOP_TYPE (op) != AOP_STR)
8207     {
8208       /* if this is remateriazable */
8209       if (AOP_TYPE (op) == AOP_IMMD)
8210         {
8211           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8212           if (loadBToo)
8213             {
8214               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8215                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8216               else
8217                 {
8218                   wassertl(FALSE, "need pointerCode");
8219                   emitcode ("", "; mov b,???");
8220                   /* genPointerGet and genPointerSet originally did different
8221                   ** things for this case. Both seem wrong.
8222                   ** from genPointerGet:
8223                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8224                   ** from genPointerSet:
8225                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8226                   */
8227                 }
8228             }
8229         }
8230       else if (AOP_TYPE (op) == AOP_DPTR)
8231         {
8232           if (loadBToo)
8233             {
8234               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8235               emitcode ("push", "acc");
8236               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8237               emitcode ("push", "acc");
8238               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8239               emitcode ("pop", "dph");
8240               emitcode ("pop", "dpl");
8241             }
8242           else
8243             {
8244               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8245               emitcode ("push", "acc");
8246               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8247               emitcode ("pop", "dpl");
8248             }
8249         }
8250       else
8251         {                       /* we need to get it byte by byte */
8252           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8253           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8254           if (loadBToo)
8255             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8256         }
8257     }
8258 }
8259
8260 /*-----------------------------------------------------------------*/
8261 /* genFarPointerGet - gget value from far space                    */
8262 /*-----------------------------------------------------------------*/
8263 static void
8264 genFarPointerGet (operand * left,
8265                   operand * result, iCode * ic, iCode * pi)
8266 {
8267   int size, offset;
8268   sym_link *retype = getSpec (operandType (result));
8269
8270   D(emitcode (";     genFarPointerGet",""));
8271
8272   aopOp (left, ic, FALSE);
8273   loadDptrFromOperand (left, FALSE);
8274
8275   /* so dptr now contains the address */
8276   aopOp (result, ic, FALSE);
8277
8278   /* if bit then unpack */
8279   if (IS_BITFIELD (retype))
8280     genUnpackBits (result, "dptr", FPOINTER);
8281   else
8282     {
8283       size = AOP_SIZE (result);
8284       offset = 0;
8285
8286       while (size--)
8287         {
8288           emitcode ("movx", "a,@dptr");
8289           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8290           if (size || pi)
8291             emitcode ("inc", "dptr");
8292         }
8293     }
8294
8295   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8296     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8297     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8298     pi->generated = 1;
8299   }
8300   freeAsmop (left, NULL, ic, TRUE);
8301   freeAsmop (result, NULL, ic, TRUE);
8302 }
8303
8304 /*-----------------------------------------------------------------*/
8305 /* genCodePointerGet - gget value from code space                  */
8306 /*-----------------------------------------------------------------*/
8307 static void
8308 genCodePointerGet (operand * left,
8309                     operand * result, iCode * ic, iCode *pi)
8310 {
8311   int size, offset;
8312   sym_link *retype = getSpec (operandType (result));
8313
8314   D(emitcode (";     genCodePointerGet",""));
8315
8316   aopOp (left, ic, FALSE);
8317   loadDptrFromOperand (left, FALSE);
8318
8319   /* so dptr now contains the address */
8320   aopOp (result, ic, FALSE);
8321
8322   /* if bit then unpack */
8323   if (IS_BITFIELD (retype))
8324     genUnpackBits (result, "dptr", CPOINTER);
8325   else
8326     {
8327       size = AOP_SIZE (result);
8328       offset = 0;
8329
8330       while (size--)
8331         {
8332           if (pi)
8333             {
8334               emitcode ("clr", "a");
8335               emitcode ("movc", "a,@a+dptr");
8336               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8337               emitcode ("inc", "dptr");
8338             }
8339           else
8340             {
8341               emitcode ("mov", "a,#0x%02x", offset);
8342               emitcode ("movc", "a,@a+dptr");
8343               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8344             }
8345         }
8346     }
8347
8348   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8349     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8350     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8351     pi->generated = 1;
8352   }
8353   freeAsmop (left, NULL, ic, TRUE);
8354   freeAsmop (result, NULL, ic, TRUE);
8355 }
8356
8357 /*-----------------------------------------------------------------*/
8358 /* genGenPointerGet - gget value from generic pointer space        */
8359 /*-----------------------------------------------------------------*/
8360 static void
8361 genGenPointerGet (operand * left,
8362                   operand * result, iCode * ic, iCode *pi)
8363 {
8364   int size, offset;
8365   sym_link *retype = getSpec (operandType (result));
8366
8367   D(emitcode (";     genGenPointerGet",""));
8368
8369   aopOp (left, ic, FALSE);
8370   loadDptrFromOperand (left, TRUE);
8371
8372   /* so dptr know contains the address */
8373   aopOp (result, ic, FALSE);
8374
8375   /* if bit then unpack */
8376   if (IS_BITFIELD (retype))
8377     genUnpackBits (result, "dptr", GPOINTER);
8378   else
8379     {
8380       size = AOP_SIZE (result);
8381       offset = 0;
8382
8383       while (size--)
8384         {
8385           emitcode ("lcall", "__gptrget");
8386           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8387           if (size || pi)
8388             emitcode ("inc", "dptr");
8389         }
8390     }
8391
8392   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8393     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8394     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8395     pi->generated = 1;
8396   }
8397   freeAsmop (left, NULL, ic, TRUE);
8398   freeAsmop (result, NULL, ic, TRUE);
8399 }
8400
8401 /*-----------------------------------------------------------------*/
8402 /* genPointerGet - generate code for pointer get                   */
8403 /*-----------------------------------------------------------------*/
8404 static void
8405 genPointerGet (iCode * ic, iCode *pi)
8406 {
8407   operand *left, *result;
8408   sym_link *type, *etype;
8409   int p_type;
8410
8411   D(emitcode (";     genPointerGet",""));
8412
8413   left = IC_LEFT (ic);
8414   result = IC_RESULT (ic);
8415
8416   /* depending on the type of pointer we need to
8417      move it to the correct pointer register */
8418   type = operandType (left);
8419   etype = getSpec (type);
8420   /* if left is of type of pointer then it is simple */
8421   if (IS_PTR (type) && !IS_FUNC (type->next))
8422     p_type = DCL_TYPE (type);
8423   else
8424     {
8425       /* we have to go by the storage class */
8426       p_type = PTR_TYPE (SPEC_OCLS (etype));
8427     }
8428
8429   /* special case when cast remat */
8430   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8431       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8432           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8433           type = operandType (left);
8434           p_type = DCL_TYPE (type);
8435   }
8436   /* now that we have the pointer type we assign
8437      the pointer values */
8438   switch (p_type)
8439     {
8440
8441     case POINTER:
8442     case IPOINTER:
8443       genNearPointerGet (left, result, ic, pi);
8444       break;
8445
8446     case PPOINTER:
8447       genPagedPointerGet (left, result, ic, pi);
8448       break;
8449
8450     case FPOINTER:
8451       genFarPointerGet (left, result, ic, pi);
8452       break;
8453
8454     case CPOINTER:
8455       genCodePointerGet (left, result, ic, pi);
8456       break;
8457
8458     case GPOINTER:
8459       genGenPointerGet (left, result, ic, pi);
8460       break;
8461     }
8462
8463 }
8464
8465
8466
8467 /*-----------------------------------------------------------------*/
8468 /* genPackBits - generates code for packed bit storage             */
8469 /*-----------------------------------------------------------------*/
8470 static void
8471 genPackBits (sym_link * etype,
8472              operand * right,
8473              char *rname, int p_type)
8474 {
8475   int offset = 0;       /* source byte offset */
8476   int rlen = 0;         /* remaining bitfield length */
8477   int blen;             /* bitfield length */
8478   int bstr;             /* bitfield starting bit within byte */
8479   int litval;           /* source literal value (if AOP_LIT) */
8480   unsigned char mask;   /* bitmask within current byte */
8481
8482   D(emitcode (";     genPackBits",""));
8483
8484   blen = SPEC_BLEN (etype);
8485   bstr = SPEC_BSTR (etype);
8486
8487   /* If the bitfield length is less than a byte */
8488   if (blen < 8)
8489     {
8490       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8491               (unsigned char) (0xFF >> (8 - bstr)));
8492
8493       if (AOP_TYPE (right) == AOP_LIT)
8494         {
8495           /* Case with a bitfield length <8 and literal source
8496           */
8497           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8498           litval <<= bstr;
8499           litval &= (~mask) & 0xff;
8500           emitPtrByteGet (rname, p_type, FALSE);
8501           if ((mask|litval)!=0xff)
8502             emitcode ("anl","a,#0x%02x", mask);
8503           if (litval)
8504             emitcode ("orl","a,#0x%02x", litval);
8505         }
8506       else
8507         {
8508           if ((blen==1) && (p_type!=GPOINTER))
8509             {
8510               /* Case with a bitfield length == 1 and no generic pointer
8511               */
8512               if (AOP_TYPE (right) == AOP_CRY)
8513                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8514               else
8515                 {
8516                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8517                   emitcode ("rrc","a");
8518                 }
8519               emitPtrByteGet (rname, p_type, FALSE);
8520               emitcode ("mov","acc.%d,c",bstr);
8521             }
8522           else
8523             {
8524               /* Case with a bitfield length < 8 and arbitrary source
8525               */
8526               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8527               /* shift and mask source value */
8528               AccLsh (bstr);
8529               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8530
8531               /* transfer A to B and get next byte */
8532               emitPtrByteGet (rname, p_type, TRUE);
8533
8534               emitcode ("anl", "a,#0x%02x", mask);
8535               emitcode ("orl", "a,b");
8536               if (p_type == GPOINTER)
8537                 emitcode ("pop", "b");
8538            }
8539         }
8540
8541       emitPtrByteSet (rname, p_type, "a");
8542       return;
8543     }
8544
8545   /* Bit length is greater than 7 bits. In this case, copy  */
8546   /* all except the partial byte at the end                 */
8547   for (rlen=blen;rlen>=8;rlen-=8)
8548     {
8549       emitPtrByteSet (rname, p_type,
8550                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8551       if (rlen>8)
8552         emitcode ("inc", "%s", rname);
8553     }
8554
8555   /* If there was a partial byte at the end */
8556   if (rlen)
8557     {
8558       mask = (((unsigned char) -1 << rlen) & 0xff);
8559
8560       if (AOP_TYPE (right) == AOP_LIT)
8561         {
8562           /* Case with partial byte and literal source
8563           */
8564           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8565           litval >>= (blen-rlen);
8566           litval &= (~mask) & 0xff;
8567           emitPtrByteGet (rname, p_type, FALSE);
8568           if ((mask|litval)!=0xff)
8569             emitcode ("anl","a,#0x%02x", mask);
8570           if (litval)
8571             emitcode ("orl","a,#0x%02x", litval);
8572         }
8573       else
8574         {
8575           /* Case with partial byte and arbitrary source
8576           */
8577           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8578           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8579
8580           /* transfer A to B and get next byte */
8581           emitPtrByteGet (rname, p_type, TRUE);
8582
8583           emitcode ("anl", "a,#0x%02x", mask);
8584           emitcode ("orl", "a,b");
8585           if (p_type == GPOINTER)
8586             emitcode ("pop", "b");
8587         }
8588       emitPtrByteSet (rname, p_type, "a");
8589     }
8590
8591 }
8592
8593
8594 /*-----------------------------------------------------------------*/
8595 /* genDataPointerSet - remat pointer to data space                 */
8596 /*-----------------------------------------------------------------*/
8597 static void
8598 genDataPointerSet (operand * right,
8599                    operand * result,
8600                    iCode * ic)
8601 {
8602   int size, offset = 0;
8603   char *l, buffer[256];
8604
8605   D(emitcode (";     genDataPointerSet",""));
8606
8607   aopOp (right, ic, FALSE);
8608
8609   l = aopGet (AOP (result), 0, FALSE, TRUE);
8610   size = AOP_SIZE (right);
8611   while (size--)
8612     {
8613       if (offset)
8614         sprintf (buffer, "(%s + %d)", l + 1, offset);
8615       else
8616         sprintf (buffer, "%s", l + 1);
8617       emitcode ("mov", "%s,%s", buffer,
8618                 aopGet (AOP (right), offset++, FALSE, FALSE));
8619     }
8620
8621   freeAsmop (right, NULL, ic, TRUE);
8622   freeAsmop (result, NULL, ic, TRUE);
8623 }
8624
8625 /*-----------------------------------------------------------------*/
8626 /* genNearPointerSet - emitcode for near pointer put                */
8627 /*-----------------------------------------------------------------*/
8628 static void
8629 genNearPointerSet (operand * right,
8630                    operand * result,
8631                    iCode * ic,
8632                    iCode * pi)
8633 {
8634   asmop *aop = NULL;
8635   regs *preg = NULL;
8636   char *rname, *l;
8637   sym_link *retype, *letype;
8638   sym_link *ptype = operandType (result);
8639
8640   D(emitcode (";     genNearPointerSet",""));
8641
8642   retype = getSpec (operandType (right));
8643   letype = getSpec (ptype);
8644   aopOp (result, ic, FALSE);
8645
8646   /* if the result is rematerializable &
8647      in data space & not a bit variable */
8648   if (AOP_TYPE (result) == AOP_IMMD &&
8649       DCL_TYPE (ptype) == POINTER &&
8650       !IS_BITVAR (retype) &&
8651       !IS_BITVAR (letype))
8652     {
8653       genDataPointerSet (right, result, ic);
8654       return;
8655     }
8656
8657   /* if the value is already in a pointer register
8658      then don't need anything more */
8659   if (!AOP_INPREG (AOP (result)))
8660     {
8661         if (
8662             //AOP_TYPE (result) == AOP_STK
8663             IS_AOP_PREG(result)
8664             )
8665         {
8666             // Aha, it is a pointer, just in disguise.
8667             rname = aopGet (AOP (result), 0, FALSE, FALSE);
8668             if (*rname != '@')
8669             {
8670                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8671                         __FILE__, __LINE__);
8672             }
8673             else
8674             {
8675                 // Expected case.
8676                 emitcode ("mov", "a%s,%s", rname + 1, rname);
8677                 rname++;  // skip the '@'.
8678             }
8679         }
8680         else
8681         {
8682             /* otherwise get a free pointer register */
8683             aop = newAsmop (0);
8684             preg = getFreePtr (ic, &aop, FALSE);
8685             emitcode ("mov", "%s,%s",
8686                       preg->name,
8687                       aopGet (AOP (result), 0, FALSE, TRUE));
8688             rname = preg->name;
8689         }
8690     }
8691     else
8692     {
8693         rname = aopGet (AOP (result), 0, FALSE, FALSE);
8694     }
8695
8696   aopOp (right, ic, FALSE);
8697
8698   /* if bitfield then unpack the bits */
8699   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8700     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
8701   else
8702     {
8703       /* we have can just get the values */
8704       int size = AOP_SIZE (right);
8705       int offset = 0;
8706
8707       while (size--)
8708         {
8709           l = aopGet (AOP (right), offset, FALSE, TRUE);
8710           if (*l == '@')
8711             {
8712               MOVA (l);
8713               emitcode ("mov", "@%s,a", rname);
8714             }
8715           else
8716             emitcode ("mov", "@%s,%s", rname, l);
8717           if (size || pi)
8718             emitcode ("inc", "%s", rname);
8719           offset++;
8720         }
8721     }
8722
8723   /* now some housekeeping stuff */
8724   if (aop) /* we had to allocate for this iCode */
8725     {
8726       if (pi)
8727         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8728       freeAsmop (NULL, aop, ic, TRUE);
8729     }
8730   else
8731     {
8732       /* we did not allocate which means left
8733          already in a pointer register, then
8734          if size > 0 && this could be used again
8735          we have to point it back to where it
8736          belongs */
8737       if ((AOP_SIZE (right) > 1 &&
8738            !OP_SYMBOL (result)->remat &&
8739            (OP_SYMBOL (result)->liveTo > ic->seq ||
8740             ic->depth)) &&
8741           !pi)
8742         {
8743           int size = AOP_SIZE (right) - 1;
8744           while (size--)
8745             emitcode ("dec", "%s", rname);
8746         }
8747     }
8748
8749   /* done */
8750   if (pi) pi->generated = 1;
8751   freeAsmop (result, NULL, ic, TRUE);
8752   freeAsmop (right, NULL, ic, TRUE);
8753 }
8754
8755 /*-----------------------------------------------------------------*/
8756 /* genPagedPointerSet - emitcode for Paged pointer put             */
8757 /*-----------------------------------------------------------------*/
8758 static void
8759 genPagedPointerSet (operand * right,
8760                     operand * result,
8761                     iCode * ic,
8762                     iCode * pi)
8763 {
8764   asmop *aop = NULL;
8765   regs *preg = NULL;
8766   char *rname, *l;
8767   sym_link *retype, *letype;
8768
8769   D(emitcode (";     genPagedPointerSet",""));
8770
8771   retype = getSpec (operandType (right));
8772   letype = getSpec (operandType (result));
8773
8774   aopOp (result, ic, FALSE);
8775
8776   /* if the value is already in a pointer register
8777      then don't need anything more */
8778   if (!AOP_INPREG (AOP (result)))
8779     {
8780       /* otherwise get a free pointer register */
8781       aop = newAsmop (0);
8782       preg = getFreePtr (ic, &aop, FALSE);
8783       emitcode ("mov", "%s,%s",
8784                 preg->name,
8785                 aopGet (AOP (result), 0, FALSE, TRUE));
8786       rname = preg->name;
8787     }
8788   else
8789     rname = aopGet (AOP (result), 0, FALSE, FALSE);
8790
8791   aopOp (right, ic, FALSE);
8792
8793   /* if bitfield then unpack the bits */
8794   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8795     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
8796   else
8797     {
8798       /* we have can just get the values */
8799       int size = AOP_SIZE (right);
8800       int offset = 0;
8801
8802       while (size--)
8803         {
8804           l = aopGet (AOP (right), offset, FALSE, TRUE);
8805
8806           MOVA (l);
8807           emitcode ("movx", "@%s,a", rname);
8808
8809           if (size || pi)
8810             emitcode ("inc", "%s", rname);
8811
8812           offset++;
8813         }
8814     }
8815
8816   /* now some housekeeping stuff */
8817   if (aop) /* we had to allocate for this iCode */
8818     {
8819       if (pi)
8820         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8821       freeAsmop (NULL, aop, ic, TRUE);
8822     }
8823   else
8824     {
8825       /* we did not allocate which means left
8826          already in a pointer register, then
8827          if size > 0 && this could be used again
8828          we have to point it back to where it
8829          belongs */
8830       if (AOP_SIZE (right) > 1 &&
8831           !OP_SYMBOL (result)->remat &&
8832           (OP_SYMBOL (result)->liveTo > ic->seq ||
8833            ic->depth))
8834         {
8835           int size = AOP_SIZE (right) - 1;
8836           while (size--)
8837             emitcode ("dec", "%s", rname);
8838         }
8839     }
8840
8841   /* done */
8842   if (pi) pi->generated = 1;
8843   freeAsmop (result, NULL, ic, TRUE);
8844   freeAsmop (right, NULL, ic, TRUE);
8845
8846
8847 }
8848
8849 /*-----------------------------------------------------------------*/
8850 /* genFarPointerSet - set value from far space                     */
8851 /*-----------------------------------------------------------------*/
8852 static void
8853 genFarPointerSet (operand * right,
8854                   operand * result, iCode * ic, iCode * pi)
8855 {
8856   int size, offset;
8857   sym_link *retype = getSpec (operandType (right));
8858   sym_link *letype = getSpec (operandType (result));
8859
8860   D(emitcode (";     genFarPointerSet",""));
8861
8862   aopOp (result, ic, FALSE);
8863   loadDptrFromOperand (result, FALSE);
8864
8865   /* so dptr know contains the address */
8866   aopOp (right, ic, FALSE);
8867
8868   /* if bit then unpack */
8869   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8870     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
8871   else
8872     {
8873       size = AOP_SIZE (right);
8874       offset = 0;
8875
8876       while (size--)
8877         {
8878           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
8879           MOVA (l);
8880           emitcode ("movx", "@dptr,a");
8881           if (size || pi)
8882             emitcode ("inc", "dptr");
8883         }
8884     }
8885   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
8886     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
8887     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
8888     pi->generated=1;
8889   }
8890   freeAsmop (result, NULL, ic, TRUE);
8891   freeAsmop (right, NULL, ic, TRUE);
8892 }
8893
8894 /*-----------------------------------------------------------------*/
8895 /* genGenPointerSet - set value from generic pointer space         */
8896 /*-----------------------------------------------------------------*/
8897 static void
8898 genGenPointerSet (operand * right,
8899                   operand * result, iCode * ic, iCode * pi)
8900 {
8901   int size, offset;
8902   sym_link *retype = getSpec (operandType (right));
8903   sym_link *letype = getSpec (operandType (result));
8904
8905   D(emitcode (";     genGenPointerSet",""));
8906
8907   aopOp (result, ic, FALSE);
8908   loadDptrFromOperand (result, TRUE);
8909
8910   /* so dptr know contains the address */
8911   aopOp (right, ic, FALSE);
8912
8913   /* if bit then unpack */
8914   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8915     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
8916   else
8917     {
8918       size = AOP_SIZE (right);
8919       offset = 0;
8920
8921       while (size--)
8922         {
8923           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
8924           MOVA (l);
8925           emitcode ("lcall", "__gptrput");
8926           if (size || pi)
8927             emitcode ("inc", "dptr");
8928         }
8929     }
8930
8931   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
8932     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
8933     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
8934     pi->generated=1;
8935   }
8936   freeAsmop (result, NULL, ic, TRUE);
8937   freeAsmop (right, NULL, ic, TRUE);
8938 }
8939
8940 /*-----------------------------------------------------------------*/
8941 /* genPointerSet - stores the value into a pointer location        */
8942 /*-----------------------------------------------------------------*/
8943 static void
8944 genPointerSet (iCode * ic, iCode *pi)
8945 {
8946   operand *right, *result;
8947   sym_link *type, *etype;
8948   int p_type;
8949
8950   D(emitcode (";     genPointerSet",""));
8951
8952   right = IC_RIGHT (ic);
8953   result = IC_RESULT (ic);
8954
8955   /* depending on the type of pointer we need to
8956      move it to the correct pointer register */
8957   type = operandType (result);
8958   etype = getSpec (type);
8959   /* if left is of type of pointer then it is simple */
8960   if (IS_PTR (type) && !IS_FUNC (type->next))
8961     {
8962       p_type = DCL_TYPE (type);
8963     }
8964   else
8965     {
8966       /* we have to go by the storage class */
8967       p_type = PTR_TYPE (SPEC_OCLS (etype));
8968     }
8969
8970   /* special case when cast remat */
8971   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
8972       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
8973           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
8974           type = operandType (result);
8975           p_type = DCL_TYPE (type);
8976   }
8977   /* now that we have the pointer type we assign
8978      the pointer values */
8979   switch (p_type)
8980     {
8981
8982     case POINTER:
8983     case IPOINTER:
8984       genNearPointerSet (right, result, ic, pi);
8985       break;
8986
8987     case PPOINTER:
8988       genPagedPointerSet (right, result, ic, pi);
8989       break;
8990
8991     case FPOINTER:
8992       genFarPointerSet (right, result, ic, pi);
8993       break;
8994
8995     case GPOINTER:
8996       genGenPointerSet (right, result, ic, pi);
8997       break;
8998
8999     default:
9000       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9001               "genPointerSet: illegal pointer type");
9002     }
9003
9004 }
9005
9006 /*-----------------------------------------------------------------*/
9007 /* genIfx - generate code for Ifx statement                        */
9008 /*-----------------------------------------------------------------*/
9009 static void
9010 genIfx (iCode * ic, iCode * popIc)
9011 {
9012   operand *cond = IC_COND (ic);
9013   int isbit = 0;
9014
9015   D(emitcode (";     genIfx",""));
9016
9017   aopOp (cond, ic, FALSE);
9018
9019   /* get the value into acc */
9020   if (AOP_TYPE (cond) != AOP_CRY)
9021     toBoolean (cond);
9022   else
9023     isbit = 1;
9024   /* the result is now in the accumulator */
9025   freeAsmop (cond, NULL, ic, TRUE);
9026
9027   /* if there was something to be popped then do it */
9028   if (popIc)
9029     genIpop (popIc);
9030
9031   /* if the condition is  a bit variable */
9032   if (isbit && IS_ITEMP (cond) &&
9033       SPIL_LOC (cond))
9034     genIfxJump (ic, SPIL_LOC (cond)->rname);
9035   else if (isbit && !IS_ITEMP (cond))
9036     genIfxJump (ic, OP_SYMBOL (cond)->rname);
9037   else
9038     genIfxJump (ic, "a");
9039
9040   ic->generated = 1;
9041 }
9042
9043 /*-----------------------------------------------------------------*/
9044 /* genAddrOf - generates code for address of                       */
9045 /*-----------------------------------------------------------------*/
9046 static void
9047 genAddrOf (iCode * ic)
9048 {
9049   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9050   int size, offset;
9051
9052   D(emitcode (";     genAddrOf",""));
9053
9054   aopOp (IC_RESULT (ic), ic, FALSE);
9055
9056   /* if the operand is on the stack then we
9057      need to get the stack offset of this
9058      variable */
9059   if (sym->onStack)
9060     {
9061       /* if it has an offset then we need to compute
9062          it */
9063       if (sym->stack)
9064         {
9065           emitcode ("mov", "a,_bp");
9066           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9067                                          ((char) (sym->stack - _G.nRegsSaved)) :
9068                                          ((char) sym->stack)) & 0xff);
9069           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9070         }
9071       else
9072         {
9073           /* we can just move _bp */
9074           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9075         }
9076       /* fill the result with zero */
9077       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9078
9079       offset = 1;
9080       while (size--)
9081         {
9082           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9083         }
9084
9085       goto release;
9086     }
9087
9088   /* object not on stack then we need the name */
9089   size = AOP_SIZE (IC_RESULT (ic));
9090   offset = 0;
9091
9092   while (size--)
9093     {
9094       char s[SDCC_NAME_MAX];
9095       if (offset)
9096         sprintf (s, "#(%s >> %d)",
9097                  sym->rname,
9098                  offset * 8);
9099       else
9100         sprintf (s, "#%s", sym->rname);
9101       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9102     }
9103
9104 release:
9105   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9106
9107 }
9108
9109 /*-----------------------------------------------------------------*/
9110 /* genFarFarAssign - assignment when both are in far space         */
9111 /*-----------------------------------------------------------------*/
9112 static void
9113 genFarFarAssign (operand * result, operand * right, iCode * ic)
9114 {
9115   int size = AOP_SIZE (right);
9116   int offset = 0;
9117   char *l;
9118
9119   D(emitcode (";     genFarFarAssign",""));
9120
9121   /* first push the right side on to the stack */
9122   while (size--)
9123     {
9124       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9125       MOVA (l);
9126       emitcode ("push", "acc");
9127     }
9128
9129   freeAsmop (right, NULL, ic, FALSE);
9130   /* now assign DPTR to result */
9131   aopOp (result, ic, FALSE);
9132   size = AOP_SIZE (result);
9133   while (size--)
9134     {
9135       emitcode ("pop", "acc");
9136       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9137     }
9138   freeAsmop (result, NULL, ic, FALSE);
9139
9140 }
9141
9142 /*-----------------------------------------------------------------*/
9143 /* genAssign - generate code for assignment                        */
9144 /*-----------------------------------------------------------------*/
9145 static void
9146 genAssign (iCode * ic)
9147 {
9148   operand *result, *right;
9149   int size, offset;
9150   unsigned long lit = 0L;
9151
9152   D(emitcode(";     genAssign",""));
9153
9154   result = IC_RESULT (ic);
9155   right = IC_RIGHT (ic);
9156
9157   /* if they are the same */
9158   if (operandsEqu (result, right) &&
9159       !isOperandVolatile (result, FALSE) &&
9160       !isOperandVolatile (right, FALSE))
9161     return;
9162
9163   aopOp (right, ic, FALSE);
9164
9165   /* special case both in far space */
9166   if (AOP_TYPE (right) == AOP_DPTR &&
9167       IS_TRUE_SYMOP (result) &&
9168       isOperandInFarSpace (result))
9169     {
9170
9171       genFarFarAssign (result, right, ic);
9172       return;
9173     }
9174
9175   aopOp (result, ic, TRUE);
9176
9177   /* if they are the same registers */
9178   if (sameRegs (AOP (right), AOP (result)) &&
9179       !isOperandVolatile (result, FALSE) &&
9180       !isOperandVolatile (right, FALSE))
9181     goto release;
9182
9183   /* if the result is a bit */
9184   if (AOP_TYPE (result) == AOP_CRY)
9185     {
9186
9187       /* if the right size is a literal then
9188          we know what the value is */
9189       if (AOP_TYPE (right) == AOP_LIT)
9190         {
9191           if (((int) operandLitValue (right)))
9192             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9193           else
9194             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9195           goto release;
9196         }
9197
9198       /* the right is also a bit variable */
9199       if (AOP_TYPE (right) == AOP_CRY)
9200         {
9201           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9202           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9203           goto release;
9204         }
9205
9206       /* we need to or */
9207       toBoolean (right);
9208       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9209       goto release;
9210     }
9211
9212   /* bit variables done */
9213   /* general case */
9214   size = AOP_SIZE (result);
9215   offset = 0;
9216   if (AOP_TYPE (right) == AOP_LIT)
9217     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9218   if ((size > 1) &&
9219       (AOP_TYPE (result) != AOP_REG) &&
9220       (AOP_TYPE (right) == AOP_LIT) &&
9221       !IS_FLOAT (operandType (right)) &&
9222       (lit < 256L))
9223     {
9224       emitcode ("clr", "a");
9225       while (size--)
9226         {
9227           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9228             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9229           else
9230             aopPut (AOP (result),
9231                     aopGet (AOP (right), size, FALSE, FALSE),
9232                     size,
9233                     isOperandVolatile (result, FALSE));
9234         }
9235     }
9236   else
9237     {
9238       while (size--)
9239         {
9240           aopPut (AOP (result),
9241                   aopGet (AOP (right), offset, FALSE, FALSE),
9242                   offset,
9243                   isOperandVolatile (result, FALSE));
9244           offset++;
9245         }
9246     }
9247
9248 release:
9249   freeAsmop (right, NULL, ic, TRUE);
9250   freeAsmop (result, NULL, ic, TRUE);
9251 }
9252
9253 /*-----------------------------------------------------------------*/
9254 /* genJumpTab - genrates code for jump table                       */
9255 /*-----------------------------------------------------------------*/
9256 static void
9257 genJumpTab (iCode * ic)
9258 {
9259   symbol *jtab;
9260   char *l;
9261
9262   D(emitcode (";     genJumpTab",""));
9263
9264   aopOp (IC_JTCOND (ic), ic, FALSE);
9265   /* get the condition into accumulator */
9266   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9267   MOVA (l);
9268   /* multiply by three */
9269   emitcode ("add", "a,acc");
9270   emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9271   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9272
9273   jtab = newiTempLabel (NULL);
9274   emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9275   emitcode ("jmp", "@a+dptr");
9276   emitcode ("", "%05d$:", jtab->key + 100);
9277   /* now generate the jump labels */
9278   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9279        jtab = setNextItem (IC_JTLABELS (ic)))
9280     emitcode ("ljmp", "%05d$", jtab->key + 100);
9281
9282 }
9283
9284 /*-----------------------------------------------------------------*/
9285 /* genCast - gen code for casting                                  */
9286 /*-----------------------------------------------------------------*/
9287 static void
9288 genCast (iCode * ic)
9289 {
9290   operand *result = IC_RESULT (ic);
9291   sym_link *ctype = operandType (IC_LEFT (ic));
9292   sym_link *rtype = operandType (IC_RIGHT (ic));
9293   operand *right = IC_RIGHT (ic);
9294   int size, offset;
9295
9296   D(emitcode(";     genCast",""));
9297
9298   /* if they are equivalent then do nothing */
9299   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9300     return;
9301
9302   aopOp (right, ic, FALSE);
9303   aopOp (result, ic, FALSE);
9304
9305   /* if the result is a bit (and not a bitfield) */
9306   // if (AOP_TYPE (result) == AOP_CRY)
9307   if (IS_BITVAR (OP_SYMBOL (result)->type)
9308       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9309     {
9310       /* if the right size is a literal then
9311          we know what the value is */
9312       if (AOP_TYPE (right) == AOP_LIT)
9313         {
9314           if (((int) operandLitValue (right)))
9315             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9316           else
9317             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9318
9319           goto release;
9320         }
9321
9322       /* the right is also a bit variable */
9323       if (AOP_TYPE (right) == AOP_CRY)
9324         {
9325           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9326           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9327           goto release;
9328         }
9329
9330       /* we need to or */
9331       toBoolean (right);
9332       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9333       goto release;
9334     }
9335
9336
9337   /* if they are the same size : or less */
9338   if (AOP_SIZE (result) <= AOP_SIZE (right))
9339     {
9340
9341       /* if they are in the same place */
9342       if (sameRegs (AOP (right), AOP (result)))
9343         goto release;
9344
9345       /* if they in different places then copy */
9346       size = AOP_SIZE (result);
9347       offset = 0;
9348       while (size--)
9349         {
9350           aopPut (AOP (result),
9351                   aopGet (AOP (right), offset, FALSE, FALSE),
9352                   offset,
9353                   isOperandVolatile (result, FALSE));
9354           offset++;
9355         }
9356       goto release;
9357     }
9358
9359
9360   /* if the result is of type pointer */
9361   if (IS_PTR (ctype))
9362     {
9363
9364       int p_type;
9365       sym_link *type = operandType (right);
9366       sym_link *etype = getSpec (type);
9367
9368       /* pointer to generic pointer */
9369       if (IS_GENPTR (ctype))
9370         {
9371           if (IS_PTR (type))
9372             p_type = DCL_TYPE (type);
9373           else
9374             {
9375               if (SPEC_SCLS(etype)==S_REGISTER) {
9376                 // let's assume it is a generic pointer
9377                 p_type=GPOINTER;
9378               } else {
9379                 /* we have to go by the storage class */
9380                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9381               }
9382             }
9383
9384           /* the first two bytes are known */
9385           size = GPTRSIZE - 1;
9386           offset = 0;
9387           while (size--)
9388             {
9389               aopPut (AOP (result),
9390                       aopGet (AOP (right), offset, FALSE, FALSE),
9391                       offset,
9392                       isOperandVolatile (result, FALSE));
9393               offset++;
9394             }
9395           /* the last byte depending on type */
9396             {
9397                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9398                 char gpValStr[10];
9399
9400                 if (gpVal == -1)
9401                 {
9402                     // pointerTypeToGPByte will have bitched.
9403                     exit(1);
9404                 }
9405
9406                 sprintf(gpValStr, "#0x%d", gpVal);
9407                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9408             }
9409           goto release;
9410         }
9411
9412       /* just copy the pointers */
9413       size = AOP_SIZE (result);
9414       offset = 0;
9415       while (size--)
9416         {
9417           aopPut (AOP (result),
9418                   aopGet (AOP (right), offset, FALSE, FALSE),
9419                   offset,
9420                   isOperandVolatile (result, FALSE));
9421           offset++;
9422         }
9423       goto release;
9424     }
9425
9426   /* so we now know that the size of destination is greater
9427      than the size of the source */
9428   /* we move to result for the size of source */
9429   size = AOP_SIZE (right);
9430   offset = 0;
9431   while (size--)
9432     {
9433       aopPut (AOP (result),
9434               aopGet (AOP (right), offset, FALSE, FALSE),
9435               offset,
9436               isOperandVolatile (result, FALSE));
9437       offset++;
9438     }
9439
9440   /* now depending on the sign of the source && destination */
9441   size = AOP_SIZE (result) - AOP_SIZE (right);
9442   /* if unsigned or not an integral type */
9443   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9444     {
9445       while (size--)
9446         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9447     }
9448   else
9449     {
9450       /* we need to extend the sign :{ */
9451       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9452                         FALSE, FALSE);
9453       MOVA (l);
9454       emitcode ("rlc", "a");
9455       emitcode ("subb", "a,acc");
9456       while (size--)
9457         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9458     }
9459
9460   /* we are done hurray !!!! */
9461
9462 release:
9463   freeAsmop (right, NULL, ic, TRUE);
9464   freeAsmop (result, NULL, ic, TRUE);
9465
9466 }
9467
9468 /*-----------------------------------------------------------------*/
9469 /* genDjnz - generate decrement & jump if not zero instrucion      */
9470 /*-----------------------------------------------------------------*/
9471 static int
9472 genDjnz (iCode * ic, iCode * ifx)
9473 {
9474   symbol *lbl, *lbl1;
9475   if (!ifx)
9476     return 0;
9477
9478   D(emitcode (";     genDjnz",""));
9479
9480   /* if the if condition has a false label
9481      then we cannot save */
9482   if (IC_FALSE (ifx))
9483     return 0;
9484
9485   /* if the minus is not of the form
9486      a = a - 1 */
9487   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9488       !IS_OP_LITERAL (IC_RIGHT (ic)))
9489     return 0;
9490
9491   if (operandLitValue (IC_RIGHT (ic)) != 1)
9492     return 0;
9493
9494   /* if the size of this greater than one then no
9495      saving */
9496   if (getSize (operandType (IC_RESULT (ic))) > 1)
9497     return 0;
9498
9499   /* otherwise we can save BIG */
9500   lbl = newiTempLabel (NULL);
9501   lbl1 = newiTempLabel (NULL);
9502
9503   aopOp (IC_RESULT (ic), ic, FALSE);
9504
9505   if (AOP_NEEDSACC(IC_RESULT(ic)))
9506   {
9507       /* If the result is accessed indirectly via
9508        * the accumulator, we must explicitly write
9509        * it back after the decrement.
9510        */
9511       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9512
9513       if (strcmp(rByte, "a"))
9514       {
9515            /* Something is hopelessly wrong */
9516            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9517                    __FILE__, __LINE__);
9518            /* We can just give up; the generated code will be inefficient,
9519             * but what the hey.
9520             */
9521            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9522            return 0;
9523       }
9524       emitcode ("dec", "%s", rByte);
9525       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9526       emitcode ("jnz", "%05d$", lbl->key + 100);
9527   }
9528   else if (IS_AOP_PREG (IC_RESULT (ic)))
9529     {
9530       emitcode ("dec", "%s",
9531                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9532       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9533       emitcode ("jnz", "%05d$", lbl->key + 100);
9534     }
9535   else
9536     {
9537       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9538                 lbl->key + 100);
9539     }
9540   emitcode ("sjmp", "%05d$", lbl1->key + 100);
9541   emitcode ("", "%05d$:", lbl->key + 100);
9542   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
9543   emitcode ("", "%05d$:", lbl1->key + 100);
9544
9545   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9546   ifx->generated = 1;
9547   return 1;
9548 }
9549
9550 /*-----------------------------------------------------------------*/
9551 /* genReceive - generate code for a receive iCode                  */
9552 /*-----------------------------------------------------------------*/
9553 static void
9554 genReceive (iCode * ic)
9555 {
9556     int size = getSize (operandType (IC_RESULT (ic)));
9557     int offset = 0;
9558   D(emitcode (";     genReceive",""));
9559
9560   if (ic->argreg == 1) { /* first parameter */
9561       if (isOperandInFarSpace (IC_RESULT (ic)) &&
9562           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
9563            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
9564
9565           regs *tempRegs[4];
9566           int receivingA = 0;
9567           int roffset = 0;
9568
9569           for (offset = 0; offset<size; offset++)
9570             if (!strcmp (fReturn[offset], "a"))
9571               receivingA = 1;
9572
9573           if (!receivingA)
9574             {
9575               if (size==1 || getTempRegs(tempRegs, size-1, ic))
9576                 {
9577                   for (offset = size-1; offset>0; offset--)
9578                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
9579                   emitcode("mov","a,%s", fReturn[0]);
9580                   _G.accInUse++;
9581                   aopOp (IC_RESULT (ic), ic, FALSE);
9582                   _G.accInUse--;
9583                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
9584                           isOperandVolatile (IC_RESULT (ic), FALSE));
9585                   for (offset = 1; offset<size; offset++)
9586                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
9587                             isOperandVolatile (IC_RESULT (ic), FALSE));
9588                   goto release;
9589                 }
9590             }
9591           else
9592             {
9593               if (getTempRegs(tempRegs, size, ic))
9594                 {
9595                   for (offset = 0; offset<size; offset++)
9596                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
9597                   aopOp (IC_RESULT (ic), ic, FALSE);
9598                   for (offset = 0; offset<size; offset++)
9599                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
9600                             isOperandVolatile (IC_RESULT (ic), FALSE));
9601                   goto release;
9602                 }
9603             }
9604
9605           offset = fReturnSizeMCS51 - size;
9606           while (size--) {
9607               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
9608                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
9609               offset++;
9610           }
9611           aopOp (IC_RESULT (ic), ic, FALSE);
9612           size = AOP_SIZE (IC_RESULT (ic));
9613           offset = 0;
9614           while (size--) {
9615               emitcode ("pop", "acc");
9616               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9617           }
9618
9619       } else {
9620           _G.accInUse++;
9621           aopOp (IC_RESULT (ic), ic, FALSE);
9622           _G.accInUse--;
9623           assignResultValue (IC_RESULT (ic));
9624       }
9625   } else { /* second receive onwards */
9626       int rb1off ;
9627       aopOp (IC_RESULT (ic), ic, FALSE);
9628       rb1off = ic->argreg;
9629       while (size--) {
9630           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9631       }
9632   }
9633
9634 release:
9635   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9636 }
9637
9638 /*-----------------------------------------------------------------*/
9639 /* genDummyRead - generate code for dummy read of volatiles        */
9640 /*-----------------------------------------------------------------*/
9641 static void
9642 genDummyRead (iCode * ic)
9643 {
9644   operand *op;
9645   int size, offset;
9646
9647   D(emitcode(";     genDummyRead",""));
9648
9649   op = IC_RIGHT (ic);
9650   if (op && IS_SYMOP (op))
9651     {
9652       aopOp (op, ic, FALSE);
9653
9654       /* if the result is a bit */
9655       if (AOP_TYPE (op) == AOP_CRY)
9656         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9657       else
9658         {
9659           /* bit variables done */
9660           /* general case */
9661           size = AOP_SIZE (op);
9662           offset = 0;
9663           while (size--)
9664           {
9665             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9666             offset++;
9667           }
9668         }
9669
9670       freeAsmop (op, NULL, ic, TRUE);
9671     }
9672
9673   op = IC_LEFT (ic);
9674   if (op && IS_SYMOP (op))
9675     {
9676       aopOp (op, ic, FALSE);
9677
9678       /* if the result is a bit */
9679       if (AOP_TYPE (op) == AOP_CRY)
9680         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9681       else
9682         {
9683           /* bit variables done */
9684           /* general case */
9685           size = AOP_SIZE (op);
9686           offset = 0;
9687           while (size--)
9688           {
9689             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9690             offset++;
9691           }
9692         }
9693
9694       freeAsmop (op, NULL, ic, TRUE);
9695     }
9696 }
9697
9698 /*-----------------------------------------------------------------*/
9699 /* genCritical - generate code for start of a critical sequence    */
9700 /*-----------------------------------------------------------------*/
9701 static void
9702 genCritical (iCode *ic)
9703 {
9704   symbol *tlbl = newiTempLabel (NULL);
9705
9706   D(emitcode(";     genCritical",""));
9707
9708   if (IC_RESULT (ic))
9709     aopOp (IC_RESULT (ic), ic, TRUE);
9710
9711   emitcode ("setb", "c");
9712   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
9713   emitcode ("clr", "c");
9714   emitcode ("", "%05d$:", (tlbl->key + 100));
9715
9716   if (IC_RESULT (ic))
9717     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
9718   else
9719     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
9720
9721   if (IC_RESULT (ic))
9722     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9723 }
9724
9725 /*-----------------------------------------------------------------*/
9726 /* genEndCritical - generate code for end of a critical sequence   */
9727 /*-----------------------------------------------------------------*/
9728 static void
9729 genEndCritical (iCode *ic)
9730 {
9731   D(emitcode(";     genEndCritical",""));
9732
9733   if (IC_RIGHT (ic))
9734     {
9735       aopOp (IC_RIGHT (ic), ic, FALSE);
9736       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
9737         {
9738           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
9739           emitcode ("mov", "ea,c");
9740         }
9741       else
9742         {
9743           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
9744           emitcode ("rrc", "a");
9745           emitcode ("mov", "ea,c");
9746         }
9747       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
9748     }
9749   else
9750     {
9751       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
9752       emitcode ("mov", "ea,c");
9753     }
9754 }
9755
9756 /*-----------------------------------------------------------------*/
9757 /* gen51Code - generate code for 8051 based controllers            */
9758 /*-----------------------------------------------------------------*/
9759 void
9760 gen51Code (iCode * lic)
9761 {
9762   iCode *ic;
9763   int cln = 0;
9764   /* int cseq = 0; */
9765
9766   _G.currentFunc = NULL;
9767   lineHead = lineCurr = NULL;
9768
9769   /* print the allocation information */
9770   if (allocInfo && currFunc)
9771     printAllocInfo (currFunc, codeOutFile);
9772   /* if debug information required */
9773   if (options.debug && currFunc)
9774     {
9775       debugFile->writeFunction(currFunc);
9776       _G.debugLine = 1;
9777       if (IS_STATIC (currFunc->etype))
9778         emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
9779       else
9780         emitcode ("", "G$%s$0$0 ==.", currFunc->name);
9781       _G.debugLine = 0;
9782     }
9783   /* stack pointer name */
9784   if (options.useXstack)
9785     spname = "_spx";
9786   else
9787     spname = "sp";
9788
9789
9790   for (ic = lic; ic; ic = ic->next)
9791     {
9792       _G.current_iCode = ic;
9793
9794       if (ic->lineno && cln != ic->lineno)
9795         {
9796           if (options.debug)
9797             {
9798               _G.debugLine = 1;
9799               emitcode ("", "C$%s$%d$%d$%d ==.",
9800                         FileBaseName (ic->filename), ic->lineno,
9801                         ic->level, ic->block);
9802               _G.debugLine = 0;
9803             }
9804           if (!options.noCcodeInAsm) {
9805             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
9806                       printCLine(ic->filename, ic->lineno));
9807           }
9808           cln = ic->lineno;
9809         }
9810       #if 0
9811       if (ic->seqPoint && ic->seqPoint != cseq)
9812         {
9813           emitcode ("", "; sequence point %d", ic->seqPoint);
9814           cseq = ic->seqPoint;
9815         }
9816       #endif
9817       if (options.iCodeInAsm) {
9818         char regsInUse[80];
9819         int i;
9820
9821         for (i=0; i<8; i++) {
9822           sprintf (&regsInUse[i],
9823                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
9824         }
9825         regsInUse[i]=0;
9826         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
9827       }
9828       /* if the result is marked as
9829          spilt and rematerializable or code for
9830          this has already been generated then
9831          do nothing */
9832       if (resultRemat (ic) || ic->generated)
9833         continue;
9834
9835       /* depending on the operation */
9836       switch (ic->op)
9837         {
9838         case '!':
9839           genNot (ic);
9840           break;
9841
9842         case '~':
9843           genCpl (ic);
9844           break;
9845
9846         case UNARYMINUS:
9847           genUminus (ic);
9848           break;
9849
9850         case IPUSH:
9851           genIpush (ic);
9852           break;
9853
9854         case IPOP:
9855           /* IPOP happens only when trying to restore a
9856              spilt live range, if there is an ifx statement
9857              following this pop then the if statement might
9858              be using some of the registers being popped which
9859              would destory the contents of the register so
9860              we need to check for this condition and handle it */
9861           if (ic->next &&
9862               ic->next->op == IFX &&
9863               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
9864             genIfx (ic->next, ic);
9865           else
9866             genIpop (ic);
9867           break;
9868
9869         case CALL:
9870           genCall (ic);
9871           break;
9872
9873         case PCALL:
9874           genPcall (ic);
9875           break;
9876
9877         case FUNCTION:
9878           genFunction (ic);
9879           break;
9880
9881         case ENDFUNCTION:
9882           genEndFunction (ic);
9883           break;
9884
9885         case RETURN:
9886           genRet (ic);
9887           break;
9888
9889         case LABEL:
9890           genLabel (ic);
9891           break;
9892
9893         case GOTO:
9894           genGoto (ic);
9895           break;
9896
9897         case '+':
9898           genPlus (ic);
9899           break;
9900
9901         case '-':
9902           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
9903             genMinus (ic);
9904           break;
9905
9906         case '*':
9907           genMult (ic);
9908           break;
9909
9910         case '/':
9911           genDiv (ic);
9912           break;
9913
9914         case '%':
9915           genMod (ic);
9916           break;
9917
9918         case '>':
9919           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
9920           break;
9921
9922         case '<':
9923           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
9924           break;
9925
9926         case LE_OP:
9927         case GE_OP:
9928         case NE_OP:
9929
9930           /* note these two are xlated by algebraic equivalence
9931              during parsing SDCC.y */
9932           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9933                   "got '>=' or '<=' shouldn't have come here");
9934           break;
9935
9936         case EQ_OP:
9937           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
9938           break;
9939
9940         case AND_OP:
9941           genAndOp (ic);
9942           break;
9943
9944         case OR_OP:
9945           genOrOp (ic);
9946           break;
9947
9948         case '^':
9949           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
9950           break;
9951
9952         case '|':
9953           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
9954           break;
9955
9956         case BITWISEAND:
9957           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
9958           break;
9959
9960         case INLINEASM:
9961           genInline (ic);
9962           break;
9963
9964         case RRC:
9965           genRRC (ic);
9966           break;
9967
9968         case RLC:
9969           genRLC (ic);
9970           break;
9971
9972         case GETHBIT:
9973           genGetHbit (ic);
9974           break;
9975
9976         case LEFT_OP:
9977           genLeftShift (ic);
9978           break;
9979
9980         case RIGHT_OP:
9981           genRightShift (ic);
9982           break;
9983
9984         case GET_VALUE_AT_ADDRESS:
9985           genPointerGet (ic, hasInc(IC_LEFT(ic),ic,getSize(operandType(IC_RESULT(ic)))));
9986           break;
9987
9988         case '=':
9989           if (POINTER_SET (ic))
9990             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
9991           else
9992             genAssign (ic);
9993           break;
9994
9995         case IFX:
9996           genIfx (ic, NULL);
9997           break;
9998
9999         case ADDRESS_OF:
10000           genAddrOf (ic);
10001           break;
10002
10003         case JUMPTABLE:
10004           genJumpTab (ic);
10005           break;
10006
10007         case CAST:
10008           genCast (ic);
10009           break;
10010
10011         case RECEIVE:
10012           genReceive (ic);
10013           break;
10014
10015         case SEND:
10016           addSet (&_G.sendSet, ic);
10017           break;
10018
10019         case DUMMY_READ_VOLATILE:
10020           genDummyRead (ic);
10021           break;
10022
10023         case CRITICAL:
10024           genCritical (ic);
10025           break;
10026
10027         case ENDCRITICAL:
10028           genEndCritical (ic);
10029           break;
10030
10031         case SWAP:
10032           genSwap (ic);
10033           break;
10034
10035         default:
10036           ic = ic;
10037         }
10038     }
10039
10040   _G.current_iCode = NULL;
10041
10042   /* now we are ready to call the
10043      peep hole optimizer */
10044   if (!options.nopeep)
10045     peepHole (&lineHead);
10046
10047   /* now do the actual printing */
10048   printLine (lineHead, codeOutFile);
10049   return;
10050 }