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