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