* device/lib/medium/Makefile: added for new memory model medium
[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 char *aopLiteralLong (value * val, int offset, int size);
48 extern int allocInfo;
49
50 /* this is the down and dirty file with all kinds of
51    kludgy & hacky stuff. This is what it is all about
52    CODE GENERATION for a specific MCU . some of the
53    routines may be reusable, will have to see */
54
55 static char *zero = "#0x00";
56 static char *one = "#0x01";
57 static char *spname;
58
59 char *fReturn8051[] =
60 {"dpl", "dph", "b", "a"};
61 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
62 char **fReturn = fReturn8051;
63 static char *accUse[] =
64 {"a", "b"};
65
66 static unsigned short rbank = -1;
67
68 #define AOP(op) op->aop
69 #define AOP_TYPE(op) AOP(op)->type
70 #define AOP_SIZE(op) AOP(op)->size
71 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
72                        AOP_TYPE(x) == AOP_R0))
73
74 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
75                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
76
77 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
78                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
79                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
80
81
82 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
83
84 #define R0INB   _G.bu.bs.r0InB
85 #define R1INB   _G.bu.bs.r1InB
86 #define OPINB   _G.bu.bs.OpInB
87 #define BINUSE  _G.bu.BInUse
88
89 static struct
90   {
91     short r0Pushed;
92     short r1Pushed;
93     union
94       {
95         struct
96           {
97             short r0InB : 2;//2 so we can see it overflow
98             short r1InB : 2;//2 so we can see it overflow
99             short OpInB : 2;//2 so we can see it overflow
100           } bs;
101         short BInUse;
102       } bu;
103     short accInUse;
104     short inLine;
105     short debugLine;
106     short nRegsSaved;
107     set *sendSet;
108     iCode *current_iCode;
109     symbol *currentFunc;
110   }
111 _G;
112
113 static char *rb1regs[] = {
114     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
115     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
116 };
117
118 extern int mcs51_ptrRegReq;
119 extern int mcs51_nRegs;
120 extern FILE *codeOutFile;
121 static void saveRBank (int, iCode *, bool);
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define CLRC     emitcode("clr","c")
129 #define SETC     emitcode("setb","c")
130
131 static lineNode *lineHead = NULL;
132 static lineNode *lineCurr = NULL;
133
134 static unsigned char SLMask[] =
135 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
136  0xE0, 0xC0, 0x80, 0x00};
137 static unsigned char SRMask[] =
138 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
139  0x07, 0x03, 0x01, 0x00};
140
141 #define LSB     0
142 #define MSB16   1
143 #define MSB24   2
144 #define MSB32   3
145
146 /*-----------------------------------------------------------------*/
147 /* emitcode - writes the code into a file : for now it is simple    */
148 /*-----------------------------------------------------------------*/
149 static void
150 emitcode (char *inst, const char *fmt,...)
151 {
152   va_list ap;
153   char lb[INITIAL_INLINEASM];
154   char *lbp = lb;
155
156   va_start (ap, fmt);
157
158   if (inst && *inst)
159     {
160       if (fmt && *fmt)
161           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
162       else
163           SNPRINTF (lb, sizeof(lb), "%s", inst);
164       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
165     }
166   else
167       tvsprintf (lb, sizeof(lb), fmt, ap);
168
169   while (isspace ((unsigned char)*lbp))
170       lbp++;
171
172   if (lbp && *lbp)
173       lineCurr = (lineCurr ?
174                   connectLine (lineCurr, newLineNode (lb)) :
175                   (lineHead = newLineNode (lb)));
176   lineCurr->isInline = _G.inLine;
177   lineCurr->isDebug = _G.debugLine;
178   lineCurr->ic = _G.current_iCode;
179   lineCurr->isComment = (*lbp==';');
180   va_end (ap);
181 }
182
183 /*-----------------------------------------------------------------*/
184 /* mcs51_emitDebuggerSymbol - associate the current code location  */
185 /*   with a debugger symbol                                        */
186 /*-----------------------------------------------------------------*/
187 void
188 mcs51_emitDebuggerSymbol (char * debugSym)
189 {
190   _G.debugLine = 1;
191   emitcode ("", "%s ==.", debugSym);
192   _G.debugLine = 0;
193 }
194
195 /*-----------------------------------------------------------------*/
196 /* mova - moves specified value into accumulator                   */
197 /*-----------------------------------------------------------------*/
198 static void
199 mova (const char *x)
200 {
201   /* do some early peephole optimization */
202   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
203     return;
204
205   emitcode("mov","a,%s", x);
206 }
207
208 /*-----------------------------------------------------------------*/
209 /* movc - moves specified value into the carry                     */
210 /*-----------------------------------------------------------------*/
211 static void
212 movc (const char *s)
213 {
214   if (s == zero)
215     CLRC;
216   else if (s == one)
217     SETC;
218   else if (strcmp (s, "c"))
219     {/* it's not in carry already */
220       MOVA (s);
221       /* set C, if a >= 1 */
222       emitcode ("add", "a,#0xff");
223     }
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* pushB - saves register B if necessary                           */
228 /*-----------------------------------------------------------------*/
229 static bool
230 pushB (void)
231 {
232   bool pushedB = FALSE;
233
234   if (BINUSE)
235     {
236       emitcode ("push", "b");
237 //    printf("B was in use !\n");
238       pushedB = TRUE;
239     }
240   else
241     {
242       OPINB++;
243     }
244   return pushedB;
245 }
246
247 /*-----------------------------------------------------------------*/
248 /* popB - restores value of register B if necessary                */
249 /*-----------------------------------------------------------------*/
250 static void
251 popB (bool pushedB)
252 {
253   if (pushedB)
254     {
255       emitcode ("pop", "b");
256     }
257   else
258     {
259       OPINB--;
260     }
261 }
262
263 /*-----------------------------------------------------------------*/
264 /* pushReg - saves register                                        */
265 /*-----------------------------------------------------------------*/
266 static bool
267 pushReg (int index, bool bits_pushed)
268 {
269   regs * reg = mcs51_regWithIdx (index);
270   if (reg->type == REG_BIT)
271     {
272       if (!bits_pushed)
273         emitcode ("push", "%s", reg->base);
274       return TRUE;
275     }
276   else
277     emitcode ("push", "%s", reg->dname);
278   return bits_pushed;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popReg - restores register                                      */
283 /*-----------------------------------------------------------------*/
284 static bool
285 popReg (int index, bool bits_popped)
286 {
287   regs * reg = mcs51_regWithIdx (index);
288   if (reg->type == REG_BIT)
289     {
290       if (!bits_popped)
291         emitcode ("pop", "%s", reg->base);
292       return TRUE;
293     }
294   else
295     emitcode ("pop", "%s", reg->dname);
296   return bits_popped;
297 }
298
299 /*-----------------------------------------------------------------*/
300 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
301 /*-----------------------------------------------------------------*/
302 static regs *
303 getFreePtr (iCode * ic, asmop ** aopp, bool result)
304 {
305   bool r0iu, r1iu;
306   bool r0ou, r1ou;
307
308   /* the logic: if r0 & r1 used in the instruction
309      then we are in trouble otherwise */
310
311   /* first check if r0 & r1 are used by this
312      instruction, in which case we are in trouble */
313   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
314   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
315   if (r0iu && r1iu) {
316       goto endOfWorld;
317     }
318
319   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
320   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
321
322   /* if no usage of r0 then return it */
323   if (!r0iu && !r0ou)
324     {
325       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
326       (*aopp)->type = AOP_R0;
327
328       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
329     }
330
331   /* if no usage of r1 then return it */
332   if (!r1iu && !r1ou)
333     {
334       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
335       (*aopp)->type = AOP_R1;
336
337       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
338     }
339
340   /* now we know they both have usage */
341   /* if r0 not used in this instruction */
342   if (!r0iu)
343     {
344       /* push it if not already pushed */
345       if (ic->op == IPUSH)
346         {
347           emitcode ("mov", "b,%s",
348                     mcs51_regWithIdx (R0_IDX)->dname);
349           R0INB++;
350         }
351       else if (!_G.r0Pushed)
352         {
353           emitcode ("push", "%s",
354                     mcs51_regWithIdx (R0_IDX)->dname);
355           _G.r0Pushed++;
356         }
357
358       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
359       (*aopp)->type = AOP_R0;
360
361       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
362     }
363
364   /* if r1 not used then */
365
366   if (!r1iu)
367     {
368       /* push it if not already pushed */
369       if (ic->op == IPUSH)
370         {
371           emitcode ("mov", "b,%s",
372                     mcs51_regWithIdx (R1_IDX)->dname);
373           R1INB++;
374         }
375       else if (!_G.r1Pushed)
376         {
377           emitcode ("push", "%s",
378                     mcs51_regWithIdx (R1_IDX)->dname);
379           _G.r1Pushed++;
380         }
381
382       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
383       (*aopp)->type = AOP_R1;
384       return mcs51_regWithIdx (R1_IDX);
385     }
386 endOfWorld:
387   /* I said end of world, but not quite end of world yet */
388   if (result) {
389     /* we can push it on the stack */
390     (*aopp)->type = AOP_STK;
391     return NULL;
392   } else {
393     /* in the case that result AND left AND right needs a pointer reg
394        we can safely use the result's */
395     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
396       (*aopp)->type = AOP_R0;
397       return mcs51_regWithIdx (R0_IDX);
398     }
399     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
400       (*aopp)->type = AOP_R1;
401       return mcs51_regWithIdx (R1_IDX);
402     }
403   }
404
405   /* now this is REALLY the end of the world */
406   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
407           "getFreePtr should never reach here");
408   exit (1);
409 }
410
411
412 /*-----------------------------------------------------------------*/
413 /* getTempRegs - initialize an array of pointers to GPR registers */
414 /*               that are not in use. Returns 1 if the requested   */
415 /*               number of registers were available, 0 otherwise.  */
416 /*-----------------------------------------------------------------*/
417 int
418 getTempRegs(regs **tempRegs, int size, iCode *ic)
419 {
420   bitVect * freeRegs;
421   int i;
422   int offset;
423
424   if (!ic)
425     ic = _G.current_iCode;
426   if (!ic)
427     return 0;
428   if (!_G.currentFunc)
429     return 0;
430
431   freeRegs = newBitVect(8);
432   bitVectSetBit (freeRegs, R2_IDX);
433   bitVectSetBit (freeRegs, R3_IDX);
434   bitVectSetBit (freeRegs, R4_IDX);
435   bitVectSetBit (freeRegs, R5_IDX);
436   bitVectSetBit (freeRegs, R6_IDX);
437   bitVectSetBit (freeRegs, R7_IDX);
438
439   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
440     {
441       bitVect * newfreeRegs;
442       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
443       freeBitVect(freeRegs);
444       freeRegs = newfreeRegs;
445     }
446   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
447
448   offset = 0;
449   for (i=0; i<freeRegs->size; i++)
450     {
451       if (bitVectBitValue(freeRegs,i))
452         tempRegs[offset++] = mcs51_regWithIdx(i);
453       if (offset>=size)
454         {
455           freeBitVect(freeRegs);
456           return 1;
457         }
458     }
459
460   freeBitVect(freeRegs);
461   return 0;
462 }
463
464
465 /*-----------------------------------------------------------------*/
466 /* newAsmop - creates a new asmOp                                  */
467 /*-----------------------------------------------------------------*/
468 static asmop *
469 newAsmop (short type)
470 {
471   asmop *aop;
472
473   aop = Safe_calloc (1, sizeof (asmop));
474   aop->type = type;
475   return aop;
476 }
477
478 /*-----------------------------------------------------------------*/
479 /* pointerCode - returns the code for a pointer type               */
480 /*-----------------------------------------------------------------*/
481 static int
482 pointerCode (sym_link * etype)
483 {
484
485   return PTR_TYPE (SPEC_OCLS (etype));
486
487 }
488
489 /*-----------------------------------------------------------------*/
490 /* leftRightUseAcc - returns size of accumulator use by operands   */
491 /*-----------------------------------------------------------------*/
492 static int
493 leftRightUseAcc(iCode *ic)
494 {
495   operand *op;
496   int size;
497   int accuseSize = 0;
498   int accuse = 0;
499
500   if (!ic)
501     {
502       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
503               "null iCode pointer");
504       return 0;
505     }
506
507   if (ic->op == IFX)
508     {
509       op = IC_COND (ic);
510       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
511         {
512           accuse = 1;
513           size = getSize (OP_SYMBOL (op)->type);
514           if (size>accuseSize)
515             accuseSize = size;
516         }
517     }
518   else if (ic->op == JUMPTABLE)
519     {
520       op = IC_JTCOND (ic);
521       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
522         {
523           accuse = 1;
524           size = getSize (OP_SYMBOL (op)->type);
525           if (size>accuseSize)
526             accuseSize = size;
527         }
528     }
529   else
530     {
531       op = IC_LEFT (ic);
532       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
533         {
534           accuse = 1;
535           size = getSize (OP_SYMBOL (op)->type);
536           if (size>accuseSize)
537             accuseSize = size;
538         }
539       op = IC_RIGHT (ic);
540       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
541         {
542           accuse = 1;
543           size = getSize (OP_SYMBOL (op)->type);
544           if (size>accuseSize)
545             accuseSize = size;
546         }
547     }
548
549   if (accuseSize)
550     return accuseSize;
551   else
552     return accuse;
553 }
554
555 /*-----------------------------------------------------------------*/
556 /* aopForSym - for a true symbol                                   */
557 /*-----------------------------------------------------------------*/
558 static asmop *
559 aopForSym (iCode * ic, symbol * sym, bool result)
560 {
561   asmop *aop;
562   memmap *space;
563
564   wassertl (ic != NULL, "Got a null iCode");
565   wassertl (sym != NULL, "Got a null symbol");
566
567   space = SPEC_OCLS (sym->etype);
568
569   /* if already has one */
570   if (sym->aop)
571     return sym->aop;
572
573   /* assign depending on the storage class */
574   /* if it is on the stack or indirectly addressable */
575   /* space we need to assign either r0 or r1 to it   */
576   if (sym->onStack || sym->iaccess)
577     {
578       sym->aop = aop = newAsmop (0);
579       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
580       aop->size = getSize (sym->type);
581
582       /* now assign the address of the variable to
583          the pointer register */
584       if (aop->type != AOP_STK)
585         {
586
587           if (sym->onStack)
588             {
589               char offset = ((sym->stack < 0) ?
590                          ((char) (sym->stack - _G.nRegsSaved)) :
591                          ((char) sym->stack)) & 0xff;
592
593               if ((offset >= -3) && (offset <= 3))
594                 {
595                   emitcode ("mov", "%s,%s",
596                             aop->aopu.aop_ptr->name, SYM_BP (sym));
597                   while (offset < 0)
598                     {
599                       emitcode ("dec", aop->aopu.aop_ptr->name);
600                       offset++;
601                     }
602                   while (offset > 0)
603                     {
604                       emitcode ("inc", aop->aopu.aop_ptr->name);
605                       offset--;
606                     }
607                 }
608               else
609                 {
610                   if (_G.accInUse || leftRightUseAcc (ic))
611                     emitcode ("push", "acc");
612                   emitcode ("mov", "a,%s", SYM_BP (sym));
613                   emitcode ("add", "a,#0x%02x", offset);
614                   emitcode ("mov", "%s,a",
615                             aop->aopu.aop_ptr->name);
616                   if (_G.accInUse || leftRightUseAcc (ic))
617                     emitcode ("pop", "acc");
618                 }
619             }
620           else
621             emitcode ("mov", "%s,#%s",
622                       aop->aopu.aop_ptr->name,
623                       sym->rname);
624           aop->paged = space->paged;
625         }
626       else
627         aop->aopu.aop_stk = sym->stack;
628       return aop;
629     }
630
631   /* if in bit space */
632   if (IN_BITSPACE (space))
633     {
634       sym->aop = aop = newAsmop (AOP_CRY);
635       aop->aopu.aop_dir = sym->rname;
636       aop->size = getSize (sym->type);
637       return aop;
638     }
639   /* if it is in direct space */
640   if (IN_DIRSPACE (space))
641     {
642       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
643       //printTypeChainRaw(sym->type, NULL);
644       //printf("space = %s\n", space ? space->sname : "NULL");
645       sym->aop = aop = newAsmop (AOP_DIR);
646       aop->aopu.aop_dir = sym->rname;
647       aop->size = getSize (sym->type);
648       return aop;
649     }
650
651   /* special case for a function */
652   if (IS_FUNC (sym->type))
653     {
654       sym->aop = aop = newAsmop (AOP_IMMD);
655       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
656       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
657       aop->size = getSize (sym->type);
658       return aop;
659     }
660
661   /* only remaining is far space */
662   /* in which case DPTR gets the address */
663   sym->aop = aop = newAsmop (AOP_DPTR);
664   emitcode ("mov", "dptr,#%s", sym->rname);
665   aop->size = getSize (sym->type);
666
667   /* if it is in code space */
668   if (IN_CODESPACE (space))
669     aop->code = 1;
670
671   return aop;
672 }
673
674 /*-----------------------------------------------------------------*/
675 /* aopForRemat - rematerialzes an object                           */
676 /*-----------------------------------------------------------------*/
677 static asmop *
678 aopForRemat (symbol * sym)
679 {
680   iCode *ic = sym->rematiCode;
681   asmop *aop = newAsmop (AOP_IMMD);
682   int ptr_type = 0;
683   int val = 0;
684
685   for (;;)
686     {
687       if (ic->op == '+')
688         val += (int) operandLitValue (IC_RIGHT (ic));
689       else if (ic->op == '-')
690         val -= (int) operandLitValue (IC_RIGHT (ic));
691       else if (IS_CAST_ICODE(ic)) {
692               sym_link *from_type = operandType(IC_RIGHT(ic));
693               aop->aopu.aop_immd.from_cast_remat = 1;
694               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
695               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
696               continue;
697       } else break;
698
699       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
700     }
701
702   if (val)
703     sprintf (buffer, "(%s %c 0x%04x)",
704              OP_SYMBOL (IC_LEFT (ic))->rname,
705              val >= 0 ? '+' : '-',
706              abs (val) & 0xffff);
707   else
708     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
709
710   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
711   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
712   /* set immd2 field if required */
713   if (aop->aopu.aop_immd.from_cast_remat) {
714           sprintf(buffer,"#0x%02x",ptr_type);
715           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
716           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
717   }
718
719   return aop;
720 }
721
722 /*-----------------------------------------------------------------*/
723 /* regsInCommon - two operands have some registers in common       */
724 /*-----------------------------------------------------------------*/
725 static bool
726 regsInCommon (operand * op1, operand * op2)
727 {
728   symbol *sym1, *sym2;
729   int i;
730
731   /* if they have registers in common */
732   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
733     return FALSE;
734
735   sym1 = OP_SYMBOL (op1);
736   sym2 = OP_SYMBOL (op2);
737
738   if (sym1->nRegs == 0 || sym2->nRegs == 0)
739     return FALSE;
740
741   for (i = 0; i < sym1->nRegs; i++)
742     {
743       int j;
744       if (!sym1->regs[i])
745         continue;
746
747       for (j = 0; j < sym2->nRegs; j++)
748         {
749           if (!sym2->regs[j])
750             continue;
751
752           if (sym2->regs[j] == sym1->regs[i])
753             return TRUE;
754         }
755     }
756
757   return FALSE;
758 }
759
760 /*-----------------------------------------------------------------*/
761 /* operandsEqu - equivalent                                        */
762 /*-----------------------------------------------------------------*/
763 static bool
764 operandsEqu (operand * op1, operand * op2)
765 {
766   symbol *sym1, *sym2;
767
768   /* if they're not symbols */
769   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
770     return FALSE;
771
772   sym1 = OP_SYMBOL (op1);
773   sym2 = OP_SYMBOL (op2);
774
775   /* if both are itemps & one is spilt
776      and the other is not then false */
777   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
778       sym1->isspilt != sym2->isspilt)
779     return FALSE;
780
781   /* if they are the same */
782   if (sym1 == sym2)
783     return TRUE;
784
785   /* if they have the same rname */
786   if (sym1->rname[0] && sym2->rname[0] &&
787       strcmp (sym1->rname, sym2->rname) == 0 &&
788       !(IS_PARM (op2) && IS_ITEMP (op1)))
789     return TRUE;
790
791   /* if left is a tmp & right is not */
792   if (IS_ITEMP (op1) &&
793       !IS_ITEMP (op2) &&
794       sym1->isspilt &&
795       (sym1->usl.spillLoc == sym2))
796     return TRUE;
797
798   if (IS_ITEMP (op2) &&
799       !IS_ITEMP (op1) &&
800       sym2->isspilt &&
801       sym1->level > 0 &&
802       (sym2->usl.spillLoc == sym1))
803     return TRUE;
804
805   return FALSE;
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* sameRegs - two asmops have the same registers                   */
810 /*-----------------------------------------------------------------*/
811 static bool
812 sameRegs (asmop * aop1, asmop * aop2)
813 {
814   int i;
815
816   if (aop1 == aop2)
817     return TRUE;
818
819   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
820     return FALSE;
821
822   if (aop1->type != aop2->type)
823     return FALSE;
824
825   if (aop1->size != aop2->size)
826     return FALSE;
827
828   for (i = 0; i < aop1->size; i++)
829     if (aop1->aopu.aop_reg[i] !=
830         aop2->aopu.aop_reg[i])
831       return FALSE;
832
833   return TRUE;
834 }
835
836 /*-----------------------------------------------------------------*/
837 /* aopOp - allocates an asmop for an operand  :                    */
838 /*-----------------------------------------------------------------*/
839 static void
840 aopOp (operand * op, iCode * ic, bool result)
841 {
842   asmop *aop;
843   symbol *sym;
844   int i;
845
846   if (!op)
847     return;
848
849   /* if this a literal */
850   if (IS_OP_LITERAL (op))
851     {
852       op->aop = aop = newAsmop (AOP_LIT);
853       aop->aopu.aop_lit = op->operand.valOperand;
854       aop->size = getSize (operandType (op));
855       return;
856     }
857
858   /* if already has a asmop then continue */
859   if (op->aop )
860     return;
861
862   /* if the underlying symbol has a aop */
863   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
864     {
865       op->aop = OP_SYMBOL (op)->aop;
866       return;
867     }
868
869   /* if this is a true symbol */
870   if (IS_TRUE_SYMOP (op))
871     {
872       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
873       return;
874     }
875
876   /* this is a temporary : this has
877      only five choices :
878      a) register
879      b) spillocation
880      c) rematerialize
881      d) conditional
882      e) can be a return use only */
883
884   sym = OP_SYMBOL (op);
885
886   /* if the type is a conditional */
887   if (sym->regType == REG_CND)
888     {
889       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
890       aop->size = 0;
891       return;
892     }
893
894   /* if it is spilt then two situations
895      a) is rematerialize
896      b) has a spill location */
897   if (sym->isspilt || sym->nRegs == 0)
898     {
899
900       /* rematerialize it NOW */
901       if (sym->remat)
902         {
903           sym->aop = op->aop = aop =
904             aopForRemat (sym);
905           aop->size = getSize (sym->type);
906           return;
907         }
908
909       if (sym->accuse)
910         {
911           int i;
912           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
913           aop->size = getSize (sym->type);
914           for (i = 0; i < 2; i++)
915             aop->aopu.aop_str[i] = accUse[i];
916           return;
917         }
918
919       if (sym->ruonly)
920         {
921           unsigned i;
922
923           aop = op->aop = sym->aop = newAsmop (AOP_STR);
924           aop->size = getSize (sym->type);
925           for (i = 0; i < fReturnSizeMCS51; i++)
926             aop->aopu.aop_str[i] = fReturn[i];
927           return;
928         }
929
930       if (sym->usl.spillLoc)
931         {
932           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
933             {
934               /* force a new aop if sizes differ */
935               sym->usl.spillLoc->aop = NULL;
936             }
937           sym->aop = op->aop = aop =
938                      aopForSym (ic, sym->usl.spillLoc, result);
939           aop->size = getSize (sym->type);
940           return;
941         }
942
943       /* else must be a dummy iTemp */
944       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
945       aop->size = getSize (sym->type);
946       return;
947     }
948
949   /* if the type is a bit register */
950   if (sym->regType == REG_BIT)
951     {
952       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
953       aop->size = sym->nRegs;//1???
954       aop->aopu.aop_reg[0] = sym->regs[0];
955       aop->aopu.aop_dir = sym->regs[0]->name;
956       return;
957     }
958
959   /* must be in a register */
960   sym->aop = op->aop = aop = newAsmop (AOP_REG);
961   aop->size = sym->nRegs;
962   for (i = 0; i < sym->nRegs; i++)
963     aop->aopu.aop_reg[i] = sym->regs[i];
964 }
965
966 /*-----------------------------------------------------------------*/
967 /* freeAsmop - free up the asmop given to an operand               */
968 /*----------------------------------------------------------------*/
969 static void
970 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
971 {
972   asmop *aop;
973
974   if (!op)
975     aop = aaop;
976   else
977     aop = op->aop;
978
979   if (!aop)
980     return;
981
982   if (aop->freed)
983     goto dealloc;
984
985   aop->freed = 1;
986
987   /* depending on the asmop type only three cases need work AOP_RO
988      , AOP_R1 && AOP_STK */
989   switch (aop->type)
990     {
991     case AOP_R0:
992       if (R0INB)
993         {
994           emitcode ("mov", "r0,b");
995           R0INB--;
996         }
997       else if (_G.r0Pushed)
998         {
999           if (pop)
1000             {
1001               emitcode ("pop", "ar0");
1002               _G.r0Pushed--;
1003             }
1004         }
1005       bitVectUnSetBit (ic->rUsed, R0_IDX);
1006       break;
1007
1008     case AOP_R1:
1009       if (R1INB)
1010         {
1011           emitcode ("mov", "r1,b");
1012           R1INB--;
1013         }
1014       if (_G.r1Pushed)
1015         {
1016           if (pop)
1017             {
1018               emitcode ("pop", "ar1");
1019               _G.r1Pushed--;
1020             }
1021         }
1022       bitVectUnSetBit (ic->rUsed, R1_IDX);
1023       break;
1024
1025     case AOP_STK:
1026       {
1027         int sz = aop->size;
1028         int stk = aop->aopu.aop_stk + aop->size - 1;
1029         bitVectUnSetBit (ic->rUsed, R0_IDX);
1030         bitVectUnSetBit (ic->rUsed, R1_IDX);
1031
1032         getFreePtr (ic, &aop, FALSE);
1033
1034         if (stk)
1035           {
1036             emitcode ("mov", "a,_bp");
1037             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1038             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1039           }
1040         else
1041           {
1042             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1043           }
1044
1045         while (sz--)
1046           {
1047             emitcode ("pop", "acc");
1048             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1049             if (!sz)
1050               break;
1051             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1052           }
1053         op->aop = aop;
1054         freeAsmop (op, NULL, ic, TRUE);
1055         if (_G.r1Pushed)
1056           {
1057             emitcode ("pop", "ar1");
1058             _G.r1Pushed--;
1059           }
1060
1061         if (_G.r0Pushed)
1062           {
1063             emitcode ("pop", "ar0");
1064             _G.r0Pushed--;
1065           }
1066       }
1067     }
1068
1069 dealloc:
1070   /* all other cases just dealloc */
1071   if (op)
1072     {
1073       op->aop = NULL;
1074       if (IS_SYMOP (op))
1075         {
1076           OP_SYMBOL (op)->aop = NULL;
1077           /* if the symbol has a spill */
1078           if (SPIL_LOC (op))
1079             SPIL_LOC (op)->aop = NULL;
1080         }
1081     }
1082 }
1083
1084 /*------------------------------------------------------------------*/
1085 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1086 /*                      pop r0 or r1 off stack if pushed            */
1087 /*------------------------------------------------------------------*/
1088 static void
1089 freeForBranchAsmop (operand * op)
1090 {
1091   asmop *aop;
1092
1093   if (!op)
1094     return;
1095
1096   aop = op->aop;
1097
1098   if (!aop)
1099     return;
1100
1101   if (aop->freed)
1102     return;
1103
1104   switch (aop->type)
1105     {
1106     case AOP_R0:
1107       if (R0INB)
1108         {
1109           emitcode ("mov", "r0,b");
1110         }
1111       else if (_G.r0Pushed)
1112         {
1113           emitcode ("pop", "ar0");
1114         }
1115       break;
1116
1117     case AOP_R1:
1118       if (R1INB)
1119         {
1120           emitcode ("mov", "r1,b");
1121         }
1122       else if (_G.r1Pushed)
1123         {
1124           emitcode ("pop", "ar1");
1125         }
1126       break;
1127
1128     case AOP_STK:
1129       {
1130         int sz = aop->size;
1131         int stk = aop->aopu.aop_stk + aop->size - 1;
1132
1133         emitcode ("mov", "b,r0");
1134         if (stk)
1135           {
1136             emitcode ("mov", "a,_bp");
1137             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1138             emitcode ("mov", "r0,a");
1139           }
1140         else
1141           {
1142             emitcode ("mov", "r0,_bp");
1143           }
1144
1145         while (sz--)
1146           {
1147             emitcode ("pop", "acc");
1148             emitcode ("mov", "@r0,a");
1149             if (!sz)
1150               break;
1151             emitcode ("dec", "r0");
1152           }
1153         emitcode ("mov", "r0,b");
1154       }
1155     }
1156
1157 }
1158
1159 /*-----------------------------------------------------------------*/
1160 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1161 /*                 clobber the accumulator                         */
1162 /*-----------------------------------------------------------------*/
1163 static bool
1164 aopGetUsesAcc (operand * oper, int offset)
1165 {
1166   asmop * aop = AOP (oper);
1167
1168   if (offset > (aop->size - 1))
1169     return FALSE;
1170
1171   switch (aop->type)
1172     {
1173
1174     case AOP_R0:
1175     case AOP_R1:
1176       if (aop->paged)
1177         return TRUE;
1178       return FALSE;
1179     case AOP_DPTR:
1180       return TRUE;
1181     case AOP_IMMD:
1182       return FALSE;
1183     case AOP_DIR:
1184       return FALSE;
1185     case AOP_REG:
1186       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1187       return FALSE;
1188     case AOP_CRY:
1189       return TRUE;
1190     case AOP_ACC:
1191       if (offset)
1192         return FALSE;
1193       return TRUE;
1194     case AOP_LIT:
1195       return FALSE;
1196     case AOP_STR:
1197       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1198         return TRUE;
1199       return FALSE;
1200     case AOP_DUMMY:
1201       return FALSE;
1202     default:
1203       /* Error case --- will have been caught already */
1204       wassert(0);
1205       return FALSE;
1206     }
1207 }
1208
1209 /*-----------------------------------------------------------------*/
1210 /* aopGet - for fetching value of the aop                          */
1211 /*-----------------------------------------------------------------*/
1212 static char *
1213 aopGet (operand * oper, int offset, bool bit16, bool dname)
1214 {
1215   char *s = buffer;
1216   char *rs;
1217   asmop * aop = AOP (oper);
1218
1219   /* offset is greater than
1220      size then zero */
1221   if (offset > (aop->size - 1) &&
1222       aop->type != AOP_LIT)
1223     return zero;
1224
1225   /* depending on type */
1226   switch (aop->type)
1227     {
1228     case AOP_DUMMY:
1229       return zero;
1230
1231     case AOP_R0:
1232     case AOP_R1:
1233       /* if we need to increment it */
1234       while (offset > aop->coff)
1235         {
1236           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1237           aop->coff++;
1238         }
1239
1240       while (offset < aop->coff)
1241         {
1242           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1243           aop->coff--;
1244         }
1245
1246       aop->coff = offset;
1247       if (aop->paged)
1248         {
1249           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1250           return (dname ? "acc" : "a");
1251         }
1252       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1253       rs = Safe_calloc (1, strlen (s) + 1);
1254       strcpy (rs, s);
1255       return rs;
1256
1257     case AOP_DPTR:
1258       if (aop->code && aop->coff==0 && offset>=1) {
1259         emitcode ("mov", "a,#0x%02x", offset);
1260         emitcode ("movc", "a,@a+dptr");
1261         return (dname ? "acc" : "a");
1262       }
1263
1264       while (offset > aop->coff)
1265         {
1266           emitcode ("inc", "dptr");
1267           aop->coff++;
1268         }
1269
1270       while (offset < aop->coff)
1271         {
1272           emitcode ("lcall", "__decdptr");
1273           aop->coff--;
1274         }
1275
1276       aop->coff = offset;
1277       if (aop->code)
1278         {
1279           emitcode ("clr", "a");
1280           emitcode ("movc", "a,@a+dptr");
1281         }
1282       else
1283         {
1284           emitcode ("movx", "a,@dptr");
1285         }
1286       return (dname ? "acc" : "a");
1287
1288
1289     case AOP_IMMD:
1290       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1291               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1292       } else if (bit16)
1293         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1294       else if (offset)
1295         sprintf (s, "#(%s >> %d)",
1296                  aop->aopu.aop_immd.aop_immd1,
1297                  offset * 8);
1298       else
1299         sprintf (s, "#%s",
1300                  aop->aopu.aop_immd.aop_immd1);
1301       rs = Safe_calloc (1, strlen (s) + 1);
1302       strcpy (rs, s);
1303       return rs;
1304
1305     case AOP_DIR:
1306       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1307         sprintf (s, "(%s >> %d)",
1308                  aop->aopu.aop_dir, offset * 8);
1309       else if (offset)
1310         sprintf (s, "(%s + %d)",
1311                  aop->aopu.aop_dir,
1312                  offset);
1313       else
1314         sprintf (s, "%s", aop->aopu.aop_dir);
1315       rs = Safe_calloc (1, strlen (s) + 1);
1316       strcpy (rs, s);
1317       return rs;
1318
1319     case AOP_REG:
1320       if (dname)
1321         return aop->aopu.aop_reg[offset]->dname;
1322       else
1323         return aop->aopu.aop_reg[offset]->name;
1324
1325     case AOP_CRY:
1326       emitcode ("clr", "a");
1327       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1328       emitcode ("rlc", "a");
1329       return (dname ? "acc" : "a");
1330
1331     case AOP_ACC:
1332       if (!offset && dname)
1333         return "acc";
1334       return aop->aopu.aop_str[offset];
1335
1336     case AOP_LIT:
1337       return aopLiteral (aop->aopu.aop_lit, offset);
1338
1339     case AOP_STR:
1340       aop->coff = offset;
1341       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1342           dname)
1343         return "acc";
1344
1345       return aop->aopu.aop_str[offset];
1346
1347     }
1348
1349   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1350           "aopget got unsupported aop->type");
1351   exit (1);
1352 }
1353
1354 /*-----------------------------------------------------------------*/
1355 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1356 /*                 clobber the accumulator                         */
1357 /*-----------------------------------------------------------------*/
1358 static bool
1359 aopPutUsesAcc (operand * oper, const char *s, int offset)
1360 {
1361   asmop * aop = AOP (oper);
1362
1363   if (offset > (aop->size - 1))
1364     return FALSE;
1365
1366   switch (aop->type)
1367     {
1368     case AOP_DUMMY:
1369       return TRUE;
1370     case AOP_DIR:
1371       return FALSE;
1372     case AOP_REG:
1373       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1374       return FALSE;
1375     case AOP_DPTR:
1376       return TRUE;
1377     case AOP_R0:
1378     case AOP_R1:
1379       return ((aop->paged) || (*s == '@'));
1380     case AOP_STK:
1381       return (*s == '@');
1382     case AOP_CRY:
1383       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1384     case AOP_STR:
1385       return FALSE;
1386     case AOP_IMMD:
1387       return FALSE;
1388     case AOP_ACC:
1389       return FALSE;
1390     default:
1391       /* Error case --- will have been caught already */
1392       wassert(0);
1393       return FALSE;
1394     }
1395 }
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopPut - puts a string for a aop and indicates if acc is in use */
1399 /*-----------------------------------------------------------------*/
1400 static bool
1401 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1402 {
1403   char *d = buffer;
1404   bool accuse = FALSE;
1405   asmop * aop = AOP (result);
1406
1407   if (aop->size && offset > (aop->size - 1))
1408     {
1409       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1410               "aopPut got offset > aop->size");
1411       exit (1);
1412     }
1413
1414   /* will assign value to value */
1415   /* depending on where it is ofcourse */
1416   switch (aop->type)
1417     {
1418     case AOP_DUMMY:
1419       MOVA (s);         /* read s in case it was volatile */
1420       accuse = TRUE;
1421       break;
1422
1423     case AOP_DIR:
1424       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1425         sprintf (d, "(%s >> %d)", aop->aopu.aop_dir, offset * 8);
1426       else if (offset)
1427         sprintf (d, "(%s + %d)", aop->aopu.aop_dir, offset);
1428       else
1429         sprintf (d, "%s", aop->aopu.aop_dir);
1430
1431       if (strcmp (d, s) || bvolatile)
1432           emitcode ("mov", "%s,%s", d, s);
1433       if (!strcmp (d, "acc"))
1434           accuse = TRUE;
1435
1436       break;
1437
1438     case AOP_REG:
1439       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1440           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1441         {
1442           if (*s == '@' ||
1443               strcmp (s, "r0") == 0 ||
1444               strcmp (s, "r1") == 0 ||
1445               strcmp (s, "r2") == 0 ||
1446               strcmp (s, "r3") == 0 ||
1447               strcmp (s, "r4") == 0 ||
1448               strcmp (s, "r5") == 0 ||
1449               strcmp (s, "r6") == 0 ||
1450               strcmp (s, "r7") == 0)
1451             emitcode ("mov", "%s,%s",
1452                       aop->aopu.aop_reg[offset]->dname, s);
1453           else
1454             emitcode ("mov", "%s,%s",
1455                       aop->aopu.aop_reg[offset]->name, s);
1456         }
1457       break;
1458
1459     case AOP_DPTR:
1460       if (aop->code)
1461         {
1462           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1463                   "aopPut writing to code space");
1464           exit (1);
1465         }
1466
1467       while (offset > aop->coff)
1468         {
1469           aop->coff++;
1470           emitcode ("inc", "dptr");
1471         }
1472
1473       while (offset < aop->coff)
1474         {
1475           aop->coff--;
1476           emitcode ("lcall", "__decdptr");
1477         }
1478
1479       aop->coff = offset;
1480
1481       /* if not in accumulator */
1482       MOVA (s);
1483
1484       emitcode ("movx", "@dptr,a");
1485       break;
1486
1487     case AOP_R0:
1488     case AOP_R1:
1489       while (offset > aop->coff)
1490         {
1491           aop->coff++;
1492           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1493         }
1494       while (offset < aop->coff)
1495         {
1496           aop->coff--;
1497           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1498         }
1499       aop->coff = offset;
1500
1501       if (aop->paged)
1502         {
1503           MOVA (s);
1504           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1505         }
1506       else if (*s == '@')
1507         {
1508           MOVA (s);
1509           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1510         }
1511       else if (strcmp (s, "r0") == 0 ||
1512                strcmp (s, "r1") == 0 ||
1513                strcmp (s, "r2") == 0 ||
1514                strcmp (s, "r3") == 0 ||
1515                strcmp (s, "r4") == 0 ||
1516                strcmp (s, "r5") == 0 ||
1517                strcmp (s, "r6") == 0 ||
1518                strcmp (s, "r7") == 0)
1519         {
1520           char buffer[10];
1521           sprintf (buffer, "a%s", s);
1522           emitcode ("mov", "@%s,%s",
1523                     aop->aopu.aop_ptr->name, buffer);
1524         }
1525       else
1526         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1527
1528       break;
1529
1530     case AOP_STK:
1531       if (strcmp (s, "a") == 0)
1532         emitcode ("push", "acc");
1533       else
1534         if (*s=='@') {
1535           MOVA(s);
1536           emitcode ("push", "acc");
1537         } else {
1538           emitcode ("push", s);
1539         }
1540
1541       break;
1542
1543     case AOP_CRY:
1544       /* if not bit variable */
1545       if (!aop->aopu.aop_dir)
1546         {
1547           /* inefficient: move carry into A and use jz/jnz */
1548           emitcode ("clr", "a");
1549           emitcode ("rlc", "a");
1550           accuse = TRUE;
1551         }
1552       else
1553         {
1554           if (s == zero)
1555             emitcode ("clr", "%s", aop->aopu.aop_dir);
1556           else if (s == one)
1557             emitcode ("setb", "%s", aop->aopu.aop_dir);
1558           else if (!strcmp (s, "c"))
1559             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1560           else if (strcmp (s, aop->aopu.aop_dir))
1561             {
1562               MOVA (s);
1563               /* set C, if a >= 1 */
1564               emitcode ("add", "a,#0xff");
1565               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1566             }
1567         }
1568       break;
1569
1570     case AOP_STR:
1571       aop->coff = offset;
1572       if (strcmp (aop->aopu.aop_str[offset], s) ||
1573           bvolatile)
1574         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1575       break;
1576
1577     case AOP_ACC:
1578       accuse = TRUE;
1579       aop->coff = offset;
1580       if (!offset && (strcmp (s, "acc") == 0) &&
1581           !bvolatile)
1582         break;
1583
1584       if (strcmp (aop->aopu.aop_str[offset], s) &&
1585           !bvolatile)
1586         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1587       break;
1588
1589     default:
1590       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1591               "aopPut got unsupported aop->type");
1592       exit (1);
1593     }
1594
1595     return accuse;
1596 }
1597
1598
1599 #if 0
1600 /*-----------------------------------------------------------------*/
1601 /* pointToEnd :- points to the last byte of the operand            */
1602 /*-----------------------------------------------------------------*/
1603 static void
1604 pointToEnd (asmop * aop)
1605 {
1606   int count;
1607   if (!aop)
1608     return;
1609
1610   aop->coff = count = (aop->size - 1);
1611   switch (aop->type)
1612     {
1613     case AOP_R0:
1614     case AOP_R1:
1615       while (count--)
1616         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1617       break;
1618     case AOP_DPTR:
1619       while (count--)
1620         emitcode ("inc", "dptr");
1621       break;
1622     }
1623
1624 }
1625 #endif
1626
1627 /*-----------------------------------------------------------------*/
1628 /* reAdjustPreg - points a register back to where it should        */
1629 /*-----------------------------------------------------------------*/
1630 static void
1631 reAdjustPreg (asmop * aop)
1632 {
1633   if ((aop->coff==0) || aop->size <= 1)
1634     return;
1635
1636   switch (aop->type)
1637     {
1638     case AOP_R0:
1639     case AOP_R1:
1640       while (aop->coff--)
1641         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1642       break;
1643     case AOP_DPTR:
1644       while (aop->coff--)
1645         {
1646           emitcode ("lcall", "__decdptr");
1647         }
1648       break;
1649     }
1650   aop->coff = 0;
1651 }
1652
1653 /*-----------------------------------------------------------------*/
1654 /* opIsGptr: returns non-zero if the passed operand is       */
1655 /* a generic pointer type.             */
1656 /*-----------------------------------------------------------------*/
1657 static int
1658 opIsGptr (operand * op)
1659 {
1660   sym_link *type = operandType (op);
1661
1662   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1663     {
1664       return 1;
1665     }
1666   return 0;
1667 }
1668
1669 /*-----------------------------------------------------------------*/
1670 /* getDataSize - get the operand data size                         */
1671 /*-----------------------------------------------------------------*/
1672 static int
1673 getDataSize (operand * op)
1674 {
1675   int size;
1676   size = AOP_SIZE (op);
1677   if (size == GPTRSIZE)
1678     {
1679       sym_link *type = operandType (op);
1680       if (IS_GENPTR (type))
1681         {
1682           /* generic pointer; arithmetic operations
1683            * should ignore the high byte (pointer type).
1684            */
1685           size--;
1686         }
1687     }
1688   return size;
1689 }
1690
1691 /*-----------------------------------------------------------------*/
1692 /* outAcc - output Acc                                             */
1693 /*-----------------------------------------------------------------*/
1694 static void
1695 outAcc (operand * result)
1696 {
1697   int size, offset;
1698   size = getDataSize (result);
1699   if (size)
1700     {
1701       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1702       size--;
1703       offset = 1;
1704       /* unsigned or positive */
1705       while (size--)
1706         {
1707           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1708         }
1709     }
1710 }
1711
1712 /*-----------------------------------------------------------------*/
1713 /* outBitC - output a bit C                                        */
1714 /*-----------------------------------------------------------------*/
1715 static void
1716 outBitC (operand * result)
1717 {
1718   /* if the result is bit */
1719   if (AOP_TYPE (result) == AOP_CRY)
1720     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1721   else
1722     {
1723       emitcode ("clr", "a");
1724       emitcode ("rlc", "a");
1725       outAcc (result);
1726     }
1727 }
1728
1729 /*-----------------------------------------------------------------*/
1730 /* toBoolean - emit code for orl a,operator(sizeop)                */
1731 /*-----------------------------------------------------------------*/
1732 static void
1733 toBoolean (operand * oper)
1734 {
1735   int size = AOP_SIZE (oper) - 1;
1736   int offset = 1;
1737   bool AccUsed = FALSE;
1738   bool pushedB;
1739
1740   while (!AccUsed && size--)
1741     {
1742       AccUsed |= aopGetUsesAcc(oper, offset++);
1743     }
1744
1745   size = AOP_SIZE (oper) - 1;
1746   offset = 1;
1747   MOVA (aopGet (oper, 0, FALSE, FALSE));
1748   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1749     {
1750       pushedB = pushB ();
1751       emitcode("mov", "b,a");
1752       while (--size)
1753         {
1754           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1755           emitcode ("orl", "b,a");
1756         }
1757       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1758       emitcode ("orl", "a,b");
1759       popB (pushedB);
1760     }
1761   else
1762     {
1763       while (size--)
1764         {
1765           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1766         }
1767     }
1768 }
1769
1770
1771 /*-----------------------------------------------------------------*/
1772 /* genNot - generate code for ! operation                          */
1773 /*-----------------------------------------------------------------*/
1774 static void
1775 genNot (iCode * ic)
1776 {
1777   symbol *tlbl;
1778
1779   D(emitcode (";     genNot",""));
1780
1781   /* assign asmOps to operand & result */
1782   aopOp (IC_LEFT (ic), ic, FALSE);
1783   aopOp (IC_RESULT (ic), ic, TRUE);
1784
1785   /* if in bit space then a special case */
1786   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1787     {
1788       /* if left==result then cpl bit */
1789       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1790         {
1791           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1792         }
1793       else
1794         {
1795           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1796           emitcode ("cpl", "c");
1797           outBitC (IC_RESULT (ic));
1798         }
1799       goto release;
1800     }
1801
1802   toBoolean (IC_LEFT (ic));
1803
1804   /* set C, if a == 0 */
1805   tlbl = newiTempLabel (NULL);
1806   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1807   emitcode ("", "%05d$:", tlbl->key + 100);
1808   outBitC (IC_RESULT (ic));
1809
1810 release:
1811   /* release the aops */
1812   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1813   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1814 }
1815
1816
1817 /*-----------------------------------------------------------------*/
1818 /* genCpl - generate code for complement                           */
1819 /*-----------------------------------------------------------------*/
1820 static void
1821 genCpl (iCode * ic)
1822 {
1823   int offset = 0;
1824   int size;
1825   symbol *tlbl;
1826   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1827
1828   D(emitcode (";", "genCpl"));
1829
1830   /* assign asmOps to operand & result */
1831   aopOp (IC_LEFT (ic), ic, FALSE);
1832   aopOp (IC_RESULT (ic), ic, TRUE);
1833
1834   /* special case if in bit space */
1835   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1836     {
1837       char *l;
1838
1839       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1840           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1841         {
1842           /* promotion rules are responsible for this strange result:
1843              bit -> int -> ~int -> bit
1844              uchar -> int -> ~int -> bit
1845           */
1846           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1847           goto release;
1848         }
1849
1850       tlbl=newiTempLabel(NULL);
1851       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1852       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1853           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1854           IS_AOP_PREG (IC_LEFT (ic)))
1855         {
1856           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1857         }
1858       else
1859         {
1860           MOVA (l);
1861           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1862         }
1863       emitcode ("", "%05d$:", tlbl->key + 100);
1864       outBitC (IC_RESULT(ic));
1865       goto release;
1866     }
1867
1868   size = AOP_SIZE (IC_RESULT (ic));
1869   while (size--)
1870     {
1871       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1872       MOVA (l);
1873       emitcode ("cpl", "a");
1874       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1875     }
1876
1877
1878 release:
1879   /* release the aops */
1880   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1881   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1882 }
1883
1884 /*-----------------------------------------------------------------*/
1885 /* genUminusFloat - unary minus for floating points                */
1886 /*-----------------------------------------------------------------*/
1887 static void
1888 genUminusFloat (operand * op, operand * result)
1889 {
1890   int size, offset = 0;
1891   char *l;
1892
1893   D(emitcode (";     genUminusFloat",""));
1894
1895   /* for this we just copy and then flip the bit */
1896
1897   size = AOP_SIZE (op) - 1;
1898
1899   while (size--)
1900     {
1901       aopPut (result,
1902               aopGet (op, offset, FALSE, FALSE),
1903               offset,
1904               isOperandVolatile (result, FALSE));
1905       offset++;
1906     }
1907
1908   l = aopGet (op, offset, FALSE, FALSE);
1909
1910   MOVA (l);
1911
1912   emitcode ("cpl", "acc.7");
1913   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1914 }
1915
1916 /*-----------------------------------------------------------------*/
1917 /* genUminus - unary minus code generation                         */
1918 /*-----------------------------------------------------------------*/
1919 static void
1920 genUminus (iCode * ic)
1921 {
1922   int offset, size;
1923   sym_link *optype, *rtype;
1924
1925
1926   D(emitcode (";     genUminus",""));
1927
1928   /* assign asmops */
1929   aopOp (IC_LEFT (ic), ic, FALSE);
1930   aopOp (IC_RESULT (ic), ic, TRUE);
1931
1932   /* if both in bit space then special
1933      case */
1934   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1935       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1936     {
1937
1938       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1939       emitcode ("cpl", "c");
1940       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1941       goto release;
1942     }
1943
1944   optype = operandType (IC_LEFT (ic));
1945   rtype = operandType (IC_RESULT (ic));
1946
1947   /* if float then do float stuff */
1948   if (IS_FLOAT (optype))
1949     {
1950       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1951       goto release;
1952     }
1953
1954   /* otherwise subtract from zero */
1955   size = AOP_SIZE (IC_LEFT (ic));
1956   offset = 0;
1957   //CLRC ;
1958   while (size--)
1959     {
1960       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1961       if (!strcmp (l, "a"))
1962         {
1963           if (offset == 0)
1964             SETC;
1965           emitcode ("cpl", "a");
1966           emitcode ("addc", "a,#0");
1967         }
1968       else
1969         {
1970           if (offset == 0)
1971             CLRC;
1972           emitcode ("clr", "a");
1973           emitcode ("subb", "a,%s", l);
1974         }
1975       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1976     }
1977
1978   /* if any remaining bytes in the result */
1979   /* we just need to propagate the sign   */
1980   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1981     {
1982       emitcode ("rlc", "a");
1983       emitcode ("subb", "a,acc");
1984       while (size--)
1985         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1986     }
1987
1988 release:
1989   /* release the aops */
1990   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1991   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1992 }
1993
1994 /*-----------------------------------------------------------------*/
1995 /* saveRegisters - will look for a call and save the registers     */
1996 /*-----------------------------------------------------------------*/
1997 static void
1998 saveRegisters (iCode * lic)
1999 {
2000   int i;
2001   iCode *ic;
2002   bitVect *rsave;
2003
2004   /* look for call */
2005   for (ic = lic; ic; ic = ic->next)
2006     if (ic->op == CALL || ic->op == PCALL)
2007       break;
2008
2009   if (!ic)
2010     {
2011       fprintf (stderr, "found parameter push with no function call\n");
2012       return;
2013     }
2014
2015   /* if the registers have been saved already or don't need to be then
2016      do nothing */
2017   if (ic->regsSaved)
2018     return;
2019   if (IS_SYMOP(IC_LEFT(ic)) &&
2020       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
2021        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
2022     return;
2023
2024   /* save the registers in use at this time but skip the
2025      ones for the result */
2026   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2027                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2028
2029   ic->regsSaved = 1;
2030   if (options.useXstack)
2031     {
2032       int count = bitVectnBitsOn (rsave);
2033
2034       if (count == 1)
2035         {
2036           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2037           if (reg->type == REG_BIT)
2038             {
2039               emitcode ("mov", "a,%s", reg->base);
2040             }
2041           else
2042             {
2043               emitcode ("mov", "a,%s", reg->name);
2044             }
2045           emitcode ("mov", "r0,%s", spname);
2046           emitcode ("inc", "%s", spname);// allocate before use
2047           emitcode ("movx", "@r0,a");
2048           if (bitVectBitValue (rsave, R0_IDX))
2049             emitcode ("mov", "r0,a");
2050         }
2051       else if (count != 0)
2052         {
2053           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2054           int nBits = bitVectnBitsOn (rsavebits);
2055
2056           if (nBits != 0)
2057             {
2058               count = count - nBits + 1;
2059               /* remove all but the first bits as they are pushed all at once */
2060               rsave = bitVectCplAnd (rsave, rsavebits);
2061               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2062             }
2063
2064           if (bitVectBitValue (rsave, R0_IDX))
2065             {
2066               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2067             }
2068           emitcode ("mov", "r0,%s", spname);
2069           MOVA ("r0");
2070           emitcode ("add", "a,#%d", count);
2071           emitcode ("mov", "%s,a", spname);
2072           for (i = 0; i < mcs51_nRegs; i++)
2073             {
2074               if (bitVectBitValue (rsave, i))
2075                 {
2076                   regs * reg = mcs51_regWithIdx (i);
2077                   if (i == R0_IDX)
2078                     {
2079                       emitcode ("pop", "acc");
2080                       emitcode ("push", "acc");
2081                     }
2082                   else if (reg->type == REG_BIT)
2083                     {
2084                       emitcode ("mov", "a,%s", reg->base);
2085                     }
2086                   else
2087                     {
2088                       emitcode ("mov", "a,%s", reg->name);
2089                     }
2090                   emitcode ("movx", "@r0,a");
2091                   if (--count)
2092                     {
2093                       emitcode ("inc", "r0");
2094                     }
2095                 }
2096             }
2097           if (bitVectBitValue (rsave, R0_IDX))
2098             {
2099               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2100             }
2101         }
2102     }
2103   else
2104     {
2105       bool bits_pushed = FALSE;
2106       for (i = 0; i < mcs51_nRegs; i++)
2107         {
2108           if (bitVectBitValue (rsave, i))
2109             {
2110               bits_pushed = pushReg (i, bits_pushed);
2111             }
2112         }
2113     }
2114 }
2115
2116 /*-----------------------------------------------------------------*/
2117 /* unsaveRegisters - pop the pushed registers                      */
2118 /*-----------------------------------------------------------------*/
2119 static void
2120 unsaveRegisters (iCode * ic)
2121 {
2122   int i;
2123   bitVect *rsave;
2124
2125   /* restore the registers in use at this time but skip the
2126      ones for the result */
2127   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2128                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2129
2130   if (options.useXstack)
2131     {
2132       int count = bitVectnBitsOn (rsave);
2133
2134       if (count == 1)
2135         {
2136           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2137           emitcode ("mov", "r0,%s", spname);
2138           emitcode ("dec", "r0");
2139           emitcode ("movx", "a,@r0");
2140           if (reg->type == REG_BIT)
2141             {
2142               emitcode ("mov", "%s,a", reg->base);
2143             }
2144           else
2145             {
2146               emitcode ("mov", "%s,a", reg->name);
2147             }
2148           emitcode ("dec", "%s", spname);
2149         }
2150       else if (count != 0)
2151         {
2152           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2153           int nBits = bitVectnBitsOn (rsavebits);
2154
2155           if (nBits != 0)
2156             {
2157               count = count - nBits + 1;
2158               /* remove all but the first bits as they are popped all at once */
2159               rsave = bitVectCplAnd (rsave, rsavebits);
2160               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2161             }
2162
2163           emitcode ("mov", "r0,%s", spname);
2164           for (i = mcs51_nRegs; i >= 0; i--)
2165             {
2166               if (bitVectBitValue (rsave, i))
2167                 {
2168                   regs * reg = mcs51_regWithIdx (i);
2169                   emitcode ("dec", "r0");
2170                   emitcode ("movx", "a,@r0");
2171                   if (i == R0_IDX)
2172                     {
2173                       emitcode ("push", "acc");
2174                     }
2175                   else if (reg->type == REG_BIT)
2176                     {
2177                       emitcode ("mov", "%s,a", reg->base);
2178                     }
2179                   else
2180                     {
2181                       emitcode ("mov", "%s,a", reg->name);
2182                     }
2183                 }
2184             }
2185           emitcode ("mov", "%s,r0", spname);
2186           if (bitVectBitValue (rsave, R0_IDX))
2187             {
2188               emitcode ("pop", "ar0");
2189             }
2190         }
2191     }
2192   else
2193     {
2194       bool bits_popped = FALSE;
2195       for (i = mcs51_nRegs; i >= 0; i--)
2196         {
2197           if (bitVectBitValue (rsave, i))
2198             {
2199               bits_popped = popReg (i, bits_popped);
2200             }
2201         }
2202     }
2203 }
2204
2205
2206 /*-----------------------------------------------------------------*/
2207 /* pushSide -                                                      */
2208 /*-----------------------------------------------------------------*/
2209 static void
2210 pushSide (operand * oper, int size)
2211 {
2212   int offset = 0;
2213   while (size--)
2214     {
2215       char *l = aopGet (oper, offset++, FALSE, TRUE);
2216       if (AOP_TYPE (oper) != AOP_REG &&
2217           AOP_TYPE (oper) != AOP_DIR &&
2218           strcmp (l, "a"))
2219         {
2220           MOVA (l);
2221           emitcode ("push", "acc");
2222         }
2223       else
2224         {
2225           emitcode ("push", "%s", l);
2226         }
2227     }
2228 }
2229
2230 /*-----------------------------------------------------------------*/
2231 /* assignResultValue - also indicates if acc is in use afterwards  */
2232 /*-----------------------------------------------------------------*/
2233 static bool
2234 assignResultValue (operand * oper, operand * func)
2235 {
2236   int offset = 0;
2237   int size = AOP_SIZE (oper);
2238   bool accuse = FALSE;
2239   bool pushedA = FALSE;
2240
2241   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2242     {
2243       outBitC (oper);
2244       return FALSE;
2245     }
2246
2247   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2248     {
2249       emitcode ("push", "acc");
2250       pushedA = TRUE;
2251     }
2252   while (size--)
2253     {
2254       if ((offset == 3) && pushedA)
2255         emitcode ("pop", "acc");
2256       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2257       offset++;
2258     }
2259   return accuse;
2260 }
2261
2262
2263 /*-----------------------------------------------------------------*/
2264 /* genXpush - pushes onto the external stack                       */
2265 /*-----------------------------------------------------------------*/
2266 static void
2267 genXpush (iCode * ic)
2268 {
2269   asmop *aop = newAsmop (0);
2270   regs *r;
2271   int size, offset = 0;
2272
2273   D(emitcode (";     genXpush",""));
2274
2275   aopOp (IC_LEFT (ic), ic, FALSE);
2276   r = getFreePtr (ic, &aop, FALSE);
2277
2278   size = AOP_SIZE (IC_LEFT (ic));
2279
2280   if (size == 1)
2281     {
2282       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2283       emitcode ("mov", "%s,%s", r->name, spname);
2284       emitcode ("inc", "%s", spname); // allocate space first
2285       emitcode ("movx", "@%s,a", r->name);
2286     }
2287   else
2288     {
2289       // allocate space first
2290       emitcode ("mov", "%s,%s", r->name, spname);
2291       MOVA (r->name);
2292       emitcode ("add", "a,#%d", size);
2293       emitcode ("mov", "%s,a", spname);
2294
2295       while (size--)
2296         {
2297           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2298           emitcode ("movx", "@%s,a", r->name);
2299           emitcode ("inc", "%s", r->name);
2300         }
2301     }
2302
2303   freeAsmop (NULL, aop, ic, TRUE);
2304   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2305 }
2306
2307 /*-----------------------------------------------------------------*/
2308 /* genIpush - generate code for pushing this gets a little complex */
2309 /*-----------------------------------------------------------------*/
2310 static void
2311 genIpush (iCode * ic)
2312 {
2313   int size, offset = 0;
2314   char *l;
2315   char *prev = "";
2316
2317   D(emitcode (";     genIpush",""));
2318
2319   /* if this is not a parm push : ie. it is spill push
2320      and spill push is always done on the local stack */
2321   if (!ic->parmPush)
2322     {
2323
2324       /* and the item is spilt then do nothing */
2325       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2326         return;
2327
2328       aopOp (IC_LEFT (ic), ic, FALSE);
2329       size = AOP_SIZE (IC_LEFT (ic));
2330       /* push it on the stack */
2331       while (size--)
2332         {
2333           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2334           if (*l == '#')
2335             {
2336               MOVA (l);
2337               l = "acc";
2338             }
2339           emitcode ("push", "%s", l);
2340         }
2341       return;
2342     }
2343
2344   /* this is a parameter push: in this case we call
2345      the routine to find the call and save those
2346      registers that need to be saved */
2347   saveRegisters (ic);
2348
2349   /* if use external stack then call the external
2350      stack pushing routine */
2351   if (options.useXstack)
2352     {
2353       genXpush (ic);
2354       return;
2355     }
2356
2357   /* then do the push */
2358   aopOp (IC_LEFT (ic), ic, FALSE);
2359
2360   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2361   size = AOP_SIZE (IC_LEFT (ic));
2362
2363   while (size--)
2364     {
2365       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2366       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2367           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2368           strcmp (l, "a"))
2369         {
2370           if (strcmp (l, prev) || *l == '@')
2371             MOVA (l);
2372           emitcode ("push", "acc");
2373         }
2374       else
2375         {
2376           emitcode ("push", "%s", l);
2377         }
2378       prev = l;
2379     }
2380
2381   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* genIpop - recover the registers: can happen only for spilling   */
2386 /*-----------------------------------------------------------------*/
2387 static void
2388 genIpop (iCode * ic)
2389 {
2390   int size, offset;
2391
2392   D(emitcode (";     genIpop",""));
2393
2394   /* if the temp was not pushed then */
2395   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2396     return;
2397
2398   aopOp (IC_LEFT (ic), ic, FALSE);
2399   size = AOP_SIZE (IC_LEFT (ic));
2400   offset = (size - 1);
2401   while (size--)
2402     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2403                                    FALSE, TRUE));
2404
2405   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* saveRBank - saves an entire register bank on the stack          */
2410 /*-----------------------------------------------------------------*/
2411 static void
2412 saveRBank (int bank, iCode * ic, bool pushPsw)
2413 {
2414   int i;
2415   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2416   asmop *aop = NULL;
2417   regs *r = NULL;
2418
2419   if (options.useXstack)
2420     {
2421       if (!ic)
2422       {
2423           /* Assume r0 is available for use. */
2424           r = mcs51_regWithIdx (R0_IDX);;
2425       }
2426       else
2427       {
2428           aop = newAsmop (0);
2429           r = getFreePtr (ic, &aop, FALSE);
2430       }
2431       // allocate space first
2432       emitcode ("mov", "%s,%s", r->name, spname);
2433       MOVA (r->name);
2434       emitcode ("add", "a,#%d", count);
2435       emitcode ("mov", "%s,a", spname);
2436     }
2437
2438   for (i = 0; i < mcs51_nRegs; i++)
2439     {
2440       if (options.useXstack)
2441         {
2442           emitcode ("mov", "a,(%s+%d)",
2443                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2444           emitcode ("movx", "@%s,a", r->name);
2445           if (--count)
2446             emitcode ("inc", "%s", r->name);
2447         }
2448       else
2449         emitcode ("push", "(%s+%d)",
2450                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2451     }
2452
2453   if (pushPsw)
2454     {
2455       if (options.useXstack)
2456         {
2457           emitcode ("mov", "a,psw");
2458           emitcode ("movx", "@%s,a", r->name);
2459
2460         }
2461       else
2462         {
2463           emitcode ("push", "psw");
2464         }
2465
2466       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2467     }
2468
2469   if (aop)
2470     {
2471       freeAsmop (NULL, aop, ic, TRUE);
2472     }
2473
2474   if (ic)
2475   {
2476     ic->bankSaved = 1;
2477   }
2478 }
2479
2480 /*-----------------------------------------------------------------*/
2481 /* unsaveRBank - restores the register bank from stack             */
2482 /*-----------------------------------------------------------------*/
2483 static void
2484 unsaveRBank (int bank, iCode * ic, bool popPsw)
2485 {
2486   int i;
2487   asmop *aop = NULL;
2488   regs *r = NULL;
2489
2490   if (options.useXstack)
2491     {
2492       if (!ic)
2493         {
2494           /* Assume r0 is available for use. */
2495           r = mcs51_regWithIdx (R0_IDX);;
2496         }
2497       else
2498         {
2499           aop = newAsmop (0);
2500           r = getFreePtr (ic, &aop, FALSE);
2501         }
2502       emitcode ("mov", "%s,%s", r->name, spname);
2503     }
2504
2505   if (popPsw)
2506     {
2507       if (options.useXstack)
2508         {
2509           emitcode ("dec", "%s", r->name);
2510           emitcode ("movx", "a,@%s", r->name);
2511           emitcode ("mov", "psw,a");
2512         }
2513       else
2514         {
2515           emitcode ("pop", "psw");
2516         }
2517     }
2518
2519   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2520     {
2521       if (options.useXstack)
2522         {
2523           emitcode ("dec", "%s", r->name);
2524           emitcode ("movx", "a,@%s", r->name);
2525           emitcode ("mov", "(%s+%d),a",
2526                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2527         }
2528       else
2529         {
2530           emitcode ("pop", "(%s+%d)",
2531                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2532         }
2533     }
2534
2535   if (options.useXstack)
2536     {
2537       emitcode ("mov", "%s,%s", spname, r->name);
2538     }
2539
2540   if (aop)
2541     {
2542       freeAsmop (NULL, aop, ic, TRUE);
2543     }
2544 }
2545
2546 /*-----------------------------------------------------------------*/
2547 /* genSend - gen code for SEND                                     */
2548 /*-----------------------------------------------------------------*/
2549 static void genSend(set *sendSet)
2550 {
2551   iCode *sic;
2552   int bit_count = 0;
2553
2554   /* first we do all bit parameters */
2555   for (sic = setFirstItem (sendSet); sic;
2556        sic = setNextItem (sendSet))
2557     {
2558       aopOp (IC_LEFT (sic), sic, FALSE);
2559
2560       if (sic->argreg > 12)
2561         {
2562           int bit = sic->argreg-13;
2563
2564           /* if left is a literal then
2565              we know what the value is */
2566           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2567             {
2568               if (((int) operandLitValue (IC_LEFT (sic))))
2569                   emitcode ("setb", "b[%d]", bit);
2570               else
2571                   emitcode ("clr", "b[%d]", bit);
2572             }
2573           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2574             {
2575               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2576                 if (strcmp (l, "c"))
2577                     emitcode ("mov", "c,%s", l);
2578                 emitcode ("mov", "b[%d],c", bit);
2579             }
2580           else
2581             {
2582               /* we need to or */
2583               toBoolean (IC_LEFT (sic));
2584               /* set C, if a >= 1 */
2585               emitcode ("add", "a,#0xff");
2586               emitcode ("mov", "b[%d],c", bit);
2587             }
2588           bit_count++;
2589           BitBankUsed = 1;
2590         }
2591       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2592     }
2593
2594   if (bit_count)
2595     {
2596       saveRegisters (setFirstItem (sendSet));
2597       emitcode ("mov", "bits,b");
2598     }
2599
2600   /* then we do all other parameters */
2601   for (sic = setFirstItem (sendSet); sic;
2602        sic = setNextItem (sendSet))
2603     {
2604       int size, offset = 0;
2605       aopOp (IC_LEFT (sic), sic, FALSE);
2606       size = AOP_SIZE (IC_LEFT (sic));
2607
2608       if (sic->argreg == 1)
2609         {
2610           while (size--)
2611             {
2612               char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2613               if (strcmp (l, fReturn[offset]))
2614                   emitcode ("mov", "%s,%s", fReturn[offset], l);
2615               offset++;
2616             }
2617         }
2618       else if (sic->argreg <= 12)
2619         {
2620           while (size--)
2621             {
2622               emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2623                         aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2624               offset++;
2625             }
2626         }
2627       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2628     }
2629 }
2630
2631 /*-----------------------------------------------------------------*/
2632 /* selectRegBank - emit code to select the register bank           */
2633 /*-----------------------------------------------------------------*/
2634 static void
2635 selectRegBank (short bank, bool keepFlags)
2636 {
2637   /* if f.e. result is in carry */
2638   if (keepFlags)
2639     {
2640       emitcode ("anl", "psw,#0xE7");
2641       if (bank)
2642         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2643     }
2644   else
2645     {
2646       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2647     }
2648 }
2649
2650 /*-----------------------------------------------------------------*/
2651 /* genCall - generates a call statement                            */
2652 /*-----------------------------------------------------------------*/
2653 static void
2654 genCall (iCode * ic)
2655 {
2656   sym_link *dtype;
2657   sym_link *etype;
2658 //  bool restoreBank = FALSE;
2659   bool swapBanks = FALSE;
2660   bool accuse = FALSE;
2661   bool accPushed = FALSE;
2662   bool resultInF0 = FALSE;
2663
2664   D(emitcode(";     genCall",""));
2665
2666   dtype = operandType (IC_LEFT (ic));
2667   etype = getSpec(dtype);
2668   /* if send set is not empty then assign */
2669   if (_G.sendSet)
2670     {
2671         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2672             genSend(reverseSet(_G.sendSet));
2673         } else {
2674             genSend(_G.sendSet);
2675         }
2676
2677       _G.sendSet = NULL;
2678     }
2679
2680   /* if we are calling a not _naked function that is not using
2681      the same register bank then we need to save the
2682      destination registers on the stack */
2683   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2684       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2685        !IFFUNC_ISISR (dtype))
2686     {
2687       swapBanks = TRUE;
2688     }
2689
2690   /* if caller saves & we have not saved then */
2691   if (!ic->regsSaved)
2692       saveRegisters (ic);
2693
2694   if (swapBanks)
2695     {
2696         emitcode ("mov", "psw,#0x%02x",
2697            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2698     }
2699
2700   /* make the call */
2701   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2702     {
2703       if (IFFUNC_CALLEESAVES(dtype))
2704         {
2705           werror (E_BANKED_WITH_CALLEESAVES);
2706         }
2707       else
2708         {
2709           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2710                      OP_SYMBOL (IC_LEFT (ic))->rname :
2711                      OP_SYMBOL (IC_LEFT (ic))->name);
2712
2713           emitcode ("mov", "r0,#%s", l);
2714           emitcode ("mov", "r1,#(%s >> 8)", l);
2715           emitcode ("mov", "r2,#(%s >> 16)", l);
2716           emitcode ("lcall", "__sdcc_banked_call");
2717         }
2718     }
2719   else
2720     {
2721       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2722                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2723                                 OP_SYMBOL (IC_LEFT (ic))->name));
2724     }
2725
2726   if (swapBanks)
2727     {
2728       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2729     }
2730
2731   /* if we need assign a result value */
2732   if ((IS_ITEMP (IC_RESULT (ic)) &&
2733        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2734        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2735         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2736         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2737       IS_TRUE_SYMOP (IC_RESULT (ic)))
2738     {
2739
2740       _G.accInUse++;
2741       aopOp (IC_RESULT (ic), ic, FALSE);
2742       _G.accInUse--;
2743
2744       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2745
2746       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2747     }
2748
2749   /* adjust the stack for parameters if required */
2750   if (ic->parmBytes)
2751     {
2752       int i;
2753       if (ic->parmBytes > 3)
2754         {
2755           if (accuse)
2756             {
2757               emitcode ("push", "acc");
2758               accPushed = TRUE;
2759             }
2760           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2761               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2762             {
2763               emitcode ("mov", "F0,c");
2764               resultInF0 = TRUE;
2765             }
2766
2767           emitcode ("mov", "a,%s", spname);
2768           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2769           emitcode ("mov", "%s,a", spname);
2770
2771           /* unsaveRegisters from xstack needs acc, but */
2772           /* unsaveRegisters from stack needs this popped */
2773           if (accPushed && !options.useXstack)
2774             {
2775               emitcode ("pop", "acc");
2776               accPushed = FALSE;
2777             }
2778         }
2779       else
2780         for (i = 0; i < ic->parmBytes; i++)
2781           emitcode ("dec", "%s", spname);
2782     }
2783
2784   /* if we had saved some registers then unsave them */
2785   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2786     {
2787       if (accuse && !accPushed && options.useXstack)
2788         {
2789           /* xstack needs acc, but doesn't touch normal stack */
2790           emitcode ("push", "acc");
2791           accPushed = TRUE;
2792         }
2793       unsaveRegisters (ic);
2794     }
2795
2796 //  /* if register bank was saved then pop them */
2797 //  if (restoreBank)
2798 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2799
2800   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2801     {
2802       if (resultInF0)
2803           emitcode ("mov", "c,F0");
2804
2805       aopOp (IC_RESULT (ic), ic, FALSE);
2806       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2807       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2808     }
2809
2810   if (accPushed)
2811     emitcode ("pop", "acc");
2812 }
2813
2814 /*-----------------------------------------------------------------*/
2815 /* -10l - generates a call by pointer statement                */
2816 /*-----------------------------------------------------------------*/
2817 static void
2818 genPcall (iCode * ic)
2819 {
2820   sym_link *dtype;
2821   sym_link *etype;
2822   symbol *rlbl = newiTempLabel (NULL);
2823 //  bool restoreBank=FALSE;
2824   bool swapBanks = FALSE;
2825   bool resultInF0 = FALSE;
2826
2827   D(emitcode(";     genPCall",""));
2828
2829   dtype = operandType (IC_LEFT (ic))->next;
2830   etype = getSpec(dtype);
2831   /* if caller saves & we have not saved then */
2832   if (!ic->regsSaved)
2833     saveRegisters (ic);
2834
2835   /* if we are calling a not _naked function that is not using
2836      the same register bank then we need to save the
2837      destination registers on the stack */
2838   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2839       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2840       !IFFUNC_ISISR (dtype))
2841     {
2842 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2843 //    restoreBank=TRUE;
2844       swapBanks = TRUE;
2845       // need caution message to user here
2846     }
2847
2848   if (IS_LITERAL(etype))
2849     {
2850       /* if send set is not empty then assign */
2851       if (_G.sendSet)
2852         {
2853           genSend(reverseSet(_G.sendSet));
2854           _G.sendSet = NULL;
2855         }
2856
2857       if (swapBanks)
2858         {
2859           emitcode ("mov", "psw,#0x%02x",
2860            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2861         }
2862
2863       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2864         {
2865           if (IFFUNC_CALLEESAVES(dtype))
2866             {
2867               werror (E_BANKED_WITH_CALLEESAVES);
2868             }
2869           else
2870             {
2871               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2872
2873               emitcode ("mov", "r0,#%s", l);
2874               emitcode ("mov", "r1,#(%s >> 8)", l);
2875               emitcode ("mov", "r2,#(%s >> 16)", l);
2876               emitcode ("lcall", "__sdcc_banked_call");
2877             }
2878         }
2879       else
2880         {
2881           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2882         }
2883     }
2884   else
2885     {
2886       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2887         {
2888           if (IFFUNC_CALLEESAVES(dtype))
2889             {
2890               werror (E_BANKED_WITH_CALLEESAVES);
2891             }
2892           else
2893             {
2894               aopOp (IC_LEFT (ic), ic, FALSE);
2895
2896               if (!swapBanks)
2897                 {
2898                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2899                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2900                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2901                 }
2902               else
2903                 {
2904                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2905                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2906                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2907                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2908                 }
2909
2910               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2911
2912               /* if send set is not empty then assign */
2913               if (_G.sendSet)
2914                 {
2915                   genSend(reverseSet(_G.sendSet));
2916                   _G.sendSet = NULL;
2917                 }
2918
2919               if (swapBanks)
2920                 {
2921                   emitcode ("mov", "psw,#0x%02x",
2922                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2923                 }
2924
2925               /* make the call */
2926               emitcode ("lcall", "__sdcc_banked_call");
2927             }
2928         }
2929       else
2930         {
2931           /* push the return address on to the stack */
2932           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2933           emitcode ("push", "acc");
2934           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2935           emitcode ("push", "acc");
2936
2937           /* now push the calling address */
2938           aopOp (IC_LEFT (ic), ic, FALSE);
2939
2940           pushSide (IC_LEFT (ic), FPTRSIZE);
2941
2942           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2943
2944           /* if send set is not empty the assign */
2945           if (_G.sendSet)
2946             {
2947               genSend(reverseSet(_G.sendSet));
2948               _G.sendSet = NULL;
2949             }
2950
2951           if (swapBanks)
2952             {
2953               emitcode ("mov", "psw,#0x%02x",
2954                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2955             }
2956
2957           /* make the call */
2958           emitcode ("ret", "");
2959           emitcode ("", "%05d$:", (rlbl->key + 100));
2960         }
2961     }
2962   if (swapBanks)
2963     {
2964       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2965     }
2966
2967   /* if we need assign a result value */
2968   if ((IS_ITEMP (IC_RESULT (ic)) &&
2969        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2970        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2971         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2972       IS_TRUE_SYMOP (IC_RESULT (ic)))
2973     {
2974
2975       _G.accInUse++;
2976       aopOp (IC_RESULT (ic), ic, FALSE);
2977       _G.accInUse--;
2978
2979       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2980
2981       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2982     }
2983
2984   /* adjust the stack for parameters if required */
2985   if (ic->parmBytes)
2986     {
2987       int i;
2988       if (ic->parmBytes > 3)
2989         {
2990           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2991               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2992             {
2993               emitcode ("mov", "F0,c");
2994               resultInF0 = TRUE;
2995             }
2996
2997           emitcode ("mov", "a,%s", spname);
2998           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2999           emitcode ("mov", "%s,a", spname);
3000         }
3001       else
3002         for (i = 0; i < ic->parmBytes; i++)
3003           emitcode ("dec", "%s", spname);
3004
3005     }
3006
3007 //  /* if register bank was saved then unsave them */
3008 //  if (restoreBank)
3009 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3010
3011   /* if we had saved some registers then unsave them */
3012   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3013     unsaveRegisters (ic);
3014
3015   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3016     {
3017       if (resultInF0)
3018           emitcode ("mov", "c,F0");
3019
3020       aopOp (IC_RESULT (ic), ic, FALSE);
3021       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3022       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3023     }
3024 }
3025
3026 /*-----------------------------------------------------------------*/
3027 /* resultRemat - result  is rematerializable                       */
3028 /*-----------------------------------------------------------------*/
3029 static int
3030 resultRemat (iCode * ic)
3031 {
3032   if (SKIP_IC (ic) || ic->op == IFX)
3033     return 0;
3034
3035   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3036     {
3037       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3038       if (sym->remat && !POINTER_SET (ic))
3039         return 1;
3040     }
3041
3042   return 0;
3043 }
3044
3045 #if defined(__BORLANDC__) || defined(_MSC_VER)
3046 #define STRCASECMP stricmp
3047 #else
3048 #define STRCASECMP strcasecmp
3049 #endif
3050
3051 /*-----------------------------------------------------------------*/
3052 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3053 /*-----------------------------------------------------------------*/
3054 static int
3055 regsCmp(void *p1, void *p2)
3056 {
3057   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3058 }
3059
3060 static bool
3061 inExcludeList (char *s)
3062 {
3063   const char *p = setFirstItem(options.excludeRegsSet);
3064
3065   if (p == NULL || STRCASECMP(p, "none") == 0)
3066     return FALSE;
3067
3068
3069   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3070 }
3071
3072 /*-----------------------------------------------------------------*/
3073 /* genFunction - generated code for function entry                 */
3074 /*-----------------------------------------------------------------*/
3075 static void
3076 genFunction (iCode * ic)
3077 {
3078   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3079   sym_link *ftype;
3080   bool     switchedPSW = FALSE;
3081   int      calleesaves_saved_register = -1;
3082   int      stackAdjust = sym->stack;
3083   int      accIsFree = sym->recvSize < 4;
3084   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3085   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3086
3087   _G.nRegsSaved = 0;
3088   /* create the function header */
3089   emitcode (";", "-----------------------------------------");
3090   emitcode (";", " function %s", sym->name);
3091   emitcode (";", "-----------------------------------------");
3092
3093   emitcode ("", "%s:", sym->rname);
3094   ftype = operandType (IC_LEFT (ic));
3095   _G.currentFunc = sym;
3096
3097   if (IFFUNC_ISNAKED(ftype))
3098   {
3099       emitcode(";", "naked function: no prologue.");
3100       return;
3101   }
3102
3103   /* here we need to generate the equates for the
3104      register bank if required */
3105   if (FUNC_REGBANK (ftype) != rbank)
3106     {
3107       int i;
3108
3109       rbank = FUNC_REGBANK (ftype);
3110       for (i = 0; i < mcs51_nRegs; i++)
3111         {
3112           if (regs8051[i].type != REG_BIT)
3113             {
3114               if (strcmp (regs8051[i].base, "0") == 0)
3115                 emitcode ("", "%s = 0x%02x",
3116                           regs8051[i].dname,
3117                           8 * rbank + regs8051[i].offset);
3118               else
3119                 emitcode ("", "%s = %s + 0x%02x",
3120                           regs8051[i].dname,
3121                           regs8051[i].base,
3122                           8 * rbank + regs8051[i].offset);
3123             }
3124         }
3125     }
3126
3127   /* if this is an interrupt service routine then
3128      save acc, b, dpl, dph  */
3129   if (IFFUNC_ISISR (sym->type))
3130     {
3131
3132       if (!inExcludeList ("acc"))
3133         emitcode ("push", "acc");
3134       if (!inExcludeList ("b"))
3135         emitcode ("push", "b");
3136       if (!inExcludeList ("dpl"))
3137         emitcode ("push", "dpl");
3138       if (!inExcludeList ("dph"))
3139         emitcode ("push", "dph");
3140       /* if this isr has no bank i.e. is going to
3141          run with bank 0 , then we need to save more
3142          registers :-) */
3143       if (!FUNC_REGBANK (sym->type))
3144         {
3145
3146           /* if this function does not call any other
3147              function then we can be economical and
3148              save only those registers that are used */
3149           if (!IFFUNC_HASFCALL(sym->type))
3150             {
3151               int i;
3152
3153               /* if any registers used */
3154               if (sym->regsUsed)
3155                 {
3156                   bool bits_pushed = FALSE;
3157                   /* save the registers used */
3158                   for (i = 0; i < sym->regsUsed->size; i++)
3159                     {
3160                       if (bitVectBitValue (sym->regsUsed, i))
3161                         bits_pushed = pushReg (i, bits_pushed);
3162                     }
3163                 }
3164             }
3165           else
3166             {
3167
3168               /* this function has a function call. We cannot
3169                  determines register usage so we will have to push the
3170                  entire bank */
3171                 saveRBank (0, ic, FALSE);
3172                 if (options.parms_in_bank1) {
3173                     int i;
3174                     for (i=0; i < 8 ; i++ ) {
3175                         emitcode ("push","%s",rb1regs[i]);
3176                     }
3177                 }
3178             }
3179         }
3180         else
3181         {
3182             /* This ISR uses a non-zero bank.
3183              *
3184              * We assume that the bank is available for our
3185              * exclusive use.
3186              *
3187              * However, if this ISR calls a function which uses some
3188              * other bank, we must save that bank entirely.
3189              */
3190             unsigned long banksToSave = 0;
3191
3192             if (IFFUNC_HASFCALL(sym->type))
3193             {
3194
3195 #define MAX_REGISTER_BANKS 4
3196
3197                 iCode *i;
3198                 int ix;
3199
3200                 for (i = ic; i; i = i->next)
3201                 {
3202                     if (i->op == ENDFUNCTION)
3203                     {
3204                         /* we got to the end OK. */
3205                         break;
3206                     }
3207
3208                     if (i->op == CALL)
3209                     {
3210                         sym_link *dtype;
3211
3212                         dtype = operandType (IC_LEFT(i));
3213                         if (dtype
3214                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3215                         {
3216                              /* Mark this bank for saving. */
3217                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3218                              {
3219                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3220                              }
3221                              else
3222                              {
3223                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3224                              }
3225
3226                              /* And note that we don't need to do it in
3227                               * genCall.
3228                               */
3229                              i->bankSaved = 1;
3230                         }
3231                     }
3232                     if (i->op == PCALL)
3233                     {
3234                         /* This is a mess; we have no idea what
3235                          * register bank the called function might
3236                          * use.
3237                          *
3238                          * The only thing I can think of to do is
3239                          * throw a warning and hope.
3240                          */
3241                         werror(W_FUNCPTR_IN_USING_ISR);
3242                     }
3243                 }
3244
3245                 if (banksToSave && options.useXstack)
3246                 {
3247                     /* Since we aren't passing it an ic,
3248                      * saveRBank will assume r0 is available to abuse.
3249                      *
3250                      * So switch to our (trashable) bank now, so
3251                      * the caller's R0 isn't trashed.
3252                      */
3253                     emitcode ("push", "psw");
3254                     emitcode ("mov", "psw,#0x%02x",
3255                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3256                     switchedPSW = TRUE;
3257                 }
3258
3259                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3260                 {
3261                      if (banksToSave & (1 << ix))
3262                      {
3263                          saveRBank(ix, NULL, FALSE);
3264                      }
3265                 }
3266             }
3267             // TODO: this needs a closer look
3268             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3269         }
3270
3271       /* Set the register bank to the desired value if nothing else */
3272       /* has done so yet. */
3273       if (!switchedPSW)
3274         {
3275           emitcode ("push", "psw");
3276           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3277         }
3278     }
3279   else
3280     {
3281       /* This is a non-ISR function. The caller has already switched register */
3282       /* banks, if necessary, so just handle the callee-saves option. */
3283
3284       /* if callee-save to be used for this function
3285          then save the registers being used in this function */
3286       if (IFFUNC_CALLEESAVES(sym->type))
3287         {
3288           int i;
3289
3290           /* if any registers used */
3291           if (sym->regsUsed)
3292             {
3293               bool bits_pushed = FALSE;
3294               /* save the registers used */
3295               for (i = 0; i < sym->regsUsed->size; i++)
3296                 {
3297                   if (bitVectBitValue (sym->regsUsed, i))
3298                     {
3299                       /* remember one saved register for later usage */
3300                       if (calleesaves_saved_register < 0)
3301                         calleesaves_saved_register = i;
3302                       bits_pushed = pushReg (i, bits_pushed);
3303                       _G.nRegsSaved++;
3304                     }
3305                 }
3306             }
3307         }
3308     }
3309
3310
3311   if (fReentrant)
3312     {
3313       if (options.useXstack)
3314         {
3315           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3316             {
3317               emitcode ("mov", "r0,%s", spname);
3318               emitcode ("inc", "%s", spname);
3319               emitcode ("xch", "a,_bpx");
3320               emitcode ("movx", "@r0,a");
3321               emitcode ("inc", "r0");
3322               emitcode ("mov", "a,r0");
3323               emitcode ("xch", "a,_bpx");
3324             }
3325           if (sym->stack)
3326             {
3327               emitcode ("push", "_bp");     /* save the callers stack  */
3328               emitcode ("mov", "_bp,sp");
3329             }
3330         }
3331       else
3332         {
3333           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3334             {
3335               /* set up the stack */
3336               emitcode ("push", "_bp");     /* save the callers stack  */
3337               emitcode ("mov", "_bp,sp");
3338             }
3339         }
3340     }
3341
3342   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3343   /* before setting up the stack frame completely. */
3344   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3345     {
3346       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3347
3348       if (rsym->isitmp)
3349         {
3350           if (rsym && rsym->regType == REG_CND)
3351             rsym = NULL;
3352           if (rsym && (rsym->accuse || rsym->ruonly))
3353             rsym = NULL;
3354           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3355             rsym = rsym->usl.spillLoc;
3356         }
3357
3358       /* If the RECEIVE operand immediately spills to the first entry on the */
3359       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3360       /* rather than the usual @r0/r1 machinations. */
3361       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3362         {
3363           int ofs;
3364
3365           _G.current_iCode = ric;
3366           D(emitcode (";     genReceive",""));
3367           for (ofs=0; ofs < sym->recvSize; ofs++)
3368             {
3369               if (!strcmp (fReturn[ofs], "a"))
3370                 emitcode ("push", "acc");
3371               else
3372                 emitcode ("push", fReturn[ofs]);
3373             }
3374           stackAdjust -= sym->recvSize;
3375           if (stackAdjust<0)
3376             {
3377               assert (stackAdjust>=0);
3378               stackAdjust = 0;
3379             }
3380           _G.current_iCode = ic;
3381           ric->generated = 1;
3382           accIsFree = 1;
3383         }
3384       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3385       /* to free up the accumulator. */
3386       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3387         {
3388           int ofs;
3389
3390           _G.current_iCode = ric;
3391           D(emitcode (";     genReceive",""));
3392           for (ofs=0; ofs < sym->recvSize; ofs++)
3393             {
3394               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3395             }
3396           _G.current_iCode = ic;
3397           ric->generated = 1;
3398           accIsFree = 1;
3399         }
3400     }
3401
3402   /* adjust the stack for the function */
3403   if (stackAdjust)
3404     {
3405       int i = stackAdjust;
3406       if (i > 256)
3407         werror (W_STACK_OVERFLOW, sym->name);
3408
3409       if (i > 3 && accIsFree)
3410         {
3411           emitcode ("mov", "a,sp");
3412           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3413           emitcode ("mov", "sp,a");
3414         }
3415       else if (i > 5)
3416         {
3417           /* The accumulator is not free, so we will need another register */
3418           /* to clobber. No need to worry about a possible conflict with */
3419           /* the above early RECEIVE optimizations since they would have */
3420           /* freed the accumulator if they were generated. */
3421
3422           if (IFFUNC_CALLEESAVES(sym->type))
3423             {
3424               /* if it's a callee-saves function we need a saved register */
3425               if (calleesaves_saved_register >= 0)
3426                 {
3427                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3428                   emitcode ("mov", "a,sp");
3429                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3430                   emitcode ("mov", "sp,a");
3431                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3432                 }
3433               else
3434                 /* do it the hard way */
3435                 while (i--)
3436                   emitcode ("inc", "sp");
3437             }
3438           else
3439             {
3440               /* not callee-saves, we can clobber r0 */
3441               emitcode ("mov", "r0,a");
3442               emitcode ("mov", "a,sp");
3443               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3444               emitcode ("mov", "sp,a");
3445               emitcode ("mov", "a,r0");
3446             }
3447         }
3448       else
3449         while (i--)
3450           emitcode ("inc", "sp");
3451     }
3452
3453   if (sym->xstack)
3454     {
3455       char i = ((char) sym->xstack & 0xff);
3456
3457       if (i > 3 && accIsFree)
3458         {
3459           emitcode ("mov", "a,_spx");
3460           emitcode ("add", "a,#0x%02x", i);
3461           emitcode ("mov", "_spx,a");
3462         }
3463       else if (i > 5)
3464         {
3465           emitcode ("push", "acc");
3466           emitcode ("mov", "a,_spx");
3467           emitcode ("add", "a,#0x%02x", i);
3468           emitcode ("mov", "_spx,a");
3469           emitcode ("pop", "acc");
3470         }
3471       else
3472         {
3473           while (i--)
3474             emitcode ("inc", "_spx");
3475         }
3476     }
3477
3478   /* if critical function then turn interrupts off */
3479   if (IFFUNC_ISCRITICAL (ftype))
3480     {
3481       symbol *tlbl = newiTempLabel (NULL);
3482       emitcode ("setb", "c");
3483       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3484       emitcode ("clr", "c");
3485       emitcode ("", "%05d$:", (tlbl->key + 100));
3486       emitcode ("push", "psw"); /* save old ea via c in psw */
3487     }
3488 }
3489
3490 /*-----------------------------------------------------------------*/
3491 /* genEndFunction - generates epilogue for functions               */
3492 /*-----------------------------------------------------------------*/
3493 static void
3494 genEndFunction (iCode * ic)
3495 {
3496   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3497   lineNode *lnp = lineCurr;
3498   bitVect  *regsUsed;
3499   bitVect  *regsUsedPrologue;
3500   bitVect  *regsUnneeded;
3501   int      idx;
3502
3503   _G.currentFunc = NULL;
3504   if (IFFUNC_ISNAKED(sym->type))
3505   {
3506       emitcode(";", "naked function: no epilogue.");
3507       if (options.debug && currFunc)
3508         debugFile->writeEndFunction (currFunc, ic, 0);
3509       return;
3510   }
3511
3512   if (IFFUNC_ISCRITICAL (sym->type))
3513     {
3514       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3515         {
3516           emitcode ("rlc", "a");   /* save c in a */
3517           emitcode ("pop", "psw"); /* restore ea via c in psw */
3518           emitcode ("mov", "ea,c");
3519           emitcode ("rrc", "a");   /* restore c from a */
3520         }
3521       else
3522         {
3523           emitcode ("pop", "psw"); /* restore ea via c in psw */
3524           emitcode ("mov", "ea,c");
3525         }
3526     }
3527
3528   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3529     {
3530       if (options.useXstack)
3531         {
3532           if (sym->stack)
3533             {
3534               emitcode ("mov", "sp,_bp");
3535               emitcode ("pop", "_bp");
3536             }
3537           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3538             {
3539               emitcode ("xch", "a,_bpx");
3540               emitcode ("mov", "r0,a");
3541               emitcode ("dec", "r0");
3542               emitcode ("movx", "a,@r0");
3543               emitcode ("xch", "a,_bpx");
3544               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3545             }
3546         }
3547       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3548         {
3549           emitcode ("mov", "sp,_bp");
3550           emitcode ("pop", "_bp");
3551         }
3552     }
3553
3554   /* restore the register bank  */
3555   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3556   {
3557     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3558      || !options.useXstack)
3559     {
3560         /* Special case of ISR using non-zero bank with useXstack
3561          * is handled below.
3562          */
3563         emitcode ("pop", "psw");
3564     }
3565   }
3566
3567   if (IFFUNC_ISISR (sym->type))
3568     {
3569
3570       /* now we need to restore the registers */
3571       /* if this isr has no bank i.e. is going to
3572          run with bank 0 , then we need to save more
3573          registers :-) */
3574       if (!FUNC_REGBANK (sym->type))
3575         {
3576           /* if this function does not call any other
3577              function then we can be economical and
3578              save only those registers that are used */
3579           if (!IFFUNC_HASFCALL(sym->type))
3580             {
3581               int i;
3582
3583               /* if any registers used */
3584               if (sym->regsUsed)
3585                 {
3586                   bool bits_popped = FALSE;
3587                   /* save the registers used */
3588                   for (i = sym->regsUsed->size; i >= 0; i--)
3589                     {
3590                       if (bitVectBitValue (sym->regsUsed, i))
3591                         bits_popped = popReg (i, bits_popped);
3592                     }
3593                 }
3594             }
3595           else
3596             {
3597               if (options.parms_in_bank1) {
3598                   int i;
3599                   for (i = 7 ; i >= 0 ; i-- ) {
3600                       emitcode ("pop","%s",rb1regs[i]);
3601                   }
3602               }
3603               /* this function has  a function call cannot
3604                  determines register usage so we will have to pop the
3605                  entire bank */
3606               unsaveRBank (0, ic, FALSE);
3607             }
3608         }
3609         else
3610         {
3611             /* This ISR uses a non-zero bank.
3612              *
3613              * Restore any register banks saved by genFunction
3614              * in reverse order.
3615              */
3616             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3617             int ix;
3618
3619             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3620             {
3621                 if (savedBanks & (1 << ix))
3622                 {
3623                     unsaveRBank(ix, NULL, FALSE);
3624                 }
3625             }
3626
3627             if (options.useXstack)
3628             {
3629                 /* Restore bank AFTER calling unsaveRBank,
3630                  * since it can trash r0.
3631                  */
3632                 emitcode ("pop", "psw");
3633             }
3634         }
3635
3636       if (!inExcludeList ("dph"))
3637         emitcode ("pop", "dph");
3638       if (!inExcludeList ("dpl"))
3639         emitcode ("pop", "dpl");
3640       if (!inExcludeList ("b"))
3641         emitcode ("pop", "b");
3642       if (!inExcludeList ("acc"))
3643         emitcode ("pop", "acc");
3644
3645       /* if debug then send end of function */
3646       if (options.debug && currFunc)
3647         {
3648           debugFile->writeEndFunction (currFunc, ic, 1);
3649         }
3650
3651       emitcode ("reti", "");
3652     }
3653   else
3654     {
3655       if (IFFUNC_CALLEESAVES(sym->type))
3656         {
3657           int i;
3658
3659           /* if any registers used */
3660           if (sym->regsUsed)
3661             {
3662               /* save the registers used */
3663               for (i = sym->regsUsed->size; i >= 0; i--)
3664                 {
3665                   if (bitVectBitValue (sym->regsUsed, i) ||
3666                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3667                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3668                 }
3669             }
3670           else if (mcs51_ptrRegReq)
3671             {
3672               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3673               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3674             }
3675
3676         }
3677
3678       /* if debug then send end of function */
3679       if (options.debug && currFunc)
3680         {
3681           debugFile->writeEndFunction (currFunc, ic, 1);
3682         }
3683
3684       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3685         {
3686           emitcode ("ljmp", "__sdcc_banked_ret");
3687         }
3688       else
3689         {
3690           emitcode ("ret", "");
3691         }
3692     }
3693
3694   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3695     return;
3696
3697   /* If this was an interrupt handler using bank 0 that called another */
3698   /* function, then all registers must be saved; nothing to optimized. */
3699   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3700       && !FUNC_REGBANK(sym->type))
3701     return;
3702
3703   /* There are no push/pops to optimize if not callee-saves or ISR */
3704   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3705     return;
3706
3707   /* If there were stack parameters, we cannot optimize without also    */
3708   /* fixing all of the stack offsets; this is too dificult to consider. */
3709   if (FUNC_HASSTACKPARM(sym->type))
3710     return;
3711
3712   /* Compute the registers actually used */
3713   regsUsed = newBitVect (mcs51_nRegs);
3714   regsUsedPrologue = newBitVect (mcs51_nRegs);
3715   while (lnp)
3716     {
3717       if (lnp->ic && lnp->ic->op == FUNCTION)
3718         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3719       else
3720         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3721
3722       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3723           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3724         break;
3725       if (!lnp->prev)
3726         break;
3727       lnp = lnp->prev;
3728     }
3729
3730   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3731       && !bitVectBitValue (regsUsed, CND_IDX))
3732     {
3733       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3734       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3735           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3736         bitVectUnSetBit (regsUsed, CND_IDX);
3737     }
3738   else
3739     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3740
3741   /* If this was an interrupt handler that called another function */
3742   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3743   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3744     {
3745       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3746       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3747       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3748       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3749       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3750     }
3751
3752   /* Remove the unneeded push/pops */
3753   regsUnneeded = newBitVect (mcs51_nRegs);
3754   while (lnp)
3755     {
3756       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3757         {
3758           if (!strncmp(lnp->line, "push", 4))
3759             {
3760               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3761               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3762                 {
3763                   connectLine (lnp->prev, lnp->next);
3764                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3765                 }
3766             }
3767           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3768             {
3769               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3770               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3771                 {
3772                   connectLine (lnp->prev, lnp->next);
3773                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3774                 }
3775             }
3776         }
3777       lnp = lnp->next;
3778     }
3779
3780   for (idx = 0; idx < regsUnneeded->size; idx++)
3781     if (bitVectBitValue (regsUnneeded, idx))
3782       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3783
3784   freeBitVect (regsUnneeded);
3785   freeBitVect (regsUsed);
3786   freeBitVect (regsUsedPrologue);
3787 }
3788
3789 /*-----------------------------------------------------------------*/
3790 /* genRet - generate code for return statement                     */
3791 /*-----------------------------------------------------------------*/
3792 static void
3793 genRet (iCode * ic)
3794 {
3795   int size, offset = 0, pushed = 0;
3796
3797   D(emitcode (";     genRet",""));
3798
3799   /* if we have no return value then
3800      just generate the "ret" */
3801   if (!IC_LEFT (ic))
3802     goto jumpret;
3803
3804   /* we have something to return then
3805      move the return value into place */
3806   aopOp (IC_LEFT (ic), ic, FALSE);
3807   size = AOP_SIZE (IC_LEFT (ic));
3808
3809
3810   if (IS_BIT(_G.currentFunc->etype))
3811     {
3812       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3813       size = 0;
3814     }
3815
3816   while (size--)
3817     {
3818       char *l;
3819       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3820         {
3821           /* #NOCHANGE */
3822           l = aopGet (IC_LEFT (ic), offset++,
3823                       FALSE, TRUE);
3824           emitcode ("push", "%s", l);
3825           pushed++;
3826         }
3827       else
3828         {
3829           l = aopGet (IC_LEFT (ic), offset,
3830                       FALSE, FALSE);
3831           if (strcmp (fReturn[offset], l))
3832             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3833         }
3834     }
3835
3836   while (pushed)
3837     {
3838       pushed--;
3839       if (strcmp (fReturn[pushed], "a"))
3840         emitcode ("pop", fReturn[pushed]);
3841       else
3842         emitcode ("pop", "acc");
3843     }
3844   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3845
3846 jumpret:
3847   /* generate a jump to the return label
3848      if the next is not the return statement */
3849   if (!(ic->next && ic->next->op == LABEL &&
3850         IC_LABEL (ic->next) == returnLabel))
3851
3852     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3853
3854 }
3855
3856 /*-----------------------------------------------------------------*/
3857 /* genLabel - generates a label                                    */
3858 /*-----------------------------------------------------------------*/
3859 static void
3860 genLabel (iCode * ic)
3861 {
3862   /* special case never generate */
3863   if (IC_LABEL (ic) == entryLabel)
3864     return;
3865
3866   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3867 }
3868
3869 /*-----------------------------------------------------------------*/
3870 /* genGoto - generates a ljmp                                      */
3871 /*-----------------------------------------------------------------*/
3872 static void
3873 genGoto (iCode * ic)
3874 {
3875   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3876 }
3877
3878 /*-----------------------------------------------------------------*/
3879 /* findLabelBackwards: walks back through the iCode chain looking  */
3880 /* for the given label. Returns number of iCode instructions     */
3881 /* between that label and given ic.          */
3882 /* Returns zero if label not found.          */
3883 /*-----------------------------------------------------------------*/
3884 static int
3885 findLabelBackwards (iCode * ic, int key)
3886 {
3887   int count = 0;
3888
3889   while (ic->prev)
3890     {
3891       ic = ic->prev;
3892       count++;
3893
3894       /* If we have any pushes or pops, we cannot predict the distance.
3895          I don't like this at all, this should be dealt with in the
3896          back-end */
3897       if (ic->op == IPUSH || ic->op == IPOP) {
3898         return 0;
3899       }
3900
3901       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3902         {
3903           return count;
3904         }
3905     }
3906
3907   return 0;
3908 }
3909
3910 /*-----------------------------------------------------------------*/
3911 /* genPlusIncr :- does addition with increment if possible         */
3912 /*-----------------------------------------------------------------*/
3913 static bool
3914 genPlusIncr (iCode * ic)
3915 {
3916   unsigned int icount;
3917   unsigned int size = getDataSize (IC_RESULT (ic));
3918
3919   /* will try to generate an increment */
3920   /* if the right side is not a literal
3921      we cannot */
3922   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3923     return FALSE;
3924
3925   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3926
3927   D(emitcode (";     genPlusIncr",""));
3928
3929   /* if increment >=16 bits in register or direct space */
3930   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3931       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3932       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3933       (size > 1) &&
3934       (icount == 1))
3935     {
3936       symbol *tlbl;
3937       int emitTlbl;
3938       int labelRange;
3939
3940       /* If the next instruction is a goto and the goto target
3941        * is < 10 instructions previous to this, we can generate
3942        * jumps straight to that target.
3943        */
3944       if (ic->next && ic->next->op == GOTO
3945           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3946           && labelRange <= 10)
3947         {
3948           emitcode (";", "tail increment optimized");
3949           tlbl = IC_LABEL (ic->next);
3950           emitTlbl = 0;
3951         }
3952       else
3953         {
3954           tlbl = newiTempLabel (NULL);
3955           emitTlbl = 1;
3956         }
3957       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3958       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3959           IS_AOP_PREG (IC_RESULT (ic)))
3960         emitcode ("cjne", "%s,#0x00,%05d$",
3961                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3962                   tlbl->key + 100);
3963       else
3964         {
3965           emitcode ("clr", "a");
3966           emitcode ("cjne", "a,%s,%05d$",
3967                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3968                     tlbl->key + 100);
3969         }
3970
3971       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3972       if (size > 2)
3973         {
3974           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3975               IS_AOP_PREG (IC_RESULT (ic)))
3976             emitcode ("cjne", "%s,#0x00,%05d$",
3977                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3978                       tlbl->key + 100);
3979           else
3980             emitcode ("cjne", "a,%s,%05d$",
3981                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3982                       tlbl->key + 100);
3983
3984           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3985         }
3986       if (size > 3)
3987         {
3988           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3989               IS_AOP_PREG (IC_RESULT (ic)))
3990             emitcode ("cjne", "%s,#0x00,%05d$",
3991                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3992                       tlbl->key + 100);
3993           else
3994             {
3995               emitcode ("cjne", "a,%s,%05d$",
3996                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3997                         tlbl->key + 100);
3998             }
3999           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4000         }
4001
4002       if (emitTlbl)
4003         {
4004           emitcode ("", "%05d$:", tlbl->key + 100);
4005         }
4006       return TRUE;
4007     }
4008
4009   /* if result is dptr */
4010   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4011       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4012       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4013       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4014     {
4015       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4016         return FALSE;
4017
4018       if (icount > 9)
4019         return FALSE;
4020
4021       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4022         return FALSE;
4023
4024       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
4025       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
4026       while (icount--)
4027         emitcode ("inc", "dptr");
4028
4029       return TRUE;
4030     }
4031
4032   /* if the literal value of the right hand side
4033      is greater than 4 then it is not worth it */
4034   if (icount > 4)
4035     return FALSE;
4036
4037   /* if the sizes are greater than 1 then we cannot */
4038   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4039       AOP_SIZE (IC_LEFT (ic)) > 1)
4040     return FALSE;
4041
4042   /* we can if the aops of the left & result match or
4043      if they are in registers and the registers are the
4044      same */
4045   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4046     {
4047
4048       if (icount > 3)
4049         {
4050           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4051           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4052           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4053         }
4054       else
4055         {
4056
4057           while (icount--)
4058             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4059         }
4060
4061       return TRUE;
4062     }
4063
4064   return FALSE;
4065 }
4066
4067 /*-----------------------------------------------------------------*/
4068 /* outBitAcc - output a bit in acc                                 */
4069 /*-----------------------------------------------------------------*/
4070 static void
4071 outBitAcc (operand * result)
4072 {
4073   symbol *tlbl = newiTempLabel (NULL);
4074   /* if the result is a bit */
4075   if (AOP_TYPE (result) == AOP_CRY)
4076     {
4077       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4078     }
4079   else
4080     {
4081       emitcode ("jz", "%05d$", tlbl->key + 100);
4082       emitcode ("mov", "a,%s", one);
4083       emitcode ("", "%05d$:", tlbl->key + 100);
4084       outAcc (result);
4085     }
4086 }
4087
4088 /*-----------------------------------------------------------------*/
4089 /* genPlusBits - generates code for addition of two bits           */
4090 /*-----------------------------------------------------------------*/
4091 static void
4092 genPlusBits (iCode * ic)
4093 {
4094   D(emitcode (";     genPlusBits",""));
4095
4096   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4097     {
4098       symbol *lbl = newiTempLabel (NULL);
4099       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4100       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4101       emitcode ("cpl", "c");
4102       emitcode ("", "%05d$:", (lbl->key + 100));
4103       outBitC (IC_RESULT (ic));
4104     }
4105   else
4106     {
4107       emitcode ("clr", "a");
4108       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4109       emitcode ("rlc", "a");
4110       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4111       emitcode ("addc", "a,#0x00");
4112       outAcc (IC_RESULT (ic));
4113     }
4114 }
4115
4116 #if 0
4117 /* This is the original version of this code.
4118
4119  * This is being kept around for reference,
4120  * because I am not entirely sure I got it right...
4121  */
4122 static void
4123 adjustArithmeticResult (iCode * ic)
4124 {
4125   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4126       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4127       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4128     aopPut (IC_RESULT (ic),
4129             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4130             2,
4131             isOperandVolatile (IC_RESULT (ic), FALSE));
4132
4133   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4134       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4135       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4136     aopPut (IC_RESULT (ic),
4137             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4138             2,
4139             isOperandVolatile (IC_RESULT (ic), FALSE));
4140
4141   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4142       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4143       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4144       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4145       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4146     {
4147       char buffer[5];
4148       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4149       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4150     }
4151 }
4152 #else
4153 /* This is the pure and virtuous version of this code.
4154  * I'm pretty certain it's right, but not enough to toss the old
4155  * code just yet...
4156  */
4157 static void
4158 adjustArithmeticResult (iCode * ic)
4159 {
4160   if (opIsGptr (IC_RESULT (ic)) &&
4161       opIsGptr (IC_LEFT (ic)) &&
4162       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4163     {
4164       aopPut (IC_RESULT (ic),
4165               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4166               GPTRSIZE - 1,
4167               isOperandVolatile (IC_RESULT (ic), FALSE));
4168     }
4169
4170   if (opIsGptr (IC_RESULT (ic)) &&
4171       opIsGptr (IC_RIGHT (ic)) &&
4172       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4173     {
4174       aopPut (IC_RESULT (ic),
4175               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4176               GPTRSIZE - 1,
4177               isOperandVolatile (IC_RESULT (ic), FALSE));
4178     }
4179
4180   if (opIsGptr (IC_RESULT (ic)) &&
4181       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4182       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4183       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4184       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4185     {
4186       char buffer[5];
4187       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4188       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4189     }
4190 }
4191 #endif
4192
4193 /*-----------------------------------------------------------------*/
4194 /* genPlus - generates code for addition                           */
4195 /*-----------------------------------------------------------------*/
4196 static void
4197 genPlus (iCode * ic)
4198 {
4199   int size, offset = 0;
4200   int skip_bytes = 0;
4201   char *add = "add";
4202   operand *leftOp, *rightOp;
4203   operand * op;
4204
4205   /* special cases :- */
4206
4207   D(emitcode (";     genPlus",""));
4208
4209   aopOp (IC_LEFT (ic), ic, FALSE);
4210   aopOp (IC_RIGHT (ic), ic, FALSE);
4211   aopOp (IC_RESULT (ic), ic, TRUE);
4212
4213   /* if literal, literal on the right or
4214      if left requires ACC or right is already
4215      in ACC */
4216   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4217       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4218       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4219     {
4220       operand *t = IC_RIGHT (ic);
4221       IC_RIGHT (ic) = IC_LEFT (ic);
4222       IC_LEFT (ic) = t;
4223     }
4224
4225   /* if both left & right are in bit
4226      space */
4227   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4228       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4229     {
4230       genPlusBits (ic);
4231       goto release;
4232     }
4233
4234   /* if left in bit space & right literal */
4235   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4236       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4237     {
4238       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4239       /* if result in bit space */
4240       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4241         {
4242           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4243             emitcode ("cpl", "c");
4244           outBitC (IC_RESULT (ic));
4245         }
4246       else
4247         {
4248           size = getDataSize (IC_RESULT (ic));
4249           while (size--)
4250             {
4251               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4252               emitcode ("addc", "a,#00");
4253               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4254             }
4255         }
4256       goto release;
4257     }
4258
4259   /* if I can do an increment instead
4260      of add then GOOD for ME */
4261   if (genPlusIncr (ic) == TRUE)
4262     goto release;
4263
4264   size = getDataSize (IC_RESULT (ic));
4265   leftOp = IC_LEFT(ic);
4266   rightOp = IC_RIGHT(ic);
4267   op=IC_LEFT(ic);
4268
4269   /* if this is an add for an array access
4270      at a 256 byte boundary */
4271   if ( 2 == size
4272        && AOP_TYPE (op) == AOP_IMMD
4273        && IS_SYMOP (op)
4274        && IS_SPEC (OP_SYM_ETYPE (op))
4275        && SPEC_ABSA (OP_SYM_ETYPE (op))
4276        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4277      )
4278     {
4279       D(emitcode (";     genPlus aligned array",""));
4280       aopPut (IC_RESULT (ic),
4281               aopGet (rightOp, 0, FALSE, FALSE),
4282               0,
4283               isOperandVolatile (IC_RESULT (ic), FALSE));
4284
4285       if( 1 == getDataSize (IC_RIGHT (ic)) )
4286         {
4287           aopPut (IC_RESULT (ic),
4288                   aopGet (leftOp, 1, FALSE, FALSE),
4289                   1,
4290                   isOperandVolatile (IC_RESULT (ic), FALSE));
4291         }
4292       else
4293         {
4294           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4295           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4296           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4297         }
4298       goto release;
4299     }
4300
4301   /* if the lower bytes of a literal are zero skip the addition */
4302   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4303     {
4304        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4305               (skip_bytes+1 < size))
4306          {
4307            skip_bytes++;
4308          }
4309        if (skip_bytes)
4310          D(emitcode (";     genPlus shortcut",""));
4311     }
4312
4313   while (size--)
4314     {
4315       if( offset >= skip_bytes )
4316         {
4317           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4318             {
4319               bool pushedB;
4320               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4321               pushedB = pushB ();
4322               emitcode("xch", "a,b");
4323               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4324               emitcode (add, "a,b");
4325               popB (pushedB);
4326             }
4327           else if (aopGetUsesAcc (leftOp, offset))
4328             {
4329               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4330               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4331             }
4332           else
4333             {
4334               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4335               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4336             }
4337           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4338           add = "addc";  /* further adds must propagate carry */
4339         }
4340       else
4341         {
4342           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4343               isOperandVolatile (IC_RESULT (ic), FALSE))
4344             {
4345               /* just move */
4346               aopPut (IC_RESULT (ic),
4347                       aopGet (leftOp, offset, FALSE, FALSE),
4348                       offset,
4349                       isOperandVolatile (IC_RESULT (ic), FALSE));
4350             }
4351         }
4352       offset++;
4353     }
4354
4355   adjustArithmeticResult (ic);
4356
4357 release:
4358   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4359   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4360   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4361 }
4362
4363 /*-----------------------------------------------------------------*/
4364 /* genMinusDec :- does subtraction with decrement if possible      */
4365 /*-----------------------------------------------------------------*/
4366 static bool
4367 genMinusDec (iCode * ic)
4368 {
4369   unsigned int icount;
4370   unsigned int size = getDataSize (IC_RESULT (ic));
4371
4372   /* will try to generate an increment */
4373   /* if the right side is not a literal
4374      we cannot */
4375   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4376     return FALSE;
4377
4378   /* if the literal value of the right hand side
4379      is greater than 4 then it is not worth it */
4380   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4381     return FALSE;
4382
4383   D(emitcode (";     genMinusDec",""));
4384
4385   /* if decrement >=16 bits in register or direct space */
4386   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4387       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4388       (size > 1) &&
4389       (icount == 1))
4390     {
4391       symbol *tlbl;
4392       int emitTlbl;
4393       int labelRange;
4394
4395       /* If the next instruction is a goto and the goto target
4396        * is <= 10 instructions previous to this, we can generate
4397        * jumps straight to that target.
4398        */
4399       if (ic->next && ic->next->op == GOTO
4400           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4401           && labelRange <= 10)
4402         {
4403           emitcode (";", "tail decrement optimized");
4404           tlbl = IC_LABEL (ic->next);
4405           emitTlbl = 0;
4406         }
4407       else
4408         {
4409           tlbl = newiTempLabel (NULL);
4410           emitTlbl = 1;
4411         }
4412
4413       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4414       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4415           IS_AOP_PREG (IC_RESULT (ic)))
4416         emitcode ("cjne", "%s,#0xff,%05d$"
4417                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4418                   ,tlbl->key + 100);
4419       else
4420         {
4421           emitcode ("mov", "a,#0xff");
4422           emitcode ("cjne", "a,%s,%05d$"
4423                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4424                     ,tlbl->key + 100);
4425         }
4426       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4427       if (size > 2)
4428         {
4429           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4430               IS_AOP_PREG (IC_RESULT (ic)))
4431             emitcode ("cjne", "%s,#0xff,%05d$"
4432                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4433                       ,tlbl->key + 100);
4434           else
4435             {
4436               emitcode ("cjne", "a,%s,%05d$"
4437                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4438                         ,tlbl->key + 100);
4439             }
4440           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4441         }
4442       if (size > 3)
4443         {
4444           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4445               IS_AOP_PREG (IC_RESULT (ic)))
4446             emitcode ("cjne", "%s,#0xff,%05d$"
4447                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4448                       ,tlbl->key + 100);
4449           else
4450             {
4451               emitcode ("cjne", "a,%s,%05d$"
4452                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4453                         ,tlbl->key + 100);
4454             }
4455           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4456         }
4457       if (emitTlbl)
4458         {
4459           emitcode ("", "%05d$:", tlbl->key + 100);
4460         }
4461       return TRUE;
4462     }
4463
4464   /* if the sizes are greater than 1 then we cannot */
4465   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4466       AOP_SIZE (IC_LEFT (ic)) > 1)
4467     return FALSE;
4468
4469   /* we can if the aops of the left & result match or
4470      if they are in registers and the registers are the
4471      same */
4472   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4473     {
4474       char *l;
4475
4476       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4477         {
4478           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4479           l = "a";
4480         }
4481       else
4482         {
4483           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4484         }
4485
4486       while (icount--)
4487         emitcode ("dec", "%s", l);
4488
4489       if (AOP_NEEDSACC (IC_RESULT (ic)))
4490         aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4491
4492       return TRUE;
4493     }
4494
4495   return FALSE;
4496 }
4497
4498 /*-----------------------------------------------------------------*/
4499 /* addSign - complete with sign                                    */
4500 /*-----------------------------------------------------------------*/
4501 static void
4502 addSign (operand * result, int offset, int sign)
4503 {
4504   int size = (getDataSize (result) - offset);
4505   if (size > 0)
4506     {
4507       if (sign)
4508         {
4509           emitcode ("rlc", "a");
4510           emitcode ("subb", "a,acc");
4511           while (size--)
4512             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4513         }
4514       else
4515         while (size--)
4516           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4517     }
4518 }
4519
4520 /*-----------------------------------------------------------------*/
4521 /* genMinusBits - generates code for subtraction  of two bits      */
4522 /*-----------------------------------------------------------------*/
4523 static void
4524 genMinusBits (iCode * ic)
4525 {
4526   symbol *lbl = newiTempLabel (NULL);
4527
4528   D(emitcode (";     genMinusBits",""));
4529
4530   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4531     {
4532       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4533       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4534       emitcode ("cpl", "c");
4535       emitcode ("", "%05d$:", (lbl->key + 100));
4536       outBitC (IC_RESULT (ic));
4537     }
4538   else
4539     {
4540       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4541       emitcode ("subb", "a,acc");
4542       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4543       emitcode ("inc", "a");
4544       emitcode ("", "%05d$:", (lbl->key + 100));
4545       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4546       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4547     }
4548 }
4549
4550 /*-----------------------------------------------------------------*/
4551 /* genMinus - generates code for subtraction                       */
4552 /*-----------------------------------------------------------------*/
4553 static void
4554 genMinus (iCode * ic)
4555 {
4556   int size, offset = 0;
4557
4558   D(emitcode (";     genMinus",""));
4559
4560   aopOp (IC_LEFT (ic), ic, FALSE);
4561   aopOp (IC_RIGHT (ic), ic, FALSE);
4562   aopOp (IC_RESULT (ic), ic, TRUE);
4563
4564   /* special cases :- */
4565   /* if both left & right are in bit space */
4566   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4567       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4568     {
4569       genMinusBits (ic);
4570       goto release;
4571     }
4572
4573   /* if I can do an decrement instead
4574      of subtract then GOOD for ME */
4575   if (genMinusDec (ic) == TRUE)
4576     goto release;
4577
4578   size = getDataSize (IC_RESULT (ic));
4579
4580   /* if literal, add a,#-lit, else normal subb */
4581   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4582     {
4583       unsigned long lit = 0L;
4584       bool useCarry = FALSE;
4585
4586       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4587       lit = -(long) lit;
4588
4589       while (size--)
4590         {
4591           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4592             {
4593             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4594               if (!offset && !size && lit== (unsigned long) -1)
4595                 {
4596                   emitcode ("dec", "a");
4597                 }
4598               else if (!useCarry)
4599                 {
4600                   /* first add without previous c */
4601                   emitcode ("add", "a,#0x%02x",
4602                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4603                   useCarry = TRUE;
4604                 }
4605               else
4606                 {
4607                   emitcode ("addc", "a,#0x%02x",
4608                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4609                 }
4610               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4611             }
4612           else
4613             {
4614               /* no need to add zeroes */
4615               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4616                 {
4617                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4618                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4619                 }
4620               offset++;
4621             }
4622         }
4623     }
4624   else
4625     {
4626       operand *leftOp, *rightOp;
4627
4628       leftOp = IC_LEFT(ic);
4629       rightOp = IC_RIGHT(ic);
4630
4631       while (size--)
4632         {
4633           if (aopGetUsesAcc(rightOp, offset)) {
4634             if (aopGetUsesAcc(leftOp, offset)) {
4635               bool pushedB;
4636
4637               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4638               pushedB = pushB ();
4639               emitcode ("mov", "b,a");
4640               if (offset == 0)
4641                 CLRC;
4642               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4643               emitcode ("subb", "a,b");
4644               popB (pushedB);
4645             } else {
4646               /* reverse subtraction with 2's complement */
4647               if (offset == 0)
4648                 emitcode( "setb", "c");
4649                else
4650                 emitcode( "cpl", "c");
4651               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4652               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4653               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4654               emitcode("cpl", "a");
4655               if (size) /* skip if last byte */
4656                 emitcode( "cpl", "c");
4657             }
4658           } else {
4659             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4660             if (offset == 0)
4661               CLRC;
4662             emitcode ("subb", "a,%s",
4663                       aopGet(rightOp, offset, FALSE, TRUE));
4664           }
4665
4666           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4667         }
4668     }
4669
4670
4671   adjustArithmeticResult (ic);
4672
4673 release:
4674   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4675   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4676   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4677 }
4678
4679
4680 /*-----------------------------------------------------------------*/
4681 /* genMultbits :- multiplication of bits                           */
4682 /*-----------------------------------------------------------------*/
4683 static void
4684 genMultbits (operand * left,
4685              operand * right,
4686              operand * result)
4687 {
4688   D(emitcode (";     genMultbits",""));
4689
4690   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4691   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4692   outBitC (result);
4693 }
4694
4695 /*-----------------------------------------------------------------*/
4696 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4697 /*-----------------------------------------------------------------*/
4698 static void
4699 genMultOneByte (operand * left,
4700                 operand * right,
4701                 operand * result)
4702 {
4703   symbol *lbl;
4704   int size = AOP_SIZE (result);
4705   bool runtimeSign, compiletimeSign;
4706   bool lUnsigned, rUnsigned, pushedB;
4707
4708   D(emitcode (";     genMultOneByte",""));
4709
4710   if (size < 1 || size > 2)
4711     {
4712       /* this should never happen */
4713       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4714                AOP_SIZE(result), __FILE__, lineno);
4715       exit (1);
4716     }
4717
4718   /* (if two literals: the value is computed before) */
4719   /* if one literal, literal on the right */
4720   if (AOP_TYPE (left) == AOP_LIT)
4721     {
4722       operand *t = right;
4723       right = left;
4724       left = t;
4725       /* emitcode (";", "swapped left and right"); */
4726     }
4727   /* if no literal, unsigned on the right: shorter code */
4728   if (   AOP_TYPE (right) != AOP_LIT
4729       && SPEC_USIGN (getSpec (operandType (left))))
4730     {
4731       operand *t = right;
4732       right = left;
4733       left = t;
4734     }
4735
4736   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4737   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4738
4739   pushedB = pushB ();
4740
4741   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4742                    no need to take care about the signedness! */
4743       || (lUnsigned && rUnsigned))
4744     {
4745       /* just an unsigned 8 * 8 = 8 multiply
4746          or 8u * 8u = 16u */
4747       /* emitcode (";","unsigned"); */
4748       /* TODO: check for accumulator clash between left & right aops? */
4749
4750       if (AOP_TYPE (right) == AOP_LIT)
4751         {
4752           /* moving to accumulator first helps peepholes */
4753           MOVA (aopGet (left, 0, FALSE, FALSE));
4754           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4755         }
4756       else
4757         {
4758           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4759           MOVA (aopGet (left, 0, FALSE, FALSE));
4760         }
4761
4762       emitcode ("mul", "ab");
4763       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4764       if (size == 2)
4765         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4766
4767       popB (pushedB);
4768       return;
4769     }
4770
4771   /* we have to do a signed multiply */
4772   /* emitcode (";", "signed"); */
4773
4774   /* now sign adjust for both left & right */
4775
4776   /* let's see what's needed: */
4777   /* apply negative sign during runtime */
4778   runtimeSign = FALSE;
4779   /* negative sign from literals */
4780   compiletimeSign = FALSE;
4781
4782   if (!lUnsigned)
4783     {
4784       if (AOP_TYPE(left) == AOP_LIT)
4785         {
4786           /* signed literal */
4787           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4788           if (val < 0)
4789             compiletimeSign = TRUE;
4790         }
4791       else
4792         /* signed but not literal */
4793         runtimeSign = TRUE;
4794     }
4795
4796   if (!rUnsigned)
4797     {
4798       if (AOP_TYPE(right) == AOP_LIT)
4799         {
4800           /* signed literal */
4801           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4802           if (val < 0)
4803             compiletimeSign ^= TRUE;
4804         }
4805       else
4806         /* signed but not literal */
4807         runtimeSign = TRUE;
4808     }
4809
4810   /* initialize F0, which stores the runtime sign */
4811   if (runtimeSign)
4812     {
4813       if (compiletimeSign)
4814         emitcode ("setb", "F0"); /* set sign flag */
4815       else
4816         emitcode ("clr", "F0"); /* reset sign flag */
4817     }
4818
4819   /* save the signs of the operands */
4820   if (AOP_TYPE(right) == AOP_LIT)
4821     {
4822       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4823
4824       if (!rUnsigned && val < 0)
4825         emitcode ("mov", "b,#0x%02x", -val);
4826       else
4827         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4828     }
4829   else /* ! literal */
4830     {
4831       if (rUnsigned)  /* emitcode (";", "signed"); */
4832
4833         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4834       else
4835         {
4836           MOVA (aopGet (right, 0, FALSE, FALSE));
4837           lbl = newiTempLabel (NULL);
4838           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4839           emitcode ("cpl", "F0"); /* complement sign flag */
4840           emitcode ("cpl", "a");  /* 2's complement */
4841           emitcode ("inc", "a");
4842           emitcode ("", "%05d$:", (lbl->key + 100));
4843           emitcode ("mov", "b,a");
4844         }
4845     }
4846
4847   if (AOP_TYPE(left) == AOP_LIT)
4848     {
4849       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4850
4851       if (!lUnsigned && val < 0)
4852         emitcode ("mov", "a,#0x%02x", -val);
4853       else
4854         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4855     }
4856   else /* ! literal */
4857     {
4858       MOVA (aopGet (left, 0, FALSE, FALSE));
4859
4860       if (!lUnsigned)
4861         {
4862           lbl = newiTempLabel (NULL);
4863           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4864           emitcode ("cpl", "F0"); /* complement sign flag */
4865           emitcode ("cpl", "a"); /* 2's complement */
4866           emitcode ("inc", "a");
4867           emitcode ("", "%05d$:", (lbl->key + 100));
4868         }
4869     }
4870
4871   /* now the multiplication */
4872   emitcode ("mul", "ab");
4873   if (runtimeSign || compiletimeSign)
4874     {
4875       lbl = newiTempLabel (NULL);
4876       if (runtimeSign)
4877         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4878       emitcode ("cpl", "a"); /* lsb 2's complement */
4879       if (size != 2)
4880         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4881       else
4882         {
4883           emitcode ("add", "a,#1"); /* this sets carry flag */
4884           emitcode ("xch", "a,b");
4885           emitcode ("cpl", "a"); /* msb 2's complement */
4886           emitcode ("addc", "a,#0");
4887           emitcode ("xch", "a,b");
4888         }
4889       emitcode ("", "%05d$:", (lbl->key + 100));
4890     }
4891   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4892   if (size == 2)
4893     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4894
4895   popB (pushedB);
4896 }
4897
4898 /*-----------------------------------------------------------------*/
4899 /* genMult - generates code for multiplication                     */
4900 /*-----------------------------------------------------------------*/
4901 static void
4902 genMult (iCode * ic)
4903 {
4904   operand *left = IC_LEFT (ic);
4905   operand *right = IC_RIGHT (ic);
4906   operand *result = IC_RESULT (ic);
4907
4908   D(emitcode (";     genMult",""));
4909
4910   /* assign the asmops */
4911   aopOp (left, ic, FALSE);
4912   aopOp (right, ic, FALSE);
4913   aopOp (result, ic, TRUE);
4914
4915   /* special cases first */
4916   /* both are bits */
4917   if (AOP_TYPE (left) == AOP_CRY &&
4918       AOP_TYPE (right) == AOP_CRY)
4919     {
4920       genMultbits (left, right, result);
4921       goto release;
4922     }
4923
4924   /* if both are of size == 1 */
4925 #if 0 // one of them can be a sloc shared with the result
4926     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4927 #else
4928   if (getSize(operandType(left)) == 1 &&
4929       getSize(operandType(right)) == 1)
4930 #endif
4931     {
4932       genMultOneByte (left, right, result);
4933       goto release;
4934     }
4935
4936   /* should have been converted to function call */
4937     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4938              getSize(OP_SYMBOL(right)->type));
4939   assert (0);
4940
4941 release:
4942   freeAsmop (result, NULL, ic, TRUE);
4943   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4944   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4945 }
4946
4947 /*-----------------------------------------------------------------*/
4948 /* genDivbits :- division of bits                                  */
4949 /*-----------------------------------------------------------------*/
4950 static void
4951 genDivbits (operand * left,
4952             operand * right,
4953             operand * result)
4954 {
4955   char *l;
4956   bool pushedB;
4957
4958   D(emitcode (";     genDivbits",""));
4959
4960   pushedB = pushB ();
4961
4962   /* the result must be bit */
4963   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4964   l = aopGet (left, 0, FALSE, FALSE);
4965
4966   MOVA (l);
4967
4968   emitcode ("div", "ab");
4969   emitcode ("rrc", "a");
4970
4971   popB (pushedB);
4972
4973   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4974 }
4975
4976 /*-----------------------------------------------------------------*/
4977 /* genDivOneByte : 8 bit division                                  */
4978 /*-----------------------------------------------------------------*/
4979 static void
4980 genDivOneByte (operand * left,
4981                operand * right,
4982                operand * result)
4983 {
4984   bool lUnsigned, rUnsigned, pushedB;
4985   bool runtimeSign, compiletimeSign;
4986   bool accuse = FALSE;
4987   bool pushedA = FALSE;
4988   symbol *lbl;
4989   int size, offset;
4990
4991   D(emitcode (";     genDivOneByte",""));
4992
4993   /* Why is it necessary that genDivOneByte() can return an int result?
4994      Have a look at:
4995
4996         volatile unsigned char uc;
4997         volatile signed char sc1, sc2;
4998         volatile int i;
4999
5000         uc  = 255;
5001         sc1 = -1;
5002         i = uc / sc1;
5003
5004      Or:
5005
5006         sc1 = -128;
5007         sc2 = -1;
5008         i = sc1 / sc2;
5009
5010      In all cases a one byte result would overflow, the following cast to int
5011      would return the wrong result.
5012
5013      Two possible solution:
5014         a) cast operands to int, if ((unsigned) / (signed)) or
5015            ((signed) / (signed))
5016         b) return an 16 bit signed int; this is what we're doing here!
5017   */
5018
5019   size = AOP_SIZE (result) - 1;
5020   offset = 1;
5021   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5022   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5023
5024   pushedB = pushB ();
5025
5026   /* signed or unsigned */
5027   if (lUnsigned && rUnsigned)
5028     {
5029       /* unsigned is easy */
5030       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5031       MOVA (aopGet (left, 0, FALSE, FALSE));
5032       emitcode ("div", "ab");
5033       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5034       while (size--)
5035         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5036
5037       popB (pushedB);
5038       return;
5039     }
5040
5041   /* signed is a little bit more difficult */
5042
5043   /* now sign adjust for both left & right */
5044
5045   /* let's see what's needed: */
5046   /* apply negative sign during runtime */
5047   runtimeSign = FALSE;
5048   /* negative sign from literals */
5049   compiletimeSign = FALSE;
5050
5051   if (!lUnsigned)
5052     {
5053       if (AOP_TYPE(left) == AOP_LIT)
5054         {
5055           /* signed literal */
5056           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5057           if (val < 0)
5058             compiletimeSign = TRUE;
5059         }
5060       else
5061         /* signed but not literal */
5062         runtimeSign = TRUE;
5063     }
5064
5065   if (!rUnsigned)
5066     {
5067       if (AOP_TYPE(right) == AOP_LIT)
5068         {
5069           /* signed literal */
5070           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5071           if (val < 0)
5072             compiletimeSign ^= TRUE;
5073         }
5074       else
5075         /* signed but not literal */
5076         runtimeSign = TRUE;
5077     }
5078
5079   /* initialize F0, which stores the runtime sign */
5080   if (runtimeSign)
5081     {
5082       if (compiletimeSign)
5083         emitcode ("setb", "F0"); /* set sign flag */
5084       else
5085         emitcode ("clr", "F0"); /* reset sign flag */
5086     }
5087
5088   /* save the signs of the operands */
5089   if (AOP_TYPE(right) == AOP_LIT)
5090     {
5091       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5092
5093       if (!rUnsigned && val < 0)
5094         emitcode ("mov", "b,#0x%02x", -val);
5095       else
5096         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5097     }
5098   else /* ! literal */
5099     {
5100       if (rUnsigned)
5101         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5102       else
5103         {
5104           MOVA (aopGet (right, 0, FALSE, FALSE));
5105           lbl = newiTempLabel (NULL);
5106           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5107           emitcode ("cpl", "F0"); /* complement sign flag */
5108           emitcode ("cpl", "a");  /* 2's complement */
5109           emitcode ("inc", "a");
5110           emitcode ("", "%05d$:", (lbl->key + 100));
5111           emitcode ("mov", "b,a");
5112         }
5113     }
5114
5115   if (AOP_TYPE(left) == AOP_LIT)
5116     {
5117       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5118
5119       if (!lUnsigned && val < 0)
5120         emitcode ("mov", "a,#0x%02x", -val);
5121       else
5122         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5123     }
5124   else /* ! literal */
5125     {
5126       MOVA (aopGet (left, 0, FALSE, FALSE));
5127
5128       if (!lUnsigned)
5129         {
5130           lbl = newiTempLabel (NULL);
5131           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5132           emitcode ("cpl", "F0"); /* complement sign flag */
5133           emitcode ("cpl", "a");  /* 2's complement */
5134           emitcode ("inc", "a");
5135           emitcode ("", "%05d$:", (lbl->key + 100));
5136         }
5137     }
5138
5139   /* now the division */
5140   emitcode ("div", "ab");
5141
5142   if (runtimeSign || compiletimeSign)
5143     {
5144       lbl = newiTempLabel (NULL);
5145       if (runtimeSign)
5146         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5147       emitcode ("cpl", "a"); /* lsb 2's complement */
5148       emitcode ("inc", "a");
5149       emitcode ("", "%05d$:", (lbl->key + 100));
5150
5151       accuse = aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5152       if (size > 0)
5153         {
5154           /* msb is 0x00 or 0xff depending on the sign */
5155           if (runtimeSign)
5156             {
5157               if (accuse)
5158                 {
5159                   emitcode ("push", "acc");
5160                   pushedA = TRUE;
5161                 }
5162               emitcode ("mov", "c,F0");
5163               emitcode ("subb", "a,acc");
5164               while (size--)
5165                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5166             }
5167           else /* compiletimeSign */
5168             {
5169               if (aopPutUsesAcc (result, "#0xFF", offset))
5170                 {
5171                   emitcode ("push", "acc");
5172                   pushedA = TRUE;
5173                 }
5174               while (size--)
5175                 aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5176             }
5177         }
5178     }
5179   else
5180     {
5181       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5182       while (size--)
5183         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5184     }
5185
5186   if (pushedA)
5187     emitcode ("pop", "acc");
5188   popB (pushedB);
5189 }
5190
5191 /*-----------------------------------------------------------------*/
5192 /* genDiv - generates code for division                            */
5193 /*-----------------------------------------------------------------*/
5194 static void
5195 genDiv (iCode * ic)
5196 {
5197   operand *left = IC_LEFT (ic);
5198   operand *right = IC_RIGHT (ic);
5199   operand *result = IC_RESULT (ic);
5200
5201   D(emitcode (";     genDiv",""));
5202
5203   /* assign the amsops */
5204   aopOp (left, ic, FALSE);
5205   aopOp (right, ic, FALSE);
5206   aopOp (result, ic, TRUE);
5207
5208   /* special cases first */
5209   /* both are bits */
5210   if (AOP_TYPE (left) == AOP_CRY &&
5211       AOP_TYPE (right) == AOP_CRY)
5212     {
5213       genDivbits (left, right, result);
5214       goto release;
5215     }
5216
5217   /* if both are of size == 1 */
5218   if (AOP_SIZE (left) == 1 &&
5219       AOP_SIZE (right) == 1)
5220     {
5221       genDivOneByte (left, right, result);
5222       goto release;
5223     }
5224
5225   /* should have been converted to function call */
5226   assert (0);
5227 release:
5228   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5229   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5230   freeAsmop (result, NULL, ic, TRUE);
5231 }
5232
5233 /*-----------------------------------------------------------------*/
5234 /* genModbits :- modulus of bits                                   */
5235 /*-----------------------------------------------------------------*/
5236 static void
5237 genModbits (operand * left,
5238             operand * right,
5239             operand * result)
5240 {
5241   char *l;
5242   bool pushedB;
5243
5244   D(emitcode (";     genModbits",""));
5245
5246   pushedB = pushB ();
5247
5248   /* the result must be bit */
5249   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5250   l = aopGet (left, 0, FALSE, FALSE);
5251
5252   MOVA (l);
5253
5254   emitcode ("div", "ab");
5255   emitcode ("mov", "a,b");
5256   emitcode ("rrc", "a");
5257
5258   popB (pushedB);
5259
5260   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5261 }
5262
5263 /*-----------------------------------------------------------------*/
5264 /* genModOneByte : 8 bit modulus                                   */
5265 /*-----------------------------------------------------------------*/
5266 static void
5267 genModOneByte (operand * left,
5268                operand * right,
5269                operand * result)
5270 {
5271   bool lUnsigned, rUnsigned, pushedB;
5272   bool runtimeSign, compiletimeSign;
5273   symbol *lbl;
5274   int size, offset;
5275
5276   D(emitcode (";     genModOneByte",""));
5277
5278   size = AOP_SIZE (result) - 1;
5279   offset = 1;
5280   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5281   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5282
5283   /* if right is a literal, check it for 2^n */
5284   if (AOP_TYPE(right) == AOP_LIT)
5285     {
5286       unsigned char val = abs((int) operandLitValue(right));
5287       symbol *lbl2 = NULL;
5288
5289       switch (val)
5290         {
5291           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5292           case 2:
5293           case 4:
5294           case 8:
5295           case 16:
5296           case 32:
5297           case 64:
5298           case 128:
5299             if (lUnsigned)
5300               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5301                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5302               /* because iCode should have been changed to genAnd  */
5303               /* see file "SDCCopt.c", function "convertToFcall()" */
5304
5305             MOVA (aopGet (left, 0, FALSE, FALSE));
5306             emitcode ("mov", "c,acc.7");
5307             emitcode ("anl", "a,#0x%02x", val - 1);
5308             lbl = newiTempLabel (NULL);
5309             emitcode ("jz", "%05d$", (lbl->key + 100));
5310             emitcode ("jnc", "%05d$", (lbl->key + 100));
5311             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5312             if (size)
5313               {
5314                 int size2 = size;
5315                 int offs2 = offset;
5316
5317                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5318                 while (size2--)
5319                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5320                 lbl2 = newiTempLabel (NULL);
5321                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5322               }
5323             emitcode ("", "%05d$:", (lbl->key + 100));
5324             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5325             while (size--)
5326               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5327             if (lbl2)
5328               {
5329                 emitcode ("", "%05d$:", (lbl2->key + 100));
5330               }
5331             return;
5332
5333           default:
5334             break;
5335         }
5336     }
5337
5338   pushedB = pushB ();
5339
5340   /* signed or unsigned */
5341   if (lUnsigned && rUnsigned)
5342     {
5343       /* unsigned is easy */
5344       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5345       MOVA (aopGet (left, 0, FALSE, FALSE));
5346       emitcode ("div", "ab");
5347       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5348       while (size--)
5349         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5350
5351       popB (pushedB);
5352       return;
5353     }
5354
5355   /* signed is a little bit more difficult */
5356
5357   /* now sign adjust for both left & right */
5358
5359   /* modulus: sign of the right operand has no influence on the result! */
5360   if (AOP_TYPE(right) == AOP_LIT)
5361     {
5362       signed char val = (char) operandLitValue(right);
5363
5364       if (!rUnsigned && val < 0)
5365         emitcode ("mov", "b,#0x%02x", -val);
5366       else
5367         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5368     }
5369   else /* not literal */
5370     {
5371       if (rUnsigned)
5372         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5373       else
5374         {
5375           MOVA (aopGet (right, 0, FALSE, FALSE));
5376           lbl = newiTempLabel (NULL);
5377           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5378           emitcode ("cpl", "a"); /* 2's complement */
5379           emitcode ("inc", "a");
5380           emitcode ("", "%05d$:", (lbl->key + 100));
5381           emitcode ("mov", "b,a");
5382         }
5383     }
5384
5385   /* let's see what's needed: */
5386   /* apply negative sign during runtime */
5387   runtimeSign = FALSE;
5388   /* negative sign from literals */
5389   compiletimeSign = FALSE;
5390
5391   /* sign adjust left side */
5392   if (AOP_TYPE(left) == AOP_LIT)
5393     {
5394       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5395
5396       if (!lUnsigned && val < 0)
5397         {
5398           compiletimeSign = TRUE; /* set sign flag */
5399           emitcode ("mov", "a,#0x%02x", -val);
5400         }
5401       else
5402         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5403     }
5404   else /* ! literal */
5405     {
5406       MOVA (aopGet (left, 0, FALSE, FALSE));
5407
5408       if (!lUnsigned)
5409         {
5410           runtimeSign = TRUE;
5411           emitcode ("clr", "F0"); /* clear sign flag */
5412
5413           lbl = newiTempLabel (NULL);
5414           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5415           emitcode ("setb", "F0"); /* set sign flag */
5416           emitcode ("cpl", "a");   /* 2's complement */
5417           emitcode ("inc", "a");
5418           emitcode ("", "%05d$:", (lbl->key + 100));
5419         }
5420     }
5421
5422   /* now the modulus */
5423   emitcode ("div", "ab");
5424
5425   if (runtimeSign || compiletimeSign)
5426     {
5427       emitcode ("mov", "a,b");
5428       lbl = newiTempLabel (NULL);
5429       if (runtimeSign)
5430         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5431       emitcode ("cpl", "a"); /* 2's complement */
5432       emitcode ("inc", "a");
5433       emitcode ("", "%05d$:", (lbl->key + 100));
5434
5435       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5436       if (size > 0)
5437         {
5438           /* msb is 0x00 or 0xff depending on the sign */
5439           if (runtimeSign)
5440             {
5441               emitcode ("mov", "c,F0");
5442               emitcode ("subb", "a,acc");
5443               while (size--)
5444                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5445             }
5446           else /* compiletimeSign */
5447             while (size--)
5448               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5449         }
5450     }
5451   else
5452     {
5453       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5454       while (size--)
5455         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5456     }
5457
5458   popB (pushedB);
5459 }
5460
5461 /*-----------------------------------------------------------------*/
5462 /* genMod - generates code for division                            */
5463 /*-----------------------------------------------------------------*/
5464 static void
5465 genMod (iCode * ic)
5466 {
5467   operand *left = IC_LEFT (ic);
5468   operand *right = IC_RIGHT (ic);
5469   operand *result = IC_RESULT (ic);
5470
5471   D(emitcode (";     genMod",""));
5472
5473   /* assign the asmops */
5474   aopOp (left, ic, FALSE);
5475   aopOp (right, ic, FALSE);
5476   aopOp (result, ic, TRUE);
5477
5478   /* special cases first */
5479   /* both are bits */
5480   if (AOP_TYPE (left) == AOP_CRY &&
5481       AOP_TYPE (right) == AOP_CRY)
5482     {
5483       genModbits (left, right, result);
5484       goto release;
5485     }
5486
5487   /* if both are of size == 1 */
5488   if (AOP_SIZE (left) == 1 &&
5489       AOP_SIZE (right) == 1)
5490     {
5491       genModOneByte (left, right, result);
5492       goto release;
5493     }
5494
5495   /* should have been converted to function call */
5496   assert (0);
5497
5498 release:
5499   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5500   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5501   freeAsmop (result, NULL, ic, TRUE);
5502 }
5503
5504 /*-----------------------------------------------------------------*/
5505 /* genIfxJump :- will create a jump depending on the ifx           */
5506 /*-----------------------------------------------------------------*/
5507 static void
5508 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5509 {
5510   symbol *jlbl;
5511   symbol *tlbl = newiTempLabel (NULL);
5512   char *inst;
5513
5514   D(emitcode (";     genIfxJump",""));
5515
5516   /* if true label then we jump if condition
5517      supplied is true */
5518   if (IC_TRUE (ic))
5519     {
5520       jlbl = IC_TRUE (ic);
5521       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5522                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5523     }
5524   else
5525     {
5526       /* false label is present */
5527       jlbl = IC_FALSE (ic);
5528       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5529                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5530     }
5531   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5532     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5533   else
5534     emitcode (inst, "%05d$", tlbl->key + 100);
5535   freeForBranchAsmop (result);
5536   freeForBranchAsmop (right);
5537   freeForBranchAsmop (left);
5538   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5539   emitcode ("", "%05d$:", tlbl->key + 100);
5540
5541   /* mark the icode as generated */
5542   ic->generated = 1;
5543 }
5544
5545 /*-----------------------------------------------------------------*/
5546 /* genCmp :- greater or less than comparison                       */
5547 /*-----------------------------------------------------------------*/
5548 static void
5549 genCmp (operand * left, operand * right,
5550         operand * result, iCode * ifx, int sign, iCode *ic)
5551 {
5552   int size, offset = 0;
5553   unsigned long lit = 0L;
5554   bool rightInB;
5555
5556   D(emitcode (";     genCmp",""));
5557
5558   /* if left & right are bit variables */
5559   if (AOP_TYPE (left) == AOP_CRY &&
5560       AOP_TYPE (right) == AOP_CRY)
5561     {
5562       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5563       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5564     }
5565   else
5566     {
5567       /* subtract right from left if at the
5568          end the carry flag is set then we know that
5569          left is greater than right */
5570       size = max (AOP_SIZE (left), AOP_SIZE (right));
5571
5572       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5573       if ((size == 1) && !sign &&
5574           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5575         {
5576           symbol *lbl = newiTempLabel (NULL);
5577           emitcode ("cjne", "%s,%s,%05d$",
5578                     aopGet (left, offset, FALSE, FALSE),
5579                     aopGet (right, offset, FALSE, FALSE),
5580                     lbl->key + 100);
5581           emitcode ("", "%05d$:", lbl->key + 100);
5582         }
5583       else
5584         {
5585           if (AOP_TYPE (right) == AOP_LIT)
5586             {
5587               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5588               /* optimize if(x < 0) or if(x >= 0) */
5589               if (lit == 0L)
5590                 {
5591                   if (!sign)
5592                     {
5593                       CLRC;
5594                     }
5595                   else
5596                     {
5597                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5598                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5599                         {
5600                           genIfxJump (ifx, "acc.7", left, right, result);
5601                           freeAsmop (right, NULL, ic, TRUE);
5602                           freeAsmop (left, NULL, ic, TRUE);
5603
5604                           return;
5605                         }
5606                       else
5607                         emitcode ("rlc", "a");
5608                     }
5609                   goto release;
5610                 }
5611             }
5612           CLRC;
5613           while (size--)
5614             {
5615               bool pushedB = FALSE;
5616               rightInB = aopGetUsesAcc(right, offset);
5617               if (rightInB)
5618                 {
5619                   pushedB = pushB ();
5620                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5621                 }
5622               MOVA (aopGet (left, offset, FALSE, FALSE));
5623               if (sign && size == 0)
5624                 {
5625                   emitcode ("xrl", "a,#0x80");
5626                   if (AOP_TYPE (right) == AOP_LIT)
5627                     {
5628                       unsigned long lit = (unsigned long)
5629                       floatFromVal (AOP (right)->aopu.aop_lit);
5630                       emitcode ("subb", "a,#0x%02x",
5631                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5632                     }
5633                   else
5634                     {
5635                       if (!rightInB)
5636                         {
5637                           pushedB = pushB ();
5638                           rightInB++;
5639                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5640                         }
5641                       emitcode ("xrl", "b,#0x80");
5642                       emitcode ("subb", "a,b");
5643                     }
5644                 }
5645               else
5646                 {
5647                   if (rightInB)
5648                     emitcode ("subb", "a,b");
5649                   else
5650                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5651                 }
5652               if (rightInB)
5653                 popB (pushedB);
5654               offset++;
5655             }
5656         }
5657     }
5658
5659 release:
5660   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5661   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5662   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5663     {
5664       outBitC (result);
5665     }
5666   else
5667     {
5668       /* if the result is used in the next
5669          ifx conditional branch then generate
5670          code a little differently */
5671       if (ifx)
5672         genIfxJump (ifx, "c", NULL, NULL, result);
5673       else
5674         outBitC (result);
5675       /* leave the result in acc */
5676     }
5677 }
5678
5679 /*-----------------------------------------------------------------*/
5680 /* genCmpGt :- greater than comparison                             */
5681 /*-----------------------------------------------------------------*/
5682 static void
5683 genCmpGt (iCode * ic, iCode * ifx)
5684 {
5685   operand *left, *right, *result;
5686   sym_link *letype, *retype;
5687   int sign;
5688
5689   D(emitcode (";     genCmpGt",""));
5690
5691   left = IC_LEFT (ic);
5692   right = IC_RIGHT (ic);
5693   result = IC_RESULT (ic);
5694
5695   letype = getSpec (operandType (left));
5696   retype = getSpec (operandType (right));
5697   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5698            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5699   /* assign the amsops */
5700   aopOp (left, ic, FALSE);
5701   aopOp (right, ic, FALSE);
5702   aopOp (result, ic, TRUE);
5703
5704   genCmp (right, left, result, ifx, sign, ic);
5705
5706   freeAsmop (result, NULL, ic, TRUE);
5707 }
5708
5709 /*-----------------------------------------------------------------*/
5710 /* genCmpLt - less than comparisons                                */
5711 /*-----------------------------------------------------------------*/
5712 static void
5713 genCmpLt (iCode * ic, iCode * ifx)
5714 {
5715   operand *left, *right, *result;
5716   sym_link *letype, *retype;
5717   int sign;
5718
5719   D(emitcode (";     genCmpLt",""));
5720
5721   left = IC_LEFT (ic);
5722   right = IC_RIGHT (ic);
5723   result = IC_RESULT (ic);
5724
5725   letype = getSpec (operandType (left));
5726   retype = getSpec (operandType (right));
5727   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5728            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5729   /* assign the amsops */
5730   aopOp (left, ic, FALSE);
5731   aopOp (right, ic, FALSE);
5732   aopOp (result, ic, TRUE);
5733
5734   genCmp (left, right, result, ifx, sign, ic);
5735
5736   freeAsmop (result, NULL, ic, TRUE);
5737 }
5738
5739 /*-----------------------------------------------------------------*/
5740 /* gencjneshort - compare and jump if not equal                    */
5741 /*-----------------------------------------------------------------*/
5742 static void
5743 gencjneshort (operand * left, operand * right, symbol * lbl)
5744 {
5745   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5746   int offset = 0;
5747   unsigned long lit = 0L;
5748
5749   /* if the left side is a literal or
5750      if the right is in a pointer register and left
5751      is not */
5752   if ((AOP_TYPE (left) == AOP_LIT) ||
5753       (AOP_TYPE (left) == AOP_IMMD) ||
5754       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5755     {
5756       operand *t = right;
5757       right = left;
5758       left = t;
5759     }
5760
5761   if (AOP_TYPE (right) == AOP_LIT)
5762     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5763
5764   /* if the right side is a literal then anything goes */
5765   if (AOP_TYPE (right) == AOP_LIT &&
5766       AOP_TYPE (left) != AOP_DIR  &&
5767       AOP_TYPE (left) != AOP_IMMD)
5768     {
5769       while (size--)
5770         {
5771           emitcode ("cjne", "%s,%s,%05d$",
5772                     aopGet (left, offset, FALSE, FALSE),
5773                     aopGet (right, offset, FALSE, FALSE),
5774                     lbl->key + 100);
5775           offset++;
5776         }
5777     }
5778
5779   /* if the right side is in a register or in direct space or
5780      if the left is a pointer register & right is not */
5781   else if (AOP_TYPE (right) == AOP_REG ||
5782            AOP_TYPE (right) == AOP_DIR ||
5783            AOP_TYPE (right) == AOP_LIT ||
5784            AOP_TYPE (right) == AOP_IMMD ||
5785            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5786            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5787     {
5788       while (size--)
5789         {
5790           MOVA (aopGet (left, offset, FALSE, FALSE));
5791           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5792               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5793             emitcode ("jnz", "%05d$", lbl->key + 100);
5794           else
5795             emitcode ("cjne", "a,%s,%05d$",
5796                       aopGet (right, offset, FALSE, TRUE),
5797                       lbl->key + 100);
5798           offset++;
5799         }
5800     }
5801   else
5802     {
5803       /* right is a pointer reg need both a & b */
5804       while (size--)
5805         {
5806           char *l;
5807           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5808           wassertl(!BINUSE, "B was in use");
5809           l = aopGet (left, offset, FALSE, FALSE);
5810           if (strcmp (l, "b"))
5811             emitcode ("mov", "b,%s", l);
5812           MOVA (aopGet (right, offset, FALSE, FALSE));
5813           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5814           offset++;
5815         }
5816     }
5817 }
5818
5819 /*-----------------------------------------------------------------*/
5820 /* gencjne - compare and jump if not equal                         */
5821 /*-----------------------------------------------------------------*/
5822 static void
5823 gencjne (operand * left, operand * right, symbol * lbl)
5824 {
5825   symbol *tlbl = newiTempLabel (NULL);
5826
5827   gencjneshort (left, right, lbl);
5828
5829   emitcode ("mov", "a,%s", one);
5830   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5831   emitcode ("", "%05d$:", lbl->key + 100);
5832   emitcode ("clr", "a");
5833   emitcode ("", "%05d$:", tlbl->key + 100);
5834 }
5835
5836 /*-----------------------------------------------------------------*/
5837 /* genCmpEq - generates code for equal to                          */
5838 /*-----------------------------------------------------------------*/
5839 static void
5840 genCmpEq (iCode * ic, iCode * ifx)
5841 {
5842   operand *left, *right, *result;
5843
5844   D(emitcode (";     genCmpEq",""));
5845
5846   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5847   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5848   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5849
5850   /* if literal, literal on the right or
5851      if the right is in a pointer register and left
5852      is not */
5853   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5854       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5855     {
5856       operand *t = IC_RIGHT (ic);
5857       IC_RIGHT (ic) = IC_LEFT (ic);
5858       IC_LEFT (ic) = t;
5859     }
5860
5861   if (ifx && !AOP_SIZE (result))
5862     {
5863       symbol *tlbl;
5864       /* if they are both bit variables */
5865       if (AOP_TYPE (left) == AOP_CRY &&
5866           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5867         {
5868           if (AOP_TYPE (right) == AOP_LIT)
5869             {
5870               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5871               if (lit == 0L)
5872                 {
5873                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5874                   emitcode ("cpl", "c");
5875                 }
5876               else if (lit == 1L)
5877                 {
5878                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5879                 }
5880               else
5881                 {
5882                   emitcode ("clr", "c");
5883                 }
5884               /* AOP_TYPE(right) == AOP_CRY */
5885             }
5886           else
5887             {
5888               symbol *lbl = newiTempLabel (NULL);
5889               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5890               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5891               emitcode ("cpl", "c");
5892               emitcode ("", "%05d$:", (lbl->key + 100));
5893             }
5894           /* if true label then we jump if condition
5895              supplied is true */
5896           tlbl = newiTempLabel (NULL);
5897           if (IC_TRUE (ifx))
5898             {
5899               emitcode ("jnc", "%05d$", tlbl->key + 100);
5900               freeForBranchAsmop (result);
5901               freeForBranchAsmop (right);
5902               freeForBranchAsmop (left);
5903               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5904             }
5905           else
5906             {
5907               emitcode ("jc", "%05d$", tlbl->key + 100);
5908               freeForBranchAsmop (result);
5909               freeForBranchAsmop (right);
5910               freeForBranchAsmop (left);
5911               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5912             }
5913           emitcode ("", "%05d$:", tlbl->key + 100);
5914         }
5915       else
5916         {
5917           tlbl = newiTempLabel (NULL);
5918           gencjneshort (left, right, tlbl);
5919           if (IC_TRUE (ifx))
5920             {
5921               freeForBranchAsmop (result);
5922               freeForBranchAsmop (right);
5923               freeForBranchAsmop (left);
5924               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5925               emitcode ("", "%05d$:", tlbl->key + 100);
5926             }
5927           else
5928             {
5929               symbol *lbl = newiTempLabel (NULL);
5930               emitcode ("sjmp", "%05d$", lbl->key + 100);
5931               emitcode ("", "%05d$:", tlbl->key + 100);
5932               freeForBranchAsmop (result);
5933               freeForBranchAsmop (right);
5934               freeForBranchAsmop (left);
5935               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5936               emitcode ("", "%05d$:", lbl->key + 100);
5937             }
5938         }
5939       /* mark the icode as generated */
5940       ifx->generated = 1;
5941       goto release;
5942     }
5943
5944   /* if they are both bit variables */
5945   if (AOP_TYPE (left) == AOP_CRY &&
5946       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5947     {
5948       if (AOP_TYPE (right) == AOP_LIT)
5949         {
5950           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5951           if (lit == 0L)
5952             {
5953               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5954               emitcode ("cpl", "c");
5955             }
5956           else if (lit == 1L)
5957             {
5958               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5959             }
5960           else
5961             {
5962               emitcode ("clr", "c");
5963             }
5964           /* AOP_TYPE(right) == AOP_CRY */
5965         }
5966       else
5967         {
5968           symbol *lbl = newiTempLabel (NULL);
5969           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5970           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5971           emitcode ("cpl", "c");
5972           emitcode ("", "%05d$:", (lbl->key + 100));
5973         }
5974       /* c = 1 if egal */
5975       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5976         {
5977           outBitC (result);
5978           goto release;
5979         }
5980       if (ifx)
5981         {
5982           genIfxJump (ifx, "c", left, right, result);
5983           goto release;
5984         }
5985       /* if the result is used in an arithmetic operation
5986          then put the result in place */
5987       outBitC (result);
5988     }
5989   else
5990     {
5991       gencjne (left, right, newiTempLabel (NULL));
5992       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5993         {
5994           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5995           goto release;
5996         }
5997       if (ifx)
5998         {
5999           genIfxJump (ifx, "a", left, right, result);
6000           goto release;
6001         }
6002       /* if the result is used in an arithmetic operation
6003          then put the result in place */
6004       if (AOP_TYPE (result) != AOP_CRY)
6005         outAcc (result);
6006       /* leave the result in acc */
6007     }
6008
6009 release:
6010   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6011   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6012   freeAsmop (result, NULL, ic, TRUE);
6013 }
6014
6015 /*-----------------------------------------------------------------*/
6016 /* ifxForOp - returns the icode containing the ifx for operand     */
6017 /*-----------------------------------------------------------------*/
6018 static iCode *
6019 ifxForOp (operand * op, iCode * ic)
6020 {
6021   /* if true symbol then needs to be assigned */
6022   if (IS_TRUE_SYMOP (op))
6023     return NULL;
6024
6025   /* if this has register type condition and
6026      the next instruction is ifx with the same operand
6027      and live to of the operand is upto the ifx only then */
6028   if (ic->next &&
6029       ic->next->op == IFX &&
6030       IC_COND (ic->next)->key == op->key &&
6031       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6032     return ic->next;
6033
6034   return NULL;
6035 }
6036
6037 /*-----------------------------------------------------------------*/
6038 /* hasInc - operand is incremented before any other use            */
6039 /*-----------------------------------------------------------------*/
6040 static iCode *
6041 hasInc (operand *op, iCode *ic,int osize)
6042 {
6043   sym_link *type = operandType(op);
6044   sym_link *retype = getSpec (type);
6045   iCode *lic = ic->next;
6046   int isize ;
6047
6048   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6049   if (!IS_SYMOP(op)) return NULL;
6050
6051   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6052   if (IS_AGGREGATE(type->next)) return NULL;
6053   if (osize != (isize = getSize(type->next))) return NULL;
6054
6055   while (lic) {
6056     /* if operand of the form op = op + <sizeof *op> */
6057     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6058         isOperandEqual(IC_RESULT(lic),op) &&
6059         isOperandLiteral(IC_RIGHT(lic)) &&
6060         operandLitValue(IC_RIGHT(lic)) == isize) {
6061       return lic;
6062     }
6063     /* if the operand used or deffed */
6064     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6065       return NULL;
6066     }
6067     /* if GOTO or IFX */
6068     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6069     lic = lic->next;
6070   }
6071   return NULL;
6072 }
6073
6074 /*-----------------------------------------------------------------*/
6075 /* genAndOp - for && operation                                     */
6076 /*-----------------------------------------------------------------*/
6077 static void
6078 genAndOp (iCode * ic)
6079 {
6080   operand *left, *right, *result;
6081   symbol *tlbl;
6082
6083   D(emitcode (";     genAndOp",""));
6084
6085   /* note here that && operations that are in an
6086      if statement are taken away by backPatchLabels
6087      only those used in arthmetic operations remain */
6088   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6089   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6090   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6091
6092   /* if both are bit variables */
6093   if (AOP_TYPE (left) == AOP_CRY &&
6094       AOP_TYPE (right) == AOP_CRY)
6095     {
6096       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6097       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6098       outBitC (result);
6099     }
6100   else
6101     {
6102       tlbl = newiTempLabel (NULL);
6103       toBoolean (left);
6104       emitcode ("jz", "%05d$", tlbl->key + 100);
6105       toBoolean (right);
6106       emitcode ("", "%05d$:", tlbl->key + 100);
6107       outBitAcc (result);
6108     }
6109
6110   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6111   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6112   freeAsmop (result, NULL, ic, TRUE);
6113 }
6114
6115
6116 /*-----------------------------------------------------------------*/
6117 /* genOrOp - for || operation                                      */
6118 /*-----------------------------------------------------------------*/
6119 static void
6120 genOrOp (iCode * ic)
6121 {
6122   operand *left, *right, *result;
6123   symbol *tlbl;
6124
6125   D(emitcode (";     genOrOp",""));
6126
6127   /* note here that || operations that are in an
6128      if statement are taken away by backPatchLabels
6129      only those used in arthmetic operations remain */
6130   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6131   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6132   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6133
6134   /* if both are bit variables */
6135   if (AOP_TYPE (left) == AOP_CRY &&
6136       AOP_TYPE (right) == AOP_CRY)
6137     {
6138       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6139       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6140       outBitC (result);
6141     }
6142   else
6143     {
6144       tlbl = newiTempLabel (NULL);
6145       toBoolean (left);
6146       emitcode ("jnz", "%05d$", tlbl->key + 100);
6147       toBoolean (right);
6148       emitcode ("", "%05d$:", tlbl->key + 100);
6149       outBitAcc (result);
6150     }
6151
6152   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6153   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6154   freeAsmop (result, NULL, ic, TRUE);
6155 }
6156
6157 /*-----------------------------------------------------------------*/
6158 /* isLiteralBit - test if lit == 2^n                               */
6159 /*-----------------------------------------------------------------*/
6160 static int
6161 isLiteralBit (unsigned long lit)
6162 {
6163   unsigned long pw[32] =
6164   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6165    0x100L, 0x200L, 0x400L, 0x800L,
6166    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6167    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6168    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6169    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6170    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6171   int idx;
6172
6173   for (idx = 0; idx < 32; idx++)
6174     if (lit == pw[idx])
6175       return idx + 1;
6176   return 0;
6177 }
6178
6179 /*-----------------------------------------------------------------*/
6180 /* continueIfTrue -                                                */
6181 /*-----------------------------------------------------------------*/
6182 static void
6183 continueIfTrue (iCode * ic)
6184 {
6185   if (IC_TRUE (ic))
6186     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6187   ic->generated = 1;
6188 }
6189
6190 /*-----------------------------------------------------------------*/
6191 /* jmpIfTrue -                                                     */
6192 /*-----------------------------------------------------------------*/
6193 static void
6194 jumpIfTrue (iCode * ic)
6195 {
6196   if (!IC_TRUE (ic))
6197     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6198   ic->generated = 1;
6199 }
6200
6201 /*-----------------------------------------------------------------*/
6202 /* jmpTrueOrFalse -                                                */
6203 /*-----------------------------------------------------------------*/
6204 static void
6205 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6206 {
6207   // ugly but optimized by peephole
6208   if (IC_TRUE (ic))
6209     {
6210       symbol *nlbl = newiTempLabel (NULL);
6211       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6212       emitcode ("", "%05d$:", tlbl->key + 100);
6213       freeForBranchAsmop (result);
6214       freeForBranchAsmop (right);
6215       freeForBranchAsmop (left);
6216       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6217       emitcode ("", "%05d$:", nlbl->key + 100);
6218     }
6219   else
6220     {
6221       freeForBranchAsmop (result);
6222       freeForBranchAsmop (right);
6223       freeForBranchAsmop (left);
6224       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6225       emitcode ("", "%05d$:", tlbl->key + 100);
6226     }
6227   ic->generated = 1;
6228 }
6229
6230 /*-----------------------------------------------------------------*/
6231 /* genAnd  - code for and                                          */
6232 /*-----------------------------------------------------------------*/
6233 static void
6234 genAnd (iCode * ic, iCode * ifx)
6235 {
6236   operand *left, *right, *result;
6237   int size, offset = 0;
6238   unsigned long lit = 0L;
6239   int bytelit = 0;
6240   char buffer[10];
6241
6242   D(emitcode (";     genAnd",""));
6243
6244   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6245   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6246   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6247
6248 #ifdef DEBUG_TYPE
6249   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6250             AOP_TYPE (result),
6251             AOP_TYPE (left), AOP_TYPE (right));
6252   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6253             AOP_SIZE (result),
6254             AOP_SIZE (left), AOP_SIZE (right));
6255 #endif
6256
6257   /* if left is a literal & right is not then exchange them */
6258   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6259       AOP_NEEDSACC (left))
6260     {
6261       operand *tmp = right;
6262       right = left;
6263       left = tmp;
6264     }
6265
6266   /* if result = right then exchange left and right */
6267   if (sameRegs (AOP (result), AOP (right)))
6268     {
6269       operand *tmp = right;
6270       right = left;
6271       left = tmp;
6272     }
6273
6274   /* if right is bit then exchange them */
6275   if (AOP_TYPE (right) == AOP_CRY &&
6276       AOP_TYPE (left) != AOP_CRY)
6277     {
6278       operand *tmp = right;
6279       right = left;
6280       left = tmp;
6281     }
6282   if (AOP_TYPE (right) == AOP_LIT)
6283     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6284
6285   size = AOP_SIZE (result);
6286
6287   // if(bit & yy)
6288   // result = bit & yy;
6289   if (AOP_TYPE (left) == AOP_CRY)
6290     {
6291       // c = bit & literal;
6292       if (AOP_TYPE (right) == AOP_LIT)
6293         {
6294           if (lit & 1)
6295             {
6296               if (size && sameRegs (AOP (result), AOP (left)))
6297                 // no change
6298                 goto release;
6299               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6300             }
6301           else
6302             {
6303               // bit(result) = 0;
6304               if (size && (AOP_TYPE (result) == AOP_CRY))
6305                 {
6306                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6307                   goto release;
6308                 }
6309               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6310                 {
6311                   jumpIfTrue (ifx);
6312                   goto release;
6313                 }
6314               emitcode ("clr", "c");
6315             }
6316         }
6317       else
6318         {
6319           if (AOP_TYPE (right) == AOP_CRY)
6320             {
6321               // c = bit & bit;
6322               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6323               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6324             }
6325           else
6326             {
6327               // c = bit & val;
6328               MOVA (aopGet (right, 0, FALSE, FALSE));
6329               // c = lsb
6330               emitcode ("rrc", "a");
6331               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6332             }
6333         }
6334       // bit = c
6335       // val = c
6336       if (size)
6337         outBitC (result);
6338       // if(bit & ...)
6339       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6340         genIfxJump (ifx, "c", left, right, result);
6341       goto release;
6342     }
6343
6344   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6345   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6346   if ((AOP_TYPE (right) == AOP_LIT) &&
6347       (AOP_TYPE (result) == AOP_CRY) &&
6348       (AOP_TYPE (left) != AOP_CRY))
6349     {
6350       int posbit = isLiteralBit (lit);
6351       /* left &  2^n */
6352       if (posbit)
6353         {
6354           posbit--;
6355           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6356           // bit = left & 2^n
6357           if (size)
6358             {
6359               switch (posbit & 0x07)
6360                 {
6361                   case 0: emitcode ("rrc", "a");
6362                           break;
6363                   case 7: emitcode ("rlc", "a");
6364                           break;
6365                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6366                           break;
6367                 }
6368             }
6369           // if(left &  2^n)
6370           else
6371             {
6372               if (ifx)
6373                 {
6374                   SNPRINTF (buffer, sizeof(buffer),
6375                             "acc.%d", posbit & 0x07);
6376                   genIfxJump (ifx, buffer, left, right, result);
6377                 }
6378               else
6379                 {// what is this case? just found it in ds390/gen.c
6380                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6381                 }
6382               goto release;
6383             }
6384         }
6385       else
6386         {
6387           symbol *tlbl = newiTempLabel (NULL);
6388           int sizel = AOP_SIZE (left);
6389           if (size)
6390             emitcode ("setb", "c");
6391           while (sizel--)
6392             {
6393               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6394                 {
6395                   MOVA (aopGet (left, offset, FALSE, FALSE));
6396                   // byte ==  2^n ?
6397                   if ((posbit = isLiteralBit (bytelit)) != 0)
6398                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6399                   else
6400                     {
6401                       if (bytelit != 0x0FFL)
6402                         emitcode ("anl", "a,%s",
6403                                   aopGet (right, offset, FALSE, TRUE));
6404                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6405                     }
6406                 }
6407               offset++;
6408             }
6409           // bit = left & literal
6410           if (size)
6411             {
6412               emitcode ("clr", "c");
6413               emitcode ("", "%05d$:", tlbl->key + 100);
6414             }
6415           // if(left & literal)
6416           else
6417             {
6418               if (ifx)
6419                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6420               else
6421                 emitcode ("", "%05d$:", tlbl->key + 100);
6422               goto release;
6423             }
6424         }
6425       outBitC (result);
6426       goto release;
6427     }
6428
6429   /* if left is same as result */
6430   if (sameRegs (AOP (result), AOP (left)))
6431     {
6432       for (; size--; offset++)
6433         {
6434           if (AOP_TYPE (right) == AOP_LIT)
6435             {
6436               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6437               if (bytelit == 0x0FF)
6438                 {
6439                   /* dummy read of volatile operand */
6440                   if (isOperandVolatile (left, FALSE))
6441                     MOVA (aopGet (left, offset, FALSE, FALSE));
6442                   else
6443                     continue;
6444                 }
6445               else if (bytelit == 0)
6446                 {
6447                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6448                 }
6449               else if (IS_AOP_PREG (result))
6450                 {
6451                   MOVA (aopGet (left, offset, FALSE, TRUE));
6452                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6453                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6454                 }
6455               else
6456                 emitcode ("anl", "%s,%s",
6457                           aopGet (left, offset, FALSE, TRUE),
6458                           aopGet (right, offset, FALSE, FALSE));
6459             }
6460           else
6461             {
6462               if (AOP_TYPE (left) == AOP_ACC)
6463                 {
6464                   if (offset)
6465                     emitcode("mov", "a,b");
6466                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6467                 }
6468               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6469                 {
6470                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6471                   MOVA (aopGet (right, offset, FALSE, FALSE));
6472                   emitcode ("anl", "a,b");
6473                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6474                 }
6475               else if (aopGetUsesAcc (left, offset))
6476                 {
6477                   MOVA (aopGet (left, offset, FALSE, FALSE));
6478                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6479                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6480                 }
6481               else
6482                 {
6483                   MOVA (aopGet (right, offset, FALSE, FALSE));
6484                   if (IS_AOP_PREG (result))
6485                     {
6486                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6487                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6488                     }
6489                   else
6490                     emitcode ("anl", "%s,a",
6491                               aopGet (left, offset, FALSE, TRUE));
6492                 }
6493             }
6494         }
6495     }
6496   else
6497     {
6498       // left & result in different registers
6499       if (AOP_TYPE (result) == AOP_CRY)
6500         {
6501           // result = bit
6502           // if(size), result in bit
6503           // if(!size && ifx), conditional oper: if(left & right)
6504           symbol *tlbl = newiTempLabel (NULL);
6505           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6506           if (size)
6507             emitcode ("setb", "c");
6508           while (sizer--)
6509             {
6510               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6511                   && AOP_TYPE(left)==AOP_ACC)
6512                 {
6513                   if (offset)
6514                     emitcode("mov", "a,b");
6515                   emitcode ("anl", "a,%s",
6516                             aopGet (right, offset, FALSE, FALSE));
6517                 } else {
6518                   if (AOP_TYPE(left)==AOP_ACC)
6519                     {
6520                       if (!offset)
6521                         {
6522                           bool pushedB = pushB ();
6523                           emitcode("mov", "b,a");
6524                           MOVA (aopGet (right, offset, FALSE, FALSE));
6525                           emitcode("anl", "a,b");
6526                           popB (pushedB);
6527                         }
6528                       else
6529                         {
6530                           MOVA (aopGet (right, offset, FALSE, FALSE));
6531                           emitcode("anl", "a,b");
6532                         }
6533                     } else {
6534                       MOVA (aopGet (right, offset, FALSE, FALSE));
6535                       emitcode ("anl", "a,%s",
6536                                 aopGet (left, offset, FALSE, FALSE));
6537                     }
6538                 }
6539               emitcode ("jnz", "%05d$", tlbl->key + 100);
6540               offset++;
6541             }
6542           if (size)
6543             {
6544               CLRC;
6545               emitcode ("", "%05d$:", tlbl->key + 100);
6546               outBitC (result);
6547             }
6548           else if (ifx)
6549             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6550           else
6551             emitcode ("", "%05d$:", tlbl->key + 100);
6552         }
6553       else
6554         {
6555           for (; (size--); offset++)
6556             {
6557               // normal case
6558               // result = left & right
6559               if (AOP_TYPE (right) == AOP_LIT)
6560                 {
6561                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6562                   if (bytelit == 0x0FF)
6563                     {
6564                       aopPut (result,
6565                               aopGet (left, offset, FALSE, FALSE),
6566                               offset,
6567                               isOperandVolatile (result, FALSE));
6568                       continue;
6569                     }
6570                   else if (bytelit == 0)
6571                     {
6572                       /* dummy read of volatile operand */
6573                       if (isOperandVolatile (left, FALSE))
6574                         MOVA (aopGet (left, offset, FALSE, FALSE));
6575                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6576                       continue;
6577                     }
6578                   else if (AOP_TYPE (left) == AOP_ACC)
6579                     {
6580                       if (!offset)
6581                         {
6582                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6583                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6584                           continue;
6585                         }
6586                       else
6587                         {
6588                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6589                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6590                           continue;
6591                         }
6592                     }
6593                 }
6594               // faster than result <- left, anl result,right
6595               // and better if result is SFR
6596               if (AOP_TYPE (left) == AOP_ACC)
6597                 {
6598                   if (offset)
6599                     emitcode("mov", "a,b");
6600                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6601                 }
6602               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6603                 {
6604                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6605                   MOVA (aopGet (right, offset, FALSE, FALSE));
6606                   emitcode ("anl", "a,b");
6607                 }
6608               else if (aopGetUsesAcc (left, offset))
6609                 {
6610                   MOVA (aopGet (left, offset, FALSE, FALSE));
6611                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6612                 }
6613               else
6614                 {
6615                   MOVA (aopGet (right, offset, FALSE, FALSE));
6616                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6617                 }
6618               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6619             }
6620         }
6621     }
6622
6623 release:
6624   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6625   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6626   freeAsmop (result, NULL, ic, TRUE);
6627 }
6628
6629 /*-----------------------------------------------------------------*/
6630 /* genOr  - code for or                                            */
6631 /*-----------------------------------------------------------------*/
6632 static void
6633 genOr (iCode * ic, iCode * ifx)
6634 {
6635   operand *left, *right, *result;
6636   int size, offset = 0;
6637   unsigned long lit = 0L;
6638   int bytelit = 0;
6639
6640   D(emitcode (";     genOr",""));
6641
6642   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6643   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6644   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6645
6646 #ifdef DEBUG_TYPE
6647   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6648             AOP_TYPE (result),
6649             AOP_TYPE (left), AOP_TYPE (right));
6650   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6651             AOP_SIZE (result),
6652             AOP_SIZE (left), AOP_SIZE (right));
6653 #endif
6654
6655   /* if left is a literal & right is not then exchange them */
6656   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6657       AOP_NEEDSACC (left))
6658     {
6659       operand *tmp = right;
6660       right = left;
6661       left = tmp;
6662     }
6663
6664   /* if result = right then exchange them */
6665   if (sameRegs (AOP (result), AOP (right)))
6666     {
6667       operand *tmp = right;
6668       right = left;
6669       left = tmp;
6670     }
6671
6672   /* if right is bit then exchange them */
6673   if (AOP_TYPE (right) == AOP_CRY &&
6674       AOP_TYPE (left) != AOP_CRY)
6675     {
6676       operand *tmp = right;
6677       right = left;
6678       left = tmp;
6679     }
6680   if (AOP_TYPE (right) == AOP_LIT)
6681     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6682
6683   size = AOP_SIZE (result);
6684
6685   // if(bit | yy)
6686   // xx = bit | yy;
6687   if (AOP_TYPE (left) == AOP_CRY)
6688     {
6689       if (AOP_TYPE (right) == AOP_LIT)
6690         {
6691           // c = bit | literal;
6692           if (lit)
6693             {
6694               // lit != 0 => result = 1
6695               if (AOP_TYPE (result) == AOP_CRY)
6696                 {
6697                   if (size)
6698                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6699                   else if (ifx)
6700                     continueIfTrue (ifx);
6701                   goto release;
6702                 }
6703               emitcode ("setb", "c");
6704             }
6705           else
6706             {
6707               // lit == 0 => result = left
6708               if (size && sameRegs (AOP (result), AOP (left)))
6709                 goto release;
6710               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6711             }
6712         }
6713       else
6714         {
6715           if (AOP_TYPE (right) == AOP_CRY)
6716             {
6717               // c = bit | bit;
6718               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6719               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6720             }
6721           else
6722             {
6723               // c = bit | val;
6724               symbol *tlbl = newiTempLabel (NULL);
6725               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6726                 emitcode ("setb", "c");
6727               emitcode ("jb", "%s,%05d$",
6728                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6729               toBoolean (right);
6730               emitcode ("jnz", "%05d$", tlbl->key + 100);
6731               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6732                 {
6733                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6734                   goto release;
6735                 }
6736               else
6737                 {
6738                   CLRC;
6739                   emitcode ("", "%05d$:", tlbl->key + 100);
6740                 }
6741             }
6742         }
6743       // bit = c
6744       // val = c
6745       if (size)
6746         outBitC (result);
6747       // if(bit | ...)
6748       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6749         genIfxJump (ifx, "c", left, right, result);
6750       goto release;
6751     }
6752
6753   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6754   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6755   if ((AOP_TYPE (right) == AOP_LIT) &&
6756       (AOP_TYPE (result) == AOP_CRY) &&
6757       (AOP_TYPE (left) != AOP_CRY))
6758     {
6759       if (lit)
6760         {
6761           // result = 1
6762           if (size)
6763             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6764           else
6765             continueIfTrue (ifx);
6766           goto release;
6767         }
6768       else
6769         {
6770           // lit = 0, result = boolean(left)
6771           if (size)
6772             emitcode ("setb", "c");
6773           toBoolean (right);
6774           if (size)
6775             {
6776               symbol *tlbl = newiTempLabel (NULL);
6777               emitcode ("jnz", "%05d$", tlbl->key + 100);
6778               CLRC;
6779               emitcode ("", "%05d$:", tlbl->key + 100);
6780             }
6781           else
6782             {
6783               genIfxJump (ifx, "a", left, right, result);
6784               goto release;
6785             }
6786         }
6787       outBitC (result);
6788       goto release;
6789     }
6790
6791   /* if left is same as result */
6792   if (sameRegs (AOP (result), AOP (left)))
6793     {
6794       for (; size--; offset++)
6795         {
6796           if (AOP_TYPE (right) == AOP_LIT)
6797             {
6798               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6799               if (bytelit == 0)
6800                 {
6801                   /* dummy read of volatile operand */
6802                   if (isOperandVolatile (left, FALSE))
6803                     MOVA (aopGet (left, offset, FALSE, FALSE));
6804                   else
6805                     continue;
6806                 }
6807               else if (bytelit == 0x0FF)
6808                 {
6809                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6810                 }
6811               else if (IS_AOP_PREG (left))
6812                 {
6813                   MOVA (aopGet (left, offset, FALSE, TRUE));
6814                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6815                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6816                 }
6817               else
6818                 {
6819                   emitcode ("orl", "%s,%s",
6820                             aopGet (left, offset, FALSE, TRUE),
6821                             aopGet (right, offset, FALSE, FALSE));
6822                 }
6823             }
6824           else
6825             {
6826               if (AOP_TYPE (left) == AOP_ACC)
6827                 {
6828                   if (offset)
6829                     emitcode("mov", "a,b");
6830                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6831                 }
6832               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6833                 {
6834                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6835                   MOVA (aopGet (right, offset, FALSE, FALSE));
6836                   emitcode ("orl", "a,b");
6837                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6838                 }
6839               else if (aopGetUsesAcc (left, offset))
6840                 {
6841                   MOVA (aopGet (left, offset, FALSE, FALSE));
6842                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6843                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6844                 }
6845               else
6846                 {
6847                   MOVA (aopGet (right, offset, FALSE, FALSE));
6848                   if (IS_AOP_PREG (left))
6849                     {
6850                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6851                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6852                     }
6853                   else
6854                     {
6855                       emitcode ("orl", "%s,a",
6856                                 aopGet (left, offset, FALSE, TRUE));
6857                     }
6858                 }
6859             }
6860         }
6861     }
6862   else
6863     {
6864       // left & result in different registers
6865       if (AOP_TYPE (result) == AOP_CRY)
6866         {
6867           // result = bit
6868           // if(size), result in bit
6869           // if(!size && ifx), conditional oper: if(left | right)
6870           symbol *tlbl = newiTempLabel (NULL);
6871           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6872           if (size)
6873             emitcode ("setb", "c");
6874           while (sizer--)
6875             {
6876               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6877                 if (offset)
6878                   emitcode("mov", "a,b");
6879                 emitcode ("orl", "a,%s",
6880                           aopGet (right, offset, FALSE, FALSE));
6881               } else {
6882                 MOVA (aopGet (right, offset, FALSE, FALSE));
6883                 emitcode ("orl", "a,%s",
6884                           aopGet (left, offset, FALSE, FALSE));
6885               }
6886               emitcode ("jnz", "%05d$", tlbl->key + 100);
6887               offset++;
6888             }
6889           if (size)
6890             {
6891               CLRC;
6892               emitcode ("", "%05d$:", tlbl->key + 100);
6893               outBitC (result);
6894             }
6895           else if (ifx)
6896             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6897           else
6898             emitcode ("", "%05d$:", tlbl->key + 100);
6899         }
6900       else
6901         {
6902           for (; (size--); offset++)
6903             {
6904               // normal case
6905               // result = left | right
6906               if (AOP_TYPE (right) == AOP_LIT)
6907                 {
6908                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6909                   if (bytelit == 0)
6910                     {
6911                       aopPut (result,
6912                               aopGet (left, offset, FALSE, FALSE),
6913                               offset,
6914                               isOperandVolatile (result, FALSE));
6915                       continue;
6916                     }
6917                   else if (bytelit == 0x0FF)
6918                     {
6919                       /* dummy read of volatile operand */
6920                       if (isOperandVolatile (left, FALSE))
6921                         MOVA (aopGet (left, offset, FALSE, FALSE));
6922                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6923                       continue;
6924                     }
6925                 }
6926               // faster than result <- left, anl result,right
6927               // and better if result is SFR
6928               if (AOP_TYPE (left) == AOP_ACC)
6929                 {
6930                   if (offset)
6931                     emitcode("mov", "a,b");
6932                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6933                 }
6934               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6935                 {
6936                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6937                   MOVA (aopGet (right, offset, FALSE, FALSE));
6938                   emitcode ("orl", "a,b");
6939                 }
6940               else if (aopGetUsesAcc (left, offset))
6941                 {
6942                   MOVA (aopGet (left, offset, FALSE, FALSE));
6943                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6944                 }
6945               else
6946                 {
6947                   MOVA (aopGet (right, offset, FALSE, FALSE));
6948                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6949                 }
6950               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6951             }
6952         }
6953     }
6954
6955 release:
6956   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6957   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6958   freeAsmop (result, NULL, ic, TRUE);
6959 }
6960
6961 /*-----------------------------------------------------------------*/
6962 /* genXor - code for xclusive or                                   */
6963 /*-----------------------------------------------------------------*/
6964 static void
6965 genXor (iCode * ic, iCode * ifx)
6966 {
6967   operand *left, *right, *result;
6968   int size, offset = 0;
6969   unsigned long lit = 0L;
6970   int bytelit = 0;
6971
6972   D(emitcode (";     genXor",""));
6973
6974   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6975   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6976   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6977
6978 #ifdef DEBUG_TYPE
6979   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6980             AOP_TYPE (result),
6981             AOP_TYPE (left), AOP_TYPE (right));
6982   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6983             AOP_SIZE (result),
6984             AOP_SIZE (left), AOP_SIZE (right));
6985 #endif
6986
6987   /* if left is a literal & right is not ||
6988      if left needs acc & right does not */
6989   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6990       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6991     {
6992       operand *tmp = right;
6993       right = left;
6994       left = tmp;
6995     }
6996
6997   /* if result = right then exchange them */
6998   if (sameRegs (AOP (result), AOP (right)))
6999     {
7000       operand *tmp = right;
7001       right = left;
7002       left = tmp;
7003     }
7004
7005   /* if right is bit then exchange them */
7006   if (AOP_TYPE (right) == AOP_CRY &&
7007       AOP_TYPE (left) != AOP_CRY)
7008     {
7009       operand *tmp = right;
7010       right = left;
7011       left = tmp;
7012     }
7013   if (AOP_TYPE (right) == AOP_LIT)
7014     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7015
7016   size = AOP_SIZE (result);
7017
7018   // if(bit ^ yy)
7019   // xx = bit ^ yy;
7020   if (AOP_TYPE (left) == AOP_CRY)
7021     {
7022       if (AOP_TYPE (right) == AOP_LIT)
7023         {
7024           // c = bit & literal;
7025           if (lit >> 1)
7026             {
7027               // lit>>1  != 0 => result = 1
7028               if (AOP_TYPE (result) == AOP_CRY)
7029                 {
7030                   if (size)
7031                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7032                   else if (ifx)
7033                     continueIfTrue (ifx);
7034                   goto release;
7035                 }
7036               emitcode ("setb", "c");
7037             }
7038           else
7039             {
7040               // lit == (0 or 1)
7041               if (lit == 0)
7042                 {
7043                   // lit == 0, result = left
7044                   if (size && sameRegs (AOP (result), AOP (left)))
7045                     goto release;
7046                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7047                 }
7048               else
7049                 {
7050                   // lit == 1, result = not(left)
7051                   if (size && sameRegs (AOP (result), AOP (left)))
7052                     {
7053                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7054                       goto release;
7055                     }
7056                   else
7057                     {
7058                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7059                       emitcode ("cpl", "c");
7060                     }
7061                 }
7062             }
7063
7064         }
7065       else
7066         {
7067           // right != literal
7068           symbol *tlbl = newiTempLabel (NULL);
7069           if (AOP_TYPE (right) == AOP_CRY)
7070             {
7071               // c = bit ^ bit;
7072               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7073             }
7074           else
7075             {
7076               int sizer = AOP_SIZE (right);
7077               // c = bit ^ val
7078               // if val>>1 != 0, result = 1
7079               emitcode ("setb", "c");
7080               while (sizer)
7081                 {
7082                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7083                   if (sizer == 1)
7084                     // test the msb of the lsb
7085                     emitcode ("anl", "a,#0xfe");
7086                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7087                   sizer--;
7088                 }
7089               // val = (0,1)
7090               emitcode ("rrc", "a");
7091             }
7092           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7093           emitcode ("cpl", "c");
7094           emitcode ("", "%05d$:", (tlbl->key + 100));
7095         }
7096       // bit = c
7097       // val = c
7098       if (size)
7099         outBitC (result);
7100       // if(bit | ...)
7101       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7102         genIfxJump (ifx, "c", left, right, result);
7103       goto release;
7104     }
7105
7106   /* if left is same as result */
7107   if (sameRegs (AOP (result), AOP (left)))
7108     {
7109       for (; size--; offset++)
7110         {
7111           if (AOP_TYPE (right) == AOP_LIT)
7112             {
7113               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7114               if (bytelit == 0)
7115                 {
7116                   /* dummy read of volatile operand */
7117                   if (isOperandVolatile (left, FALSE))
7118                     MOVA (aopGet (left, offset, FALSE, FALSE));
7119                   else
7120                     continue;
7121                 }
7122               else if (IS_AOP_PREG (left))
7123                 {
7124                   MOVA (aopGet (left, offset, FALSE, TRUE));
7125                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7126                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7127                 }
7128               else
7129                 {
7130                   emitcode ("xrl", "%s,%s",
7131                             aopGet (left, offset, FALSE, TRUE),
7132                             aopGet (right, offset, FALSE, FALSE));
7133                 }
7134             }
7135           else
7136             {
7137               if (AOP_TYPE (left) == AOP_ACC)
7138                 {
7139                   if (offset)
7140                     emitcode("mov", "a,b");
7141                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7142                 }
7143               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7144                 {
7145                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7146                   MOVA (aopGet (right, offset, FALSE, FALSE));
7147                   emitcode ("xrl", "a,b");
7148                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7149                 }
7150               else if (aopGetUsesAcc (left, offset))
7151                 {
7152                   MOVA (aopGet (left, offset, FALSE, FALSE));
7153                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7154                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7155                 }
7156               else
7157                 {
7158                   MOVA (aopGet (right, offset, FALSE, FALSE));
7159                   if (IS_AOP_PREG (left))
7160                     {
7161                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7162                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7163                     }
7164                   else
7165                     emitcode ("xrl", "%s,a",
7166                               aopGet (left, offset, FALSE, TRUE));
7167                 }
7168             }
7169         }
7170     }
7171   else
7172     {
7173       // left & result in different registers
7174       if (AOP_TYPE (result) == AOP_CRY)
7175         {
7176           // result = bit
7177           // if(size), result in bit
7178           // if(!size && ifx), conditional oper: if(left ^ right)
7179           symbol *tlbl = newiTempLabel (NULL);
7180           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7181           if (size)
7182             emitcode ("setb", "c");
7183           while (sizer--)
7184             {
7185               if ((AOP_TYPE (right) == AOP_LIT) &&
7186                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7187                 {
7188                   MOVA (aopGet (left, offset, FALSE, FALSE));
7189                 }
7190               else
7191                 {
7192                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7193                     if (offset)
7194                       emitcode("mov", "a,b");
7195                     emitcode ("xrl", "a,%s",
7196                               aopGet (right, offset, FALSE, FALSE));
7197                   } else {
7198                     MOVA (aopGet (right, offset, FALSE, FALSE));
7199                     emitcode ("xrl", "a,%s",
7200                               aopGet (left, offset, FALSE, FALSE));
7201                   }
7202                 }
7203               emitcode ("jnz", "%05d$", tlbl->key + 100);
7204               offset++;
7205             }
7206           if (size)
7207             {
7208               CLRC;
7209               emitcode ("", "%05d$:", tlbl->key + 100);
7210               outBitC (result);
7211             }
7212           else if (ifx)
7213             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7214         }
7215       else
7216         {
7217           for (; (size--); offset++)
7218             {
7219               // normal case
7220               // result = left & right
7221               if (AOP_TYPE (right) == AOP_LIT)
7222                 {
7223                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7224                   if (bytelit == 0)
7225                     {
7226                       aopPut (result,
7227                               aopGet (left, offset, FALSE, FALSE),
7228                               offset,
7229                               isOperandVolatile (result, FALSE));
7230                       continue;
7231                     }
7232                 }
7233               // faster than result <- left, anl result,right
7234               // and better if result is SFR
7235               if (AOP_TYPE (left) == AOP_ACC)
7236                 {
7237                   if (offset)
7238                     emitcode("mov", "a,b");
7239                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7240                 }
7241               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7242                 {
7243                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7244                   MOVA (aopGet (right, offset, FALSE, FALSE));
7245                   emitcode ("xrl", "a,b");
7246                 }
7247               else if (aopGetUsesAcc (left, offset))
7248                 {
7249                   MOVA (aopGet (left, offset, FALSE, FALSE));
7250                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7251                 }
7252               else
7253                 {
7254                   MOVA (aopGet (right, offset, FALSE, FALSE));
7255                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7256                 }
7257               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7258             }
7259         }
7260     }
7261
7262 release:
7263   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7264   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7265   freeAsmop (result, NULL, ic, TRUE);
7266 }
7267
7268 /*-----------------------------------------------------------------*/
7269 /* genInline - write the inline code out                           */
7270 /*-----------------------------------------------------------------*/
7271 static void
7272 genInline (iCode * ic)
7273 {
7274   char *buffer, *bp, *bp1;
7275
7276   D(emitcode (";     genInline",""));
7277
7278   _G.inLine += (!options.asmpeep);
7279
7280   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7281   strcpy (buffer, IC_INLINE (ic));
7282
7283   /* emit each line as a code */
7284   while (*bp)
7285     {
7286       if (*bp == '\n')
7287         {
7288           *bp++ = '\0';
7289           emitcode (bp1, "");
7290           bp1 = bp;
7291         }
7292       else
7293         {
7294           /* Add \n for labels, not dirs such as c:\mydir */
7295           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7296             {
7297               bp++;
7298               *bp = '\0';
7299               bp++;
7300               emitcode (bp1, "");
7301               bp1 = bp;
7302             }
7303           else
7304             bp++;
7305         }
7306     }
7307   if (bp1 != bp)
7308     emitcode (bp1, "");
7309   /*     emitcode("",buffer); */
7310   _G.inLine -= (!options.asmpeep);
7311 }
7312
7313 /*-----------------------------------------------------------------*/
7314 /* genRRC - rotate right with carry                                */
7315 /*-----------------------------------------------------------------*/
7316 static void
7317 genRRC (iCode * ic)
7318 {
7319   operand *left, *result;
7320   int size, offset = 0;
7321   char *l;
7322
7323   D(emitcode (";     genRRC",""));
7324
7325   /* rotate right with carry */
7326   left = IC_LEFT (ic);
7327   result = IC_RESULT (ic);
7328   aopOp (left, ic, FALSE);
7329   aopOp (result, ic, FALSE);
7330
7331   /* move it to the result */
7332   size = AOP_SIZE (result);
7333   offset = size - 1;
7334   if (size == 1) { /* special case for 1 byte */
7335       l = aopGet (left, offset, FALSE, FALSE);
7336       MOVA (l);
7337       emitcode ("rr", "a");
7338       goto release;
7339   }
7340   /* no need to clear carry, bit7 will be written later */
7341   while (size--)
7342     {
7343       l = aopGet (left, offset, FALSE, FALSE);
7344       MOVA (l);
7345       emitcode ("rrc", "a");
7346       if (AOP_SIZE (result) > 1)
7347         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7348     }
7349   /* now we need to put the carry into the
7350      highest order byte of the result */
7351   if (AOP_SIZE (result) > 1)
7352     {
7353       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7354       MOVA (l);
7355     }
7356   emitcode ("mov", "acc.7,c");
7357  release:
7358   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7359   freeAsmop (left, NULL, ic, TRUE);
7360   freeAsmop (result, NULL, ic, TRUE);
7361 }
7362
7363 /*-----------------------------------------------------------------*/
7364 /* genRLC - generate code for rotate left with carry               */
7365 /*-----------------------------------------------------------------*/
7366 static void
7367 genRLC (iCode * ic)
7368 {
7369   operand *left, *result;
7370   int size, offset = 0;
7371   char *l;
7372
7373   D(emitcode (";     genRLC",""));
7374
7375   /* rotate right with carry */
7376   left = IC_LEFT (ic);
7377   result = IC_RESULT (ic);
7378   aopOp (left, ic, FALSE);
7379   aopOp (result, ic, FALSE);
7380
7381   /* move it to the result */
7382   size = AOP_SIZE (result);
7383   offset = 0;
7384   if (size--)
7385     {
7386       l = aopGet (left, offset, FALSE, FALSE);
7387       MOVA (l);
7388       if (size == 0) { /* special case for 1 byte */
7389               emitcode("rl","a");
7390               goto release;
7391       }
7392       emitcode("rlc","a"); /* bit0 will be written later */
7393       if (AOP_SIZE (result) > 1)
7394         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7395       while (size--)
7396         {
7397           l = aopGet (left, offset, FALSE, FALSE);
7398           MOVA (l);
7399           emitcode ("rlc", "a");
7400           if (AOP_SIZE (result) > 1)
7401             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7402         }
7403     }
7404   /* now we need to put the carry into the
7405      highest order byte of the result */
7406   if (AOP_SIZE (result) > 1)
7407     {
7408       l = aopGet (result, 0, FALSE, FALSE);
7409       MOVA (l);
7410     }
7411   emitcode ("mov", "acc.0,c");
7412  release:
7413   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7414   freeAsmop (left, NULL, ic, TRUE);
7415   freeAsmop (result, NULL, ic, TRUE);
7416 }
7417
7418 /*-----------------------------------------------------------------*/
7419 /* genGetHbit - generates code get highest order bit               */
7420 /*-----------------------------------------------------------------*/
7421 static void
7422 genGetHbit (iCode * ic)
7423 {
7424   operand *left, *result;
7425
7426   D(emitcode (";     genGetHbit",""));
7427
7428   left = IC_LEFT (ic);
7429   result = IC_RESULT (ic);
7430   aopOp (left, ic, FALSE);
7431   aopOp (result, ic, FALSE);
7432
7433   /* get the highest order byte into a */
7434   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7435   if (AOP_TYPE (result) == AOP_CRY)
7436     {
7437       emitcode ("rlc", "a");
7438       outBitC (result);
7439     }
7440   else
7441     {
7442       emitcode ("rl", "a");
7443       emitcode ("anl", "a,#0x01");
7444       outAcc (result);
7445     }
7446
7447
7448   freeAsmop (left, NULL, ic, TRUE);
7449   freeAsmop (result, NULL, ic, TRUE);
7450 }
7451
7452 /*-----------------------------------------------------------------*/
7453 /* genGetAbit - generates code get a single bit                    */
7454 /*-----------------------------------------------------------------*/
7455 static void
7456 genGetAbit (iCode * ic)
7457 {
7458   operand *left, *right, *result;
7459   int shCount;
7460
7461   D(emitcode (";     genGetAbit",""));
7462
7463   left = IC_LEFT (ic);
7464   right = IC_RIGHT (ic);
7465   result = IC_RESULT (ic);
7466   aopOp (left, ic, FALSE);
7467   aopOp (right, ic, FALSE);
7468   aopOp (result, ic, FALSE);
7469
7470   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7471
7472   /* get the needed byte into a */
7473   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7474   shCount %= 8;
7475   if (AOP_TYPE (result) == AOP_CRY)
7476     {
7477       if ((shCount) == 7)
7478           emitcode ("rlc", "a");
7479       else if ((shCount) == 0)
7480           emitcode ("rrc", "a");
7481       else
7482           emitcode ("mov", "c,acc[%d]", shCount);
7483       outBitC (result);
7484     }
7485   else
7486     {
7487       switch (shCount)
7488         {
7489         case 2:
7490           emitcode ("rr", "a");
7491           //fallthrough
7492         case 1:
7493           emitcode ("rr", "a");
7494           //fallthrough
7495         case 0:
7496           emitcode ("anl", "a,#0x01");
7497           break;
7498         case 3:
7499         case 5:
7500           emitcode ("mov", "c,acc[%d]", shCount);
7501           emitcode ("clr", "a");
7502           emitcode ("rlc", "a");
7503           break;
7504         case 4:
7505           emitcode ("swap", "a");
7506           emitcode ("anl", "a,#0x01");
7507           break;
7508         case 6:
7509           emitcode ("rl", "a");
7510           //fallthrough
7511         case 7:
7512           emitcode ("rl", "a");
7513           emitcode ("anl", "a,#0x01");
7514           break;
7515         }
7516       outAcc (result);
7517     }
7518
7519   freeAsmop (left, NULL, ic, TRUE);
7520   freeAsmop (right, NULL, ic, TRUE);
7521   freeAsmop (result, NULL, ic, TRUE);
7522 }
7523
7524 /*-----------------------------------------------------------------*/
7525 /* genGetByte - generates code get a single byte                   */
7526 /*-----------------------------------------------------------------*/
7527 static void
7528 genGetByte (iCode * ic)
7529 {
7530   operand *left, *right, *result;
7531   int offset;
7532
7533   D(emitcode (";     genGetByte",""));
7534
7535   left = IC_LEFT (ic);
7536   right = IC_RIGHT (ic);
7537   result = IC_RESULT (ic);
7538   aopOp (left, ic, FALSE);
7539   aopOp (right, ic, FALSE);
7540   aopOp (result, ic, FALSE);
7541
7542   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7543   aopPut (result,
7544           aopGet (left, offset, FALSE, FALSE),
7545           0,
7546           isOperandVolatile (result, FALSE));
7547
7548   freeAsmop (left, NULL, ic, TRUE);
7549   freeAsmop (right, NULL, ic, TRUE);
7550   freeAsmop (result, NULL, ic, TRUE);
7551 }
7552
7553 /*-----------------------------------------------------------------*/
7554 /* genGetWord - generates code get two bytes                       */
7555 /*-----------------------------------------------------------------*/
7556 static void
7557 genGetWord (iCode * ic)
7558 {
7559   operand *left, *right, *result;
7560   int offset;
7561
7562   D(emitcode (";     genGetWord",""));
7563
7564   left = IC_LEFT (ic);
7565   right = IC_RIGHT (ic);
7566   result = IC_RESULT (ic);
7567   aopOp (left, ic, FALSE);
7568   aopOp (right, ic, FALSE);
7569   aopOp (result, ic, FALSE);
7570
7571   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7572   aopPut (result,
7573           aopGet (left, offset, FALSE, FALSE),
7574           0,
7575           isOperandVolatile (result, FALSE));
7576   aopPut (result,
7577           aopGet (left, offset+1, FALSE, FALSE),
7578           1,
7579           isOperandVolatile (result, FALSE));
7580
7581   freeAsmop (left, NULL, ic, TRUE);
7582   freeAsmop (right, NULL, ic, TRUE);
7583   freeAsmop (result, NULL, ic, TRUE);
7584 }
7585
7586 /*-----------------------------------------------------------------*/
7587 /* genSwap - generates code to swap nibbles or bytes               */
7588 /*-----------------------------------------------------------------*/
7589 static void
7590 genSwap (iCode * ic)
7591 {
7592   operand *left, *result;
7593
7594   D(emitcode (";     genSwap",""));
7595
7596   left = IC_LEFT (ic);
7597   result = IC_RESULT (ic);
7598   aopOp (left, ic, FALSE);
7599   aopOp (result, ic, FALSE);
7600
7601   switch (AOP_SIZE (left))
7602     {
7603     case 1: /* swap nibbles in byte */
7604       MOVA (aopGet (left, 0, FALSE, FALSE));
7605       emitcode ("swap", "a");
7606       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7607       break;
7608     case 2: /* swap bytes in word */
7609       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7610         {
7611           MOVA (aopGet (left, 0, FALSE, FALSE));
7612           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7613                   0, isOperandVolatile (result, FALSE));
7614           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7615         }
7616       else if (operandsEqu (left, result))
7617         {
7618           char * reg = "a";
7619           bool pushedB = FALSE, leftInB = FALSE;
7620
7621           MOVA (aopGet (left, 0, FALSE, FALSE));
7622           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7623             {
7624               pushedB = pushB ();
7625               emitcode ("mov", "b,a");
7626               reg = "b";
7627               leftInB = TRUE;
7628             }
7629           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7630                   0, isOperandVolatile (result, FALSE));
7631           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7632
7633           if (leftInB)
7634             popB (pushedB);
7635         }
7636       else
7637         {
7638           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7639                   0, isOperandVolatile (result, FALSE));
7640           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7641                   1, isOperandVolatile (result, FALSE));
7642         }
7643       break;
7644     default:
7645       wassertl(FALSE, "unsupported SWAP operand size");
7646     }
7647
7648   freeAsmop (left, NULL, ic, TRUE);
7649   freeAsmop (result, NULL, ic, TRUE);
7650 }
7651
7652
7653 /*-----------------------------------------------------------------*/
7654 /* AccRol - rotate left accumulator by known count                 */
7655 /*-----------------------------------------------------------------*/
7656 static void
7657 AccRol (int shCount)
7658 {
7659   shCount &= 0x0007;            // shCount : 0..7
7660
7661   switch (shCount)
7662     {
7663     case 0:
7664       break;
7665     case 1:
7666       emitcode ("rl", "a");
7667       break;
7668     case 2:
7669       emitcode ("rl", "a");
7670       emitcode ("rl", "a");
7671       break;
7672     case 3:
7673       emitcode ("swap", "a");
7674       emitcode ("rr", "a");
7675       break;
7676     case 4:
7677       emitcode ("swap", "a");
7678       break;
7679     case 5:
7680       emitcode ("swap", "a");
7681       emitcode ("rl", "a");
7682       break;
7683     case 6:
7684       emitcode ("rr", "a");
7685       emitcode ("rr", "a");
7686       break;
7687     case 7:
7688       emitcode ("rr", "a");
7689       break;
7690     }
7691 }
7692
7693 /*-----------------------------------------------------------------*/
7694 /* AccLsh - left shift accumulator by known count                  */
7695 /*-----------------------------------------------------------------*/
7696 static void
7697 AccLsh (int shCount)
7698 {
7699   if (shCount != 0)
7700     {
7701       if (shCount == 1)
7702         emitcode ("add", "a,acc");
7703       else if (shCount == 2)
7704         {
7705           emitcode ("add", "a,acc");
7706           emitcode ("add", "a,acc");
7707         }
7708       else
7709         {
7710           /* rotate left accumulator */
7711           AccRol (shCount);
7712           /* and kill the lower order bits */
7713           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7714         }
7715     }
7716 }
7717
7718 /*-----------------------------------------------------------------*/
7719 /* AccRsh - right shift accumulator by known count                 */
7720 /*-----------------------------------------------------------------*/
7721 static void
7722 AccRsh (int shCount)
7723 {
7724   if (shCount != 0)
7725     {
7726       if (shCount == 1)
7727         {
7728           CLRC;
7729           emitcode ("rrc", "a");
7730         }
7731       else
7732         {
7733           /* rotate right accumulator */
7734           AccRol (8 - shCount);
7735           /* and kill the higher order bits */
7736           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7737         }
7738     }
7739 }
7740
7741 /*-----------------------------------------------------------------*/
7742 /* AccSRsh - signed right shift accumulator by known count                 */
7743 /*-----------------------------------------------------------------*/
7744 static void
7745 AccSRsh (int shCount)
7746 {
7747   symbol *tlbl;
7748   if (shCount != 0)
7749     {
7750       if (shCount == 1)
7751         {
7752           emitcode ("mov", "c,acc.7");
7753           emitcode ("rrc", "a");
7754         }
7755       else if (shCount == 2)
7756         {
7757           emitcode ("mov", "c,acc.7");
7758           emitcode ("rrc", "a");
7759           emitcode ("mov", "c,acc.7");
7760           emitcode ("rrc", "a");
7761         }
7762       else
7763         {
7764           tlbl = newiTempLabel (NULL);
7765           /* rotate right accumulator */
7766           AccRol (8 - shCount);
7767           /* and kill the higher order bits */
7768           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7769           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7770           emitcode ("orl", "a,#0x%02x",
7771                     (unsigned char) ~SRMask[shCount]);
7772           emitcode ("", "%05d$:", tlbl->key + 100);
7773         }
7774     }
7775 }
7776
7777 /*-----------------------------------------------------------------*/
7778 /* shiftR1Left2Result - shift right one byte from left to result   */
7779 /*-----------------------------------------------------------------*/
7780 static void
7781 shiftR1Left2Result (operand * left, int offl,
7782                     operand * result, int offr,
7783                     int shCount, int sign)
7784 {
7785   MOVA (aopGet (left, offl, FALSE, FALSE));
7786   /* shift right accumulator */
7787   if (sign)
7788     AccSRsh (shCount);
7789   else
7790     AccRsh (shCount);
7791   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7792 }
7793
7794 /*-----------------------------------------------------------------*/
7795 /* shiftL1Left2Result - shift left one byte from left to result    */
7796 /*-----------------------------------------------------------------*/
7797 static void
7798 shiftL1Left2Result (operand * left, int offl,
7799                     operand * result, int offr, int shCount)
7800 {
7801   char *l;
7802   l = aopGet (left, offl, FALSE, FALSE);
7803   MOVA (l);
7804   /* shift left accumulator */
7805   AccLsh (shCount);
7806   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7807 }
7808
7809 /*-----------------------------------------------------------------*/
7810 /* movLeft2Result - move byte from left to result                  */
7811 /*-----------------------------------------------------------------*/
7812 static void
7813 movLeft2Result (operand * left, int offl,
7814                 operand * result, int offr, int sign)
7815 {
7816   char *l;
7817   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7818     {
7819       l = aopGet (left, offl, FALSE, FALSE);
7820
7821       if (*l == '@' && (IS_AOP_PREG (result)))
7822         {
7823           emitcode ("mov", "a,%s", l);
7824           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7825         }
7826       else
7827         {
7828           if (!sign)
7829             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7830           else
7831             {
7832               /* MSB sign in acc.7 ! */
7833               if (getDataSize (left) == offl + 1)
7834                 {
7835                   MOVA (l);
7836                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7837                 }
7838             }
7839         }
7840     }
7841 }
7842
7843 /*-----------------------------------------------------------------*/
7844 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7845 /*-----------------------------------------------------------------*/
7846 static void
7847 AccAXRrl1 (char *x)
7848 {
7849   emitcode ("rrc", "a");
7850   emitcode ("xch", "a,%s", x);
7851   emitcode ("rrc", "a");
7852   emitcode ("xch", "a,%s", x);
7853 }
7854
7855 /*-----------------------------------------------------------------*/
7856 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7857 /*-----------------------------------------------------------------*/
7858 static void
7859 AccAXLrl1 (char *x)
7860 {
7861   emitcode ("xch", "a,%s", x);
7862   emitcode ("rlc", "a");
7863   emitcode ("xch", "a,%s", x);
7864   emitcode ("rlc", "a");
7865 }
7866
7867 /*-----------------------------------------------------------------*/
7868 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7869 /*-----------------------------------------------------------------*/
7870 static void
7871 AccAXLsh1 (char *x)
7872 {
7873   emitcode ("xch", "a,%s", x);
7874   emitcode ("add", "a,acc");
7875   emitcode ("xch", "a,%s", x);
7876   emitcode ("rlc", "a");
7877 }
7878
7879 /*-----------------------------------------------------------------*/
7880 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7881 /*-----------------------------------------------------------------*/
7882 static void
7883 AccAXLsh (char *x, int shCount)
7884 {
7885   switch (shCount)
7886     {
7887     case 0:
7888       break;
7889     case 1:
7890       AccAXLsh1 (x);
7891       break;
7892     case 2:
7893       AccAXLsh1 (x);
7894       AccAXLsh1 (x);
7895       break;
7896     case 3:
7897     case 4:
7898     case 5:                     // AAAAABBB:CCCCCDDD
7899
7900       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7901
7902       emitcode ("anl", "a,#0x%02x",
7903                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7904
7905       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7906
7907       AccRol (shCount);         // DDDCCCCC:BBB00000
7908
7909       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7910
7911       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7912
7913       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7914
7915       emitcode ("anl", "a,#0x%02x",
7916                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7917
7918       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7919
7920       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7921
7922       break;
7923     case 6:                     // AAAAAABB:CCCCCCDD
7924       emitcode ("anl", "a,#0x%02x",
7925                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7926       emitcode ("mov", "c,acc.0");      // c = B
7927       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7928 #if 0 // REMOVE ME
7929       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7930       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7931 #else
7932       emitcode("rrc","a");
7933       emitcode("xch","a,%s", x);
7934       emitcode("rrc","a");
7935       emitcode("mov","c,acc.0"); //<< get correct bit
7936       emitcode("xch","a,%s", x);
7937
7938       emitcode("rrc","a");
7939       emitcode("xch","a,%s", x);
7940       emitcode("rrc","a");
7941       emitcode("xch","a,%s", x);
7942 #endif
7943       break;
7944     case 7:                     // a:x <<= 7
7945
7946       emitcode ("anl", "a,#0x%02x",
7947                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7948
7949       emitcode ("mov", "c,acc.0");      // c = B
7950
7951       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7952
7953       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7954
7955       break;
7956     default:
7957       break;
7958     }
7959 }
7960
7961 /*-----------------------------------------------------------------*/
7962 /* AccAXRsh - right shift a:x known count (0..7)                   */
7963 /*-----------------------------------------------------------------*/
7964 static void
7965 AccAXRsh (char *x, int shCount)
7966 {
7967   switch (shCount)
7968     {
7969     case 0:
7970       break;
7971     case 1:
7972       CLRC;
7973       AccAXRrl1 (x);            // 0->a:x
7974
7975       break;
7976     case 2:
7977       CLRC;
7978       AccAXRrl1 (x);            // 0->a:x
7979
7980       CLRC;
7981       AccAXRrl1 (x);            // 0->a:x
7982
7983       break;
7984     case 3:
7985     case 4:
7986     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7987
7988       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7989
7990       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7991
7992       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7993
7994       emitcode ("anl", "a,#0x%02x",
7995                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7996
7997       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7998
7999       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8000
8001       emitcode ("anl", "a,#0x%02x",
8002                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8003
8004       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8005
8006       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8007
8008       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8009
8010       break;
8011     case 6:                     // AABBBBBB:CCDDDDDD
8012
8013       emitcode ("mov", "c,acc.7");
8014       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8015
8016       emitcode ("mov", "c,acc.7");
8017       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8018
8019       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8020
8021       emitcode ("anl", "a,#0x%02x",
8022                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8023
8024       break;
8025     case 7:                     // ABBBBBBB:CDDDDDDD
8026
8027       emitcode ("mov", "c,acc.7");      // c = A
8028
8029       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8030
8031       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8032
8033       emitcode ("anl", "a,#0x%02x",
8034                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8035
8036       break;
8037     default:
8038       break;
8039     }
8040 }
8041
8042 /*-----------------------------------------------------------------*/
8043 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8044 /*-----------------------------------------------------------------*/
8045 static void
8046 AccAXRshS (char *x, int shCount)
8047 {
8048   symbol *tlbl;
8049   switch (shCount)
8050     {
8051     case 0:
8052       break;
8053     case 1:
8054       emitcode ("mov", "c,acc.7");
8055       AccAXRrl1 (x);            // s->a:x
8056
8057       break;
8058     case 2:
8059       emitcode ("mov", "c,acc.7");
8060       AccAXRrl1 (x);            // s->a:x
8061
8062       emitcode ("mov", "c,acc.7");
8063       AccAXRrl1 (x);            // s->a:x
8064
8065       break;
8066     case 3:
8067     case 4:
8068     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8069
8070       tlbl = newiTempLabel (NULL);
8071       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8072
8073       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8074
8075       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8076
8077       emitcode ("anl", "a,#0x%02x",
8078                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8079
8080       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8081
8082       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8083
8084       emitcode ("anl", "a,#0x%02x",
8085                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8086
8087       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8088
8089       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8090
8091       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8092
8093       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8094       emitcode ("orl", "a,#0x%02x",
8095                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8096
8097       emitcode ("", "%05d$:", tlbl->key + 100);
8098       break;                    // SSSSAAAA:BBBCCCCC
8099
8100     case 6:                     // AABBBBBB:CCDDDDDD
8101
8102       tlbl = newiTempLabel (NULL);
8103       emitcode ("mov", "c,acc.7");
8104       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8105
8106       emitcode ("mov", "c,acc.7");
8107       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8108
8109       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8110
8111       emitcode ("anl", "a,#0x%02x",
8112                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8113
8114       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8115       emitcode ("orl", "a,#0x%02x",
8116                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8117
8118       emitcode ("", "%05d$:", tlbl->key + 100);
8119       break;
8120     case 7:                     // ABBBBBBB:CDDDDDDD
8121
8122       tlbl = newiTempLabel (NULL);
8123       emitcode ("mov", "c,acc.7");      // c = A
8124
8125       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8126
8127       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8128
8129       emitcode ("anl", "a,#0x%02x",
8130                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8131
8132       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8133       emitcode ("orl", "a,#0x%02x",
8134                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8135
8136       emitcode ("", "%05d$:", tlbl->key + 100);
8137       break;
8138     default:
8139       break;
8140     }
8141 }
8142
8143 /*-----------------------------------------------------------------*/
8144 /* shiftL2Left2Result - shift left two bytes from left to result   */
8145 /*-----------------------------------------------------------------*/
8146 static void
8147 shiftL2Left2Result (operand * left, int offl,
8148                     operand * result, int offr, int shCount)
8149 {
8150   char * x;
8151   bool pushedB = FALSE;
8152   bool usedB = FALSE;
8153
8154   if (sameRegs (AOP (result), AOP (left)) &&
8155       ((offl + MSB16) == offr))
8156     {
8157       /* don't crash result[offr] */
8158       MOVA (aopGet (left, offl, FALSE, FALSE));
8159       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8160       x = aopGet (result, offr, FALSE, FALSE);
8161     }
8162   else if (aopGetUsesAcc (result, offr))
8163     {
8164       movLeft2Result (left, offl, result, offr, 0);
8165       pushedB = pushB ();
8166       usedB = TRUE;
8167       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8168       MOVA (aopGet (result, offr, FALSE, FALSE));
8169       emitcode ("xch", "a,b");
8170       x = "b";
8171     }
8172   else
8173     {
8174       movLeft2Result (left, offl, result, offr, 0);
8175       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8176       x = aopGet (result, offr, FALSE, FALSE);
8177     }
8178   /* ax << shCount (x = lsb(result)) */
8179   AccAXLsh (x, shCount);
8180   if (usedB)
8181     {
8182       emitcode ("xch", "a,b");
8183       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8184       aopPut (result, "b", offr + MSB16, isOperandVolatile (result, FALSE));
8185       popB (pushedB);
8186     }
8187   else
8188     {
8189       aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8190     }
8191 }
8192
8193
8194 /*-----------------------------------------------------------------*/
8195 /* shiftR2Left2Result - shift right two bytes from left to result  */
8196 /*-----------------------------------------------------------------*/
8197 static void
8198 shiftR2Left2Result (operand * left, int offl,
8199                     operand * result, int offr,
8200                     int shCount, int sign)
8201 {
8202   char * x;
8203   bool pushedB = FALSE;
8204   bool usedB = FALSE;
8205
8206   if (sameRegs (AOP (result), AOP (left)) &&
8207       ((offl + MSB16) == offr))
8208     {
8209       /* don't crash result[offr] */
8210       MOVA (aopGet (left, offl, FALSE, FALSE));
8211       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8212       x = aopGet (result, offr, FALSE, FALSE);
8213     }
8214   else if (aopGetUsesAcc (result, offr))
8215     {
8216       movLeft2Result (left, offl, result, offr, 0);
8217       pushedB = pushB ();
8218       usedB = TRUE;
8219       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8220       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8221       x = "b";
8222     }
8223   else
8224     {
8225       movLeft2Result (left, offl, result, offr, 0);
8226       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8227       x = aopGet (result, offr, FALSE, FALSE);
8228     }
8229   /* a:x >> shCount (x = lsb(result)) */
8230   if (sign)
8231     AccAXRshS (x, shCount);
8232   else
8233     AccAXRsh (x, shCount);
8234   if (usedB)
8235     {
8236       emitcode ("xch", "a,b");
8237       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8238       emitcode ("xch", "a,b");
8239       popB (pushedB);
8240     }
8241   if (getDataSize (result) > 1)
8242     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8243 }
8244
8245 /*-----------------------------------------------------------------*/
8246 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8247 /*-----------------------------------------------------------------*/
8248 static void
8249 shiftLLeftOrResult (operand * left, int offl,
8250                     operand * result, int offr, int shCount)
8251 {
8252   MOVA (aopGet (left, offl, FALSE, FALSE));
8253   /* shift left accumulator */
8254   AccLsh (shCount);
8255   /* or with result */
8256   if (aopGetUsesAcc (result, offr))
8257     {
8258       emitcode ("xch", "a,b");
8259       MOVA (aopGet (result, offr, FALSE, FALSE));
8260       emitcode ("orl", "a,b");
8261     }
8262   else
8263     {
8264       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8265     }
8266   /* back to result */
8267   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8268 }
8269
8270 /*-----------------------------------------------------------------*/
8271 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8272 /*-----------------------------------------------------------------*/
8273 static void
8274 shiftRLeftOrResult (operand * left, int offl,
8275                     operand * result, int offr, int shCount)
8276 {
8277   MOVA (aopGet (left, offl, FALSE, FALSE));
8278   /* shift right accumulator */
8279   AccRsh (shCount);
8280   /* or with result */
8281   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8282   /* back to result */
8283   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8284 }
8285
8286 /*-----------------------------------------------------------------*/
8287 /* genlshOne - left shift a one byte quantity by known count       */
8288 /*-----------------------------------------------------------------*/
8289 static void
8290 genlshOne (operand * result, operand * left, int shCount)
8291 {
8292   D(emitcode (";     genlshOne",""));
8293
8294   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8295 }
8296
8297 /*-----------------------------------------------------------------*/
8298 /* genlshTwo - left shift two bytes by known amount != 0           */
8299 /*-----------------------------------------------------------------*/
8300 static void
8301 genlshTwo (operand * result, operand * left, int shCount)
8302 {
8303   int size;
8304
8305   D(emitcode (";     genlshTwo",""));
8306
8307   size = getDataSize (result);
8308
8309   /* if shCount >= 8 */
8310   if (shCount >= 8)
8311     {
8312       shCount -= 8;
8313
8314       if (size > 1)
8315         {
8316           if (shCount)
8317             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8318           else
8319             movLeft2Result (left, LSB, result, MSB16, 0);
8320         }
8321       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8322     }
8323
8324   /*  1 <= shCount <= 7 */
8325   else
8326     {
8327       if (size == 1)
8328         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8329       else
8330         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8331     }
8332 }
8333
8334 /*-----------------------------------------------------------------*/
8335 /* shiftLLong - shift left one long from left to result            */
8336 /* offl = LSB or MSB16                                             */
8337 /*-----------------------------------------------------------------*/
8338 static void
8339 shiftLLong (operand * left, operand * result, int offr)
8340 {
8341   char *l;
8342   int size = AOP_SIZE (result);
8343
8344   if (size >= LSB + offr)
8345     {
8346       l = aopGet (left, LSB, FALSE, FALSE);
8347       MOVA (l);
8348       emitcode ("add", "a,acc");
8349       if (sameRegs (AOP (left), AOP (result)) &&
8350           size >= MSB16 + offr && offr != LSB)
8351         emitcode ("xch", "a,%s",
8352                   aopGet (left, LSB + offr, FALSE, FALSE));
8353       else
8354         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8355     }
8356
8357   if (size >= MSB16 + offr)
8358     {
8359       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8360         {
8361           l = aopGet (left, MSB16, FALSE, FALSE);
8362           MOVA (l);
8363         }
8364       emitcode ("rlc", "a");
8365       if (sameRegs (AOP (left), AOP (result)) &&
8366           size >= MSB24 + offr && offr != LSB)
8367         emitcode ("xch", "a,%s",
8368                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8369       else
8370         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8371     }
8372
8373   if (size >= MSB24 + offr)
8374     {
8375       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8376         {
8377           l = aopGet (left, MSB24, FALSE, FALSE);
8378           MOVA (l);
8379         }
8380       emitcode ("rlc", "a");
8381       if (sameRegs (AOP (left), AOP (result)) &&
8382           size >= MSB32 + offr && offr != LSB)
8383         emitcode ("xch", "a,%s",
8384                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8385       else
8386         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8387     }
8388
8389   if (size > MSB32 + offr)
8390     {
8391       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8392         {
8393           l = aopGet (left, MSB32, FALSE, FALSE);
8394           MOVA (l);
8395         }
8396       emitcode ("rlc", "a");
8397       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8398     }
8399   if (offr != LSB)
8400     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8401 }
8402
8403 /*-----------------------------------------------------------------*/
8404 /* genlshFour - shift four byte by a known amount != 0             */
8405 /*-----------------------------------------------------------------*/
8406 static void
8407 genlshFour (operand * result, operand * left, int shCount)
8408 {
8409   int size;
8410
8411   D(emitcode (";     genlshFour",""));
8412
8413   size = AOP_SIZE (result);
8414
8415   /* if shifting more that 3 bytes */
8416   if (shCount >= 24)
8417     {
8418       shCount -= 24;
8419       if (shCount)
8420         /* lowest order of left goes to the highest
8421            order of the destination */
8422         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8423       else
8424         movLeft2Result (left, LSB, result, MSB32, 0);
8425       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8426       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8427       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8428       return;
8429     }
8430
8431   /* more than two bytes */
8432   else if (shCount >= 16)
8433     {
8434       /* lower order two bytes goes to higher order two bytes */
8435       shCount -= 16;
8436       /* if some more remaining */
8437       if (shCount)
8438         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8439       else
8440         {
8441           movLeft2Result (left, MSB16, result, MSB32, 0);
8442           movLeft2Result (left, LSB, result, MSB24, 0);
8443         }
8444       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8445       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8446       return;
8447     }
8448
8449   /* if more than 1 byte */
8450   else if (shCount >= 8)
8451     {
8452       /* lower order three bytes goes to higher order  three bytes */
8453       shCount -= 8;
8454       if (size == 2)
8455         {
8456           if (shCount)
8457             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8458           else
8459             movLeft2Result (left, LSB, result, MSB16, 0);
8460         }
8461       else
8462         {                       /* size = 4 */
8463           if (shCount == 0)
8464             {
8465               movLeft2Result (left, MSB24, result, MSB32, 0);
8466               movLeft2Result (left, MSB16, result, MSB24, 0);
8467               movLeft2Result (left, LSB, result, MSB16, 0);
8468               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8469             }
8470           else if (shCount == 1)
8471             shiftLLong (left, result, MSB16);
8472           else
8473             {
8474               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8475               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8476               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8477               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8478             }
8479         }
8480     }
8481
8482   /* 1 <= shCount <= 7 */
8483   else if (shCount <= 2)
8484     {
8485       shiftLLong (left, result, LSB);
8486       if (shCount == 2)
8487         shiftLLong (result, result, LSB);
8488     }
8489   /* 3 <= shCount <= 7, optimize */
8490   else
8491     {
8492       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8493       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8494       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8495     }
8496 }
8497
8498 /*-----------------------------------------------------------------*/
8499 /* genLeftShiftLiteral - left shifting by known count              */
8500 /*-----------------------------------------------------------------*/
8501 static void
8502 genLeftShiftLiteral (operand * left,
8503                      operand * right,
8504                      operand * result,
8505                      iCode * ic)
8506 {
8507   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8508   int size;
8509
8510   D(emitcode (";     genLeftShiftLiteral",""));
8511
8512   freeAsmop (right, NULL, ic, TRUE);
8513
8514   aopOp (left, ic, FALSE);
8515   aopOp (result, ic, FALSE);
8516
8517   size = getSize (operandType (result));
8518
8519 #if VIEW_SIZE
8520   emitcode ("; shift left ", "result %d, left %d", size,
8521             AOP_SIZE (left));
8522 #endif
8523
8524   /* I suppose that the left size >= result size */
8525   if (shCount == 0)
8526     {
8527       while (size--)
8528         {
8529           movLeft2Result (left, size, result, size, 0);
8530         }
8531     }
8532
8533   else if (shCount >= (size * 8))
8534     while (size--)
8535       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8536   else
8537     {
8538       switch (size)
8539         {
8540         case 1:
8541           genlshOne (result, left, shCount);
8542           break;
8543
8544         case 2:
8545           genlshTwo (result, left, shCount);
8546           break;
8547
8548         case 4:
8549           genlshFour (result, left, shCount);
8550           break;
8551         default:
8552           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8553                   "*** ack! mystery literal shift!\n");
8554           break;
8555         }
8556     }
8557   freeAsmop (left, NULL, ic, TRUE);
8558   freeAsmop (result, NULL, ic, TRUE);
8559 }
8560
8561 /*-----------------------------------------------------------------*/
8562 /* genLeftShift - generates code for left shifting                 */
8563 /*-----------------------------------------------------------------*/
8564 static void
8565 genLeftShift (iCode * ic)
8566 {
8567   operand *left, *right, *result;
8568   int size, offset;
8569   char *l;
8570   symbol *tlbl, *tlbl1;
8571   bool pushedB;
8572
8573   D(emitcode (";     genLeftShift",""));
8574
8575   right = IC_RIGHT (ic);
8576   left = IC_LEFT (ic);
8577   result = IC_RESULT (ic);
8578
8579   aopOp (right, ic, FALSE);
8580
8581   /* if the shift count is known then do it
8582      as efficiently as possible */
8583   if (AOP_TYPE (right) == AOP_LIT)
8584     {
8585       genLeftShiftLiteral (left, right, result, ic);
8586       return;
8587     }
8588
8589   /* shift count is unknown then we have to form
8590      a loop get the loop count in B : Note: we take
8591      only the lower order byte since shifting
8592      more that 32 bits make no sense anyway, ( the
8593      largest size of an object can be only 32 bits ) */
8594
8595   pushedB = pushB ();
8596   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8597   emitcode ("inc", "b");
8598   freeAsmop (right, NULL, ic, TRUE);
8599   aopOp (left, ic, FALSE);
8600   aopOp (result, ic, FALSE);
8601
8602   /* now move the left to the result if they are not the same */
8603   if (!sameRegs (AOP (left), AOP (result)) &&
8604       AOP_SIZE (result) > 1)
8605     {
8606
8607       size = AOP_SIZE (result);
8608       offset = 0;
8609       while (size--)
8610         {
8611           l = aopGet (left, offset, FALSE, TRUE);
8612           if (*l == '@' && (IS_AOP_PREG (result)))
8613             {
8614
8615               emitcode ("mov", "a,%s", l);
8616               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8617             }
8618           else
8619             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8620           offset++;
8621         }
8622     }
8623
8624   tlbl = newiTempLabel (NULL);
8625   size = AOP_SIZE (result);
8626   offset = 0;
8627   tlbl1 = newiTempLabel (NULL);
8628
8629   /* if it is only one byte then */
8630   if (size == 1)
8631     {
8632       symbol *tlbl1 = newiTempLabel (NULL);
8633
8634       l = aopGet (left, 0, FALSE, FALSE);
8635       MOVA (l);
8636       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8637       emitcode ("", "%05d$:", tlbl->key + 100);
8638       emitcode ("add", "a,acc");
8639       emitcode ("", "%05d$:", tlbl1->key + 100);
8640       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8641       popB (pushedB);
8642       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8643       goto release;
8644     }
8645
8646   reAdjustPreg (AOP (result));
8647
8648   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8649   emitcode ("", "%05d$:", tlbl->key + 100);
8650   l = aopGet (result, offset, FALSE, FALSE);
8651   MOVA (l);
8652   emitcode ("add", "a,acc");
8653   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8654   while (--size)
8655     {
8656       l = aopGet (result, offset, FALSE, FALSE);
8657       MOVA (l);
8658       emitcode ("rlc", "a");
8659       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8660     }
8661   reAdjustPreg (AOP (result));
8662
8663   emitcode ("", "%05d$:", tlbl1->key + 100);
8664   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8665   popB (pushedB);
8666 release:
8667   freeAsmop (left, NULL, ic, TRUE);
8668   freeAsmop (result, NULL, ic, TRUE);
8669 }
8670
8671 /*-----------------------------------------------------------------*/
8672 /* genrshOne - right shift a one byte quantity by known count      */
8673 /*-----------------------------------------------------------------*/
8674 static void
8675 genrshOne (operand * result, operand * left,
8676            int shCount, int sign)
8677 {
8678   D(emitcode (";     genrshOne",""));
8679
8680   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8681 }
8682
8683 /*-----------------------------------------------------------------*/
8684 /* genrshTwo - right shift two bytes by known amount != 0          */
8685 /*-----------------------------------------------------------------*/
8686 static void
8687 genrshTwo (operand * result, operand * left,
8688            int shCount, int sign)
8689 {
8690   D(emitcode (";     genrshTwo",""));
8691
8692   /* if shCount >= 8 */
8693   if (shCount >= 8)
8694     {
8695       shCount -= 8;
8696       if (shCount)
8697         shiftR1Left2Result (left, MSB16, result, LSB,
8698                             shCount, sign);
8699       else
8700         movLeft2Result (left, MSB16, result, LSB, sign);
8701       addSign (result, MSB16, sign);
8702     }
8703
8704   /*  1 <= shCount <= 7 */
8705   else
8706     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8707 }
8708
8709 /*-----------------------------------------------------------------*/
8710 /* shiftRLong - shift right one long from left to result           */
8711 /* offl = LSB or MSB16                                             */
8712 /*-----------------------------------------------------------------*/
8713 static void
8714 shiftRLong (operand * left, int offl,
8715             operand * result, int sign)
8716 {
8717   int isSameRegs=sameRegs(AOP(left),AOP(result));
8718
8719   if (isSameRegs && offl>1) {
8720     // we are in big trouble, but this shouldn't happen
8721     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8722   }
8723
8724   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8725
8726   if (offl==MSB16) {
8727     // shift is > 8
8728     if (sign) {
8729       emitcode ("rlc", "a");
8730       emitcode ("subb", "a,acc");
8731       if (isSameRegs)
8732         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8733       else {
8734         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8735         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8736       }
8737     } else {
8738       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8739     }
8740   }
8741
8742   if (!sign) {
8743     emitcode ("clr", "c");
8744   } else {
8745     emitcode ("mov", "c,acc.7");
8746   }
8747
8748   emitcode ("rrc", "a");
8749
8750   if (isSameRegs && offl==MSB16) {
8751     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8752   } else {
8753     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8754     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8755   }
8756
8757   emitcode ("rrc", "a");
8758   if (isSameRegs && offl==1) {
8759     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8760   } else {
8761     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8762     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8763   }
8764   emitcode ("rrc", "a");
8765   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8766
8767   if (offl == LSB)
8768     {
8769       MOVA (aopGet (left, LSB, FALSE, FALSE));
8770       emitcode ("rrc", "a");
8771       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8772     }
8773 }
8774
8775 /*-----------------------------------------------------------------*/
8776 /* genrshFour - shift four byte by a known amount != 0             */
8777 /*-----------------------------------------------------------------*/
8778 static void
8779 genrshFour (operand * result, operand * left,
8780             int shCount, int sign)
8781 {
8782   D(emitcode (";     genrshFour",""));
8783
8784   /* if shifting more that 3 bytes */
8785   if (shCount >= 24)
8786     {
8787       shCount -= 24;
8788       if (shCount)
8789         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8790       else
8791         movLeft2Result (left, MSB32, result, LSB, sign);
8792       addSign (result, MSB16, sign);
8793     }
8794   else if (shCount >= 16)
8795     {
8796       shCount -= 16;
8797       if (shCount)
8798         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8799       else
8800         {
8801           movLeft2Result (left, MSB24, result, LSB, 0);
8802           movLeft2Result (left, MSB32, result, MSB16, sign);
8803         }
8804       addSign (result, MSB24, sign);
8805     }
8806   else if (shCount >= 8)
8807     {
8808       shCount -= 8;
8809       if (shCount == 1)
8810         shiftRLong (left, MSB16, result, sign);
8811       else if (shCount == 0)
8812         {
8813           movLeft2Result (left, MSB16, result, LSB, 0);
8814           movLeft2Result (left, MSB24, result, MSB16, 0);
8815           movLeft2Result (left, MSB32, result, MSB24, sign);
8816           addSign (result, MSB32, sign);
8817         }
8818       else
8819         {
8820           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8821           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8822           /* the last shift is signed */
8823           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8824           addSign (result, MSB32, sign);
8825         }
8826     }
8827   else
8828     {                           /* 1 <= shCount <= 7 */
8829       if (shCount <= 2)
8830         {
8831           shiftRLong (left, LSB, result, sign);
8832           if (shCount == 2)
8833             shiftRLong (result, LSB, result, sign);
8834         }
8835       else
8836         {
8837           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8838           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8839           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8840         }
8841     }
8842 }
8843
8844 /*-----------------------------------------------------------------*/
8845 /* genRightShiftLiteral - right shifting by known count            */
8846 /*-----------------------------------------------------------------*/
8847 static void
8848 genRightShiftLiteral (operand * left,
8849                       operand * right,
8850                       operand * result,
8851                       iCode * ic,
8852                       int sign)
8853 {
8854   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8855   int size;
8856
8857   D(emitcode (";     genRightShiftLiteral",""));
8858
8859   freeAsmop (right, NULL, ic, TRUE);
8860
8861   aopOp (left, ic, FALSE);
8862   aopOp (result, ic, FALSE);
8863
8864 #if VIEW_SIZE
8865   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8866             AOP_SIZE (left));
8867 #endif
8868
8869   size = getDataSize (left);
8870   /* test the LEFT size !!! */
8871
8872   /* I suppose that the left size >= result size */
8873   if (shCount == 0)
8874     {
8875       size = getDataSize (result);
8876       while (size--)
8877         movLeft2Result (left, size, result, size, 0);
8878     }
8879
8880   else if (shCount >= (size * 8))
8881     {
8882       if (sign) {
8883         /* get sign in acc.7 */
8884         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8885       }
8886       addSign (result, LSB, sign);
8887     }
8888   else
8889     {
8890       switch (size)
8891         {
8892         case 1:
8893           genrshOne (result, left, shCount, sign);
8894           break;
8895
8896         case 2:
8897           genrshTwo (result, left, shCount, sign);
8898           break;
8899
8900         case 4:
8901           genrshFour (result, left, shCount, sign);
8902           break;
8903         default:
8904           break;
8905         }
8906     }
8907   freeAsmop (left, NULL, ic, TRUE);
8908   freeAsmop (result, NULL, ic, TRUE);
8909 }
8910
8911 /*-----------------------------------------------------------------*/
8912 /* genSignedRightShift - right shift of signed number              */
8913 /*-----------------------------------------------------------------*/
8914 static void
8915 genSignedRightShift (iCode * ic)
8916 {
8917   operand *right, *left, *result;
8918   int size, offset;
8919   char *l;
8920   symbol *tlbl, *tlbl1;
8921   bool pushedB;
8922
8923   D(emitcode (";     genSignedRightShift",""));
8924
8925   /* we do it the hard way put the shift count in b
8926      and loop thru preserving the sign */
8927
8928   right = IC_RIGHT (ic);
8929   left = IC_LEFT (ic);
8930   result = IC_RESULT (ic);
8931
8932   aopOp (right, ic, FALSE);
8933
8934
8935   if (AOP_TYPE (right) == AOP_LIT)
8936     {
8937       genRightShiftLiteral (left, right, result, ic, 1);
8938       return;
8939     }
8940   /* shift count is unknown then we have to form
8941      a loop get the loop count in B : Note: we take
8942      only the lower order byte since shifting
8943      more that 32 bits make no sense anyway, ( the
8944      largest size of an object can be only 32 bits ) */
8945
8946   pushedB = pushB ();
8947   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8948   emitcode ("inc", "b");
8949   freeAsmop (right, NULL, ic, TRUE);
8950   aopOp (left, ic, FALSE);
8951   aopOp (result, ic, FALSE);
8952
8953   /* now move the left to the result if they are not the
8954      same */
8955   if (!sameRegs (AOP (left), AOP (result)) &&
8956       AOP_SIZE (result) > 1)
8957     {
8958
8959       size = AOP_SIZE (result);
8960       offset = 0;
8961       while (size--)
8962         {
8963           l = aopGet (left, offset, FALSE, TRUE);
8964           if (*l == '@' && IS_AOP_PREG (result))
8965             {
8966
8967               emitcode ("mov", "a,%s", l);
8968               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8969             }
8970           else
8971             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8972           offset++;
8973         }
8974     }
8975
8976   /* mov the highest order bit to OVR */
8977   tlbl = newiTempLabel (NULL);
8978   tlbl1 = newiTempLabel (NULL);
8979
8980   size = AOP_SIZE (result);
8981   offset = size - 1;
8982   MOVA (aopGet (left, offset, FALSE, FALSE));
8983   emitcode ("rlc", "a");
8984   emitcode ("mov", "ov,c");
8985   /* if it is only one byte then */
8986   if (size == 1)
8987     {
8988       l = aopGet (left, 0, FALSE, FALSE);
8989       MOVA (l);
8990       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8991       emitcode ("", "%05d$:", tlbl->key + 100);
8992       emitcode ("mov", "c,ov");
8993       emitcode ("rrc", "a");
8994       emitcode ("", "%05d$:", tlbl1->key + 100);
8995       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8996       popB (pushedB);
8997       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8998       goto release;
8999     }
9000
9001   reAdjustPreg (AOP (result));
9002   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9003   emitcode ("", "%05d$:", tlbl->key + 100);
9004   emitcode ("mov", "c,ov");
9005   while (size--)
9006     {
9007       l = aopGet (result, offset, FALSE, FALSE);
9008       MOVA (l);
9009       emitcode ("rrc", "a");
9010       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9011     }
9012   reAdjustPreg (AOP (result));
9013   emitcode ("", "%05d$:", tlbl1->key + 100);
9014   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9015   popB (pushedB);
9016
9017 release:
9018   freeAsmop (left, NULL, ic, TRUE);
9019   freeAsmop (result, NULL, ic, TRUE);
9020 }
9021
9022 /*-----------------------------------------------------------------*/
9023 /* genRightShift - generate code for right shifting                */
9024 /*-----------------------------------------------------------------*/
9025 static void
9026 genRightShift (iCode * ic)
9027 {
9028   operand *right, *left, *result;
9029   sym_link *letype;
9030   int size, offset;
9031   char *l;
9032   symbol *tlbl, *tlbl1;
9033   bool pushedB;
9034
9035   D(emitcode (";     genRightShift",""));
9036
9037   /* if signed then we do it the hard way preserve the
9038      sign bit moving it inwards */
9039   letype = getSpec (operandType (IC_LEFT (ic)));
9040
9041   if (!SPEC_USIGN (letype))
9042     {
9043       genSignedRightShift (ic);
9044       return;
9045     }
9046
9047   /* signed & unsigned types are treated the same : i.e. the
9048      signed is NOT propagated inwards : quoting from the
9049      ANSI - standard : "for E1 >> E2, is equivalent to division
9050      by 2**E2 if unsigned or if it has a non-negative value,
9051      otherwise the result is implementation defined ", MY definition
9052      is that the sign does not get propagated */
9053
9054   right = IC_RIGHT (ic);
9055   left = IC_LEFT (ic);
9056   result = IC_RESULT (ic);
9057
9058   aopOp (right, ic, FALSE);
9059
9060   /* if the shift count is known then do it
9061      as efficiently as possible */
9062   if (AOP_TYPE (right) == AOP_LIT)
9063     {
9064       genRightShiftLiteral (left, right, result, ic, 0);
9065       return;
9066     }
9067
9068   /* shift count is unknown then we have to form
9069      a loop get the loop count in B : Note: we take
9070      only the lower order byte since shifting
9071      more that 32 bits make no sense anyway, ( the
9072      largest size of an object can be only 32 bits ) */
9073
9074   pushedB = pushB ();
9075   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9076   emitcode ("inc", "b");
9077   freeAsmop (right, NULL, ic, TRUE);
9078   aopOp (left, ic, FALSE);
9079   aopOp (result, ic, FALSE);
9080
9081   /* now move the left to the result if they are not the
9082      same */
9083   if (!sameRegs (AOP (left), AOP (result)) &&
9084       AOP_SIZE (result) > 1)
9085     {
9086
9087       size = AOP_SIZE (result);
9088       offset = 0;
9089       while (size--)
9090         {
9091           l = aopGet (left, offset, FALSE, TRUE);
9092           if (*l == '@' && IS_AOP_PREG (result))
9093             {
9094
9095               emitcode ("mov", "a,%s", l);
9096               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9097             }
9098           else
9099             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9100           offset++;
9101         }
9102     }
9103
9104   tlbl = newiTempLabel (NULL);
9105   tlbl1 = newiTempLabel (NULL);
9106   size = AOP_SIZE (result);
9107   offset = size - 1;
9108
9109   /* if it is only one byte then */
9110   if (size == 1)
9111     {
9112       l = aopGet (left, 0, FALSE, FALSE);
9113       MOVA (l);
9114       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9115       emitcode ("", "%05d$:", tlbl->key + 100);
9116       CLRC;
9117       emitcode ("rrc", "a");
9118       emitcode ("", "%05d$:", tlbl1->key + 100);
9119       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9120       popB (pushedB);
9121       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9122       goto release;
9123     }
9124
9125   reAdjustPreg (AOP (result));
9126   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9127   emitcode ("", "%05d$:", tlbl->key + 100);
9128   CLRC;
9129   while (size--)
9130     {
9131       l = aopGet (result, offset, FALSE, FALSE);
9132       MOVA (l);
9133       emitcode ("rrc", "a");
9134       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9135     }
9136   reAdjustPreg (AOP (result));
9137
9138   emitcode ("", "%05d$:", tlbl1->key + 100);
9139   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9140   popB (pushedB);
9141
9142 release:
9143   freeAsmop (left, NULL, ic, TRUE);
9144   freeAsmop (result, NULL, ic, TRUE);
9145 }
9146
9147 /*-----------------------------------------------------------------*/
9148 /* emitPtrByteGet - emits code to get a byte into A through a      */
9149 /*                  pointer register (R0, R1, or DPTR). The        */
9150 /*                  original value of A can be preserved in B.     */
9151 /*-----------------------------------------------------------------*/
9152 static void
9153 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9154 {
9155   switch (p_type)
9156     {
9157     case IPOINTER:
9158     case POINTER:
9159       if (preserveAinB)
9160         emitcode ("mov", "b,a");
9161       emitcode ("mov", "a,@%s", rname);
9162       break;
9163
9164     case PPOINTER:
9165       if (preserveAinB)
9166         emitcode ("mov", "b,a");
9167       emitcode ("movx", "a,@%s", rname);
9168       break;
9169
9170     case FPOINTER:
9171       if (preserveAinB)
9172         emitcode ("mov", "b,a");
9173       emitcode ("movx", "a,@dptr");
9174       break;
9175
9176     case CPOINTER:
9177       if (preserveAinB)
9178         emitcode ("mov", "b,a");
9179       emitcode ("clr", "a");
9180       emitcode ("movc", "a,@a+dptr");
9181       break;
9182
9183     case GPOINTER:
9184       if (preserveAinB)
9185         {
9186           emitcode ("push", "b");
9187           emitcode ("push", "acc");
9188         }
9189       emitcode ("lcall", "__gptrget");
9190       if (preserveAinB)
9191         emitcode ("pop", "b");
9192       break;
9193     }
9194 }
9195
9196 /*-----------------------------------------------------------------*/
9197 /* emitPtrByteSet - emits code to set a byte from src through a    */
9198 /*                  pointer register (R0, R1, or DPTR).            */
9199 /*-----------------------------------------------------------------*/
9200 static void
9201 emitPtrByteSet (char *rname, int p_type, char *src)
9202 {
9203   switch (p_type)
9204     {
9205     case IPOINTER:
9206     case POINTER:
9207       if (*src=='@')
9208         {
9209           MOVA (src);
9210           emitcode ("mov", "@%s,a", rname);
9211         }
9212       else
9213         emitcode ("mov", "@%s,%s", rname, src);
9214       break;
9215
9216     case PPOINTER:
9217       MOVA (src);
9218       emitcode ("movx", "@%s,a", rname);
9219       break;
9220
9221     case FPOINTER:
9222       MOVA (src);
9223       emitcode ("movx", "@dptr,a");
9224       break;
9225
9226     case GPOINTER:
9227       MOVA (src);
9228       emitcode ("lcall", "__gptrput");
9229       break;
9230     }
9231 }
9232
9233 /*-----------------------------------------------------------------*/
9234 /* genUnpackBits - generates code for unpacking bits               */
9235 /*-----------------------------------------------------------------*/
9236 static void
9237 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9238 {
9239   int offset = 0;       /* result byte offset */
9240   int rsize;            /* result size */
9241   int rlen = 0;         /* remaining bitfield length */
9242   sym_link *etype;      /* bitfield type information */
9243   int blen;             /* bitfield length */
9244   int bstr;             /* bitfield starting bit within byte */
9245   char buffer[10];
9246
9247   D(emitcode (";     genUnpackBits",""));
9248
9249   etype = getSpec (operandType (result));
9250   rsize = getSize (operandType (result));
9251   blen = SPEC_BLEN (etype);
9252   bstr = SPEC_BSTR (etype);
9253
9254   if (ifx && blen <= 8)
9255     {
9256       emitPtrByteGet (rname, ptype, FALSE);
9257       if (blen == 1)
9258         {
9259           SNPRINTF (buffer, sizeof(buffer),
9260                     "acc.%d", bstr);
9261           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9262         }
9263       else
9264         {
9265           if (blen < 8)
9266             emitcode ("anl", "a,#0x%02x",
9267                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9268           genIfxJump (ifx, "a", NULL, NULL, NULL);
9269         }
9270       return;
9271     }
9272   wassert (!ifx);
9273
9274   /* If the bitfield length is less than a byte */
9275   if (blen < 8)
9276     {
9277       emitPtrByteGet (rname, ptype, FALSE);
9278       AccRsh (bstr);
9279       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9280       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9281       goto finish;
9282     }
9283
9284   /* Bit field did not fit in a byte. Copy all
9285      but the partial byte at the end.  */
9286   for (rlen=blen;rlen>=8;rlen-=8)
9287     {
9288       emitPtrByteGet (rname, ptype, FALSE);
9289       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9290       if (rlen>8)
9291         emitcode ("inc", "%s", rname);
9292     }
9293
9294   /* Handle the partial byte at the end */
9295   if (rlen)
9296     {
9297       emitPtrByteGet (rname, ptype, FALSE);
9298       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9299       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9300     }
9301
9302 finish:
9303   if (offset < rsize)
9304     {
9305       rsize -= offset;
9306       while (rsize--)
9307         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
9308     }
9309 }
9310
9311
9312 /*-----------------------------------------------------------------*/
9313 /* genDataPointerGet - generates code when ptr offset is known     */
9314 /*-----------------------------------------------------------------*/
9315 static void
9316 genDataPointerGet (operand * left,
9317                    operand * result,
9318                    iCode * ic)
9319 {
9320   char *l;
9321   char buffer[256];
9322   int size, offset = 0;
9323
9324   D(emitcode (";     genDataPointerGet",""));
9325
9326   aopOp (result, ic, TRUE);
9327
9328   /* get the string representation of the name */
9329   l = aopGet (left, 0, FALSE, TRUE);
9330   size = AOP_SIZE (result);
9331   while (size--)
9332     {
9333       if (offset)
9334         sprintf (buffer, "(%s + %d)", l + 1, offset);
9335       else
9336         sprintf (buffer, "%s", l + 1);
9337       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9338     }
9339
9340   freeAsmop (left, NULL, ic, TRUE);
9341   freeAsmop (result, NULL, ic, TRUE);
9342 }
9343
9344 /*-----------------------------------------------------------------*/
9345 /* genNearPointerGet - emitcode for near pointer fetch             */
9346 /*-----------------------------------------------------------------*/
9347 static void
9348 genNearPointerGet (operand * left,
9349                    operand * result,
9350                    iCode * ic,
9351                    iCode * pi,
9352                    iCode * ifx)
9353 {
9354   asmop *aop = NULL;
9355   regs *preg = NULL;
9356   char *rname;
9357   sym_link *rtype, *retype;
9358   sym_link *ltype = operandType (left);
9359   char buffer[80];
9360
9361   D(emitcode (";     genNearPointerGet",""));
9362
9363   rtype = operandType (result);
9364   retype = getSpec (rtype);
9365
9366   aopOp (left, ic, FALSE);
9367
9368   /* if left is rematerialisable and
9369      result is not bitfield variable type and
9370      the left is pointer to data space i.e
9371      lower 128 bytes of space */
9372   if (AOP_TYPE (left) == AOP_IMMD &&
9373       !IS_BITFIELD (retype) &&
9374       DCL_TYPE (ltype) == POINTER)
9375     {
9376       genDataPointerGet (left, result, ic);
9377       return;
9378     }
9379
9380  /* if the value is already in a pointer register
9381      then don't need anything more */
9382   if (!AOP_INPREG (AOP (left)))
9383     {
9384       if (IS_AOP_PREG (left))
9385         {
9386           // Aha, it is a pointer, just in disguise.
9387           rname = aopGet (left, 0, FALSE, FALSE);
9388           if (*rname != '@')
9389             {
9390               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9391                       __FILE__, __LINE__);
9392             }
9393           else
9394             {
9395               // Expected case.
9396               emitcode ("mov", "a%s,%s", rname + 1, rname);
9397               rname++;  // skip the '@'.
9398             }
9399         }
9400       else
9401         {
9402           /* otherwise get a free pointer register */
9403           aop = newAsmop (0);
9404           preg = getFreePtr (ic, &aop, FALSE);
9405           emitcode ("mov", "%s,%s",
9406                     preg->name,
9407                     aopGet (left, 0, FALSE, TRUE));
9408           rname = preg->name;
9409         }
9410     }
9411   else
9412     rname = aopGet (left, 0, FALSE, FALSE);
9413
9414   //aopOp (result, ic, FALSE);
9415   aopOp (result, ic, result?TRUE:FALSE);
9416
9417   /* if bitfield then unpack the bits */
9418   if (IS_BITFIELD (retype))
9419     genUnpackBits (result, rname, POINTER, ifx);
9420   else
9421     {
9422       /* we have can just get the values */
9423       int size = AOP_SIZE (result);
9424       int offset = 0;
9425
9426       while (size--)
9427         {
9428           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9429             {
9430
9431               emitcode ("mov", "a,@%s", rname);
9432               if (!ifx)
9433               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9434             }
9435           else
9436             {
9437               sprintf (buffer, "@%s", rname);
9438               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9439             }
9440           offset++;
9441           if (size || pi)
9442             emitcode ("inc", "%s", rname);
9443         }
9444     }
9445
9446   /* now some housekeeping stuff */
9447   if (aop)       /* we had to allocate for this iCode */
9448     {
9449       if (pi) { /* post increment present */
9450         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9451       }
9452       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9453     }
9454   else
9455     {
9456       /* we did not allocate which means left
9457          already in a pointer register, then
9458          if size > 0 && this could be used again
9459          we have to point it back to where it
9460          belongs */
9461       if ((AOP_SIZE (result) > 1 &&
9462            !OP_SYMBOL (left)->remat &&
9463            (OP_SYMBOL (left)->liveTo > ic->seq ||
9464             ic->depth)) &&
9465           !pi)
9466         {
9467           int size = AOP_SIZE (result) - 1;
9468           while (size--)
9469             emitcode ("dec", "%s", rname);
9470         }
9471     }
9472
9473   if (ifx && !ifx->generated)
9474     {
9475       genIfxJump (ifx, "a", left, NULL, result);
9476     }
9477
9478   /* done */
9479   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9480   freeAsmop (left, NULL, ic, TRUE);
9481   if (pi) pi->generated = 1;
9482 }
9483
9484 /*-----------------------------------------------------------------*/
9485 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9486 /*-----------------------------------------------------------------*/
9487 static void
9488 genPagedPointerGet (operand * left,
9489                     operand * result,
9490                     iCode * ic,
9491                     iCode *pi,
9492                     iCode *ifx)
9493 {
9494   asmop *aop = NULL;
9495   regs *preg = NULL;
9496   char *rname;
9497   sym_link *rtype, *retype;
9498
9499   D(emitcode (";     genPagedPointerGet",""));
9500
9501   rtype = operandType (result);
9502   retype = getSpec (rtype);
9503
9504   aopOp (left, ic, FALSE);
9505
9506   /* if the value is already in a pointer register
9507      then don't need anything more */
9508   if (!AOP_INPREG (AOP (left)))
9509     {
9510       /* otherwise get a free pointer register */
9511       aop = newAsmop (0);
9512       preg = getFreePtr (ic, &aop, FALSE);
9513       emitcode ("mov", "%s,%s",
9514                 preg->name,
9515                 aopGet (left, 0, FALSE, TRUE));
9516       rname = preg->name;
9517     }
9518   else
9519     rname = aopGet (left, 0, FALSE, FALSE);
9520
9521   aopOp (result, ic, FALSE);
9522
9523   /* if bitfield then unpack the bits */
9524   if (IS_BITFIELD (retype))
9525     genUnpackBits (result, rname, PPOINTER, ifx);
9526   else
9527     {
9528       /* we have can just get the values */
9529       int size = AOP_SIZE (result);
9530       int offset = 0;
9531
9532       while (size--)
9533         {
9534
9535           emitcode ("movx", "a,@%s", rname);
9536           if (!ifx)
9537           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9538
9539           offset++;
9540
9541           if (size || pi)
9542             emitcode ("inc", "%s", rname);
9543         }
9544     }
9545
9546   /* now some housekeeping stuff */
9547   if (aop) /* we had to allocate for this iCode */
9548     {
9549       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9550       freeAsmop (NULL, aop, ic, TRUE);
9551     }
9552   else
9553     {
9554       /* we did not allocate which means left
9555          already in a pointer register, then
9556          if size > 0 && this could be used again
9557          we have to point it back to where it
9558          belongs */
9559       if ((AOP_SIZE (result) > 1 &&
9560            !OP_SYMBOL (left)->remat &&
9561            (OP_SYMBOL (left)->liveTo > ic->seq ||
9562             ic->depth)) &&
9563           !pi)
9564         {
9565           int size = AOP_SIZE (result) - 1;
9566           while (size--)
9567             emitcode ("dec", "%s", rname);
9568         }
9569     }
9570
9571   if (ifx && !ifx->generated)
9572     {
9573       genIfxJump (ifx, "a", left, NULL, result);
9574     }
9575
9576   /* done */
9577   freeAsmop (left, NULL, ic, TRUE);
9578   freeAsmop (result, NULL, ic, TRUE);
9579   if (pi) pi->generated = 1;
9580
9581 }
9582
9583 /*--------------------------------------------------------------------*/
9584 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9585 /*--------------------------------------------------------------------*/
9586 static void
9587 loadDptrFromOperand (operand *op, bool loadBToo)
9588 {
9589   if (AOP_TYPE (op) != AOP_STR)
9590     {
9591       /* if this is rematerializable */
9592       if (AOP_TYPE (op) == AOP_IMMD)
9593         {
9594           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9595           if (loadBToo)
9596             {
9597               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9598                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9599               else
9600                 {
9601                   wassertl(FALSE, "need pointerCode");
9602                   emitcode ("", "; mov b,???");
9603                   /* genPointerGet and genPointerSet originally did different
9604                   ** things for this case. Both seem wrong.
9605                   ** from genPointerGet:
9606                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9607                   ** from genPointerSet:
9608                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9609                   */
9610                 }
9611             }
9612         }
9613       else if (AOP_TYPE (op) == AOP_DPTR)
9614         {
9615           if (loadBToo)
9616             {
9617               MOVA (aopGet (op, 0, FALSE, FALSE));
9618               emitcode ("push", "acc");
9619               MOVA (aopGet (op, 1, FALSE, FALSE));
9620               emitcode ("push", "acc");
9621               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9622               emitcode ("pop", "dph");
9623               emitcode ("pop", "dpl");
9624             }
9625           else
9626             {
9627               MOVA (aopGet (op, 0, FALSE, FALSE));
9628               emitcode ("push", "acc");
9629               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9630               emitcode ("pop", "dpl");
9631             }
9632         }
9633       else
9634         {                       /* we need to get it byte by byte */
9635           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9636           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9637           if (loadBToo)
9638             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9639         }
9640     }
9641 }
9642
9643 /*-----------------------------------------------------------------*/
9644 /* genFarPointerGet - gget value from far space                    */
9645 /*-----------------------------------------------------------------*/
9646 static void
9647 genFarPointerGet (operand * left,
9648                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9649 {
9650   int size, offset;
9651   sym_link *retype = getSpec (operandType (result));
9652
9653   D(emitcode (";     genFarPointerGet",""));
9654
9655   aopOp (left, ic, FALSE);
9656   loadDptrFromOperand (left, FALSE);
9657
9658   /* so dptr now contains the address */
9659   aopOp (result, ic, FALSE);
9660
9661   /* if bit then unpack */
9662   if (IS_BITFIELD (retype))
9663     genUnpackBits (result, "dptr", FPOINTER, ifx);
9664   else
9665     {
9666       size = AOP_SIZE (result);
9667       offset = 0;
9668
9669       while (size--)
9670         {
9671           emitcode ("movx", "a,@dptr");
9672           if (!ifx)
9673             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9674           if (size || pi)
9675             emitcode ("inc", "dptr");
9676         }
9677     }
9678
9679   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9680     {
9681     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9682     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9683     pi->generated = 1;
9684   }
9685
9686   if (ifx && !ifx->generated)
9687     {
9688       genIfxJump (ifx, "a", left, NULL, result);
9689     }
9690
9691   freeAsmop (left, NULL, ic, TRUE);
9692   freeAsmop (result, NULL, ic, TRUE);
9693 }
9694
9695 /*-----------------------------------------------------------------*/
9696 /* genCodePointerGet - gget value from code space                  */
9697 /*-----------------------------------------------------------------*/
9698 static void
9699 genCodePointerGet (operand * left,
9700                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9701 {
9702   int size, offset;
9703   sym_link *retype = getSpec (operandType (result));
9704
9705   D(emitcode (";     genCodePointerGet",""));
9706
9707   aopOp (left, ic, FALSE);
9708   loadDptrFromOperand (left, FALSE);
9709
9710   /* so dptr now contains the address */
9711   aopOp (result, ic, FALSE);
9712
9713   /* if bit then unpack */
9714   if (IS_BITFIELD (retype))
9715     genUnpackBits (result, "dptr", CPOINTER, ifx);
9716   else
9717     {
9718       size = AOP_SIZE (result);
9719       offset = 0;
9720
9721       while (size--)
9722         {
9723           if (pi)
9724             {
9725               emitcode ("clr", "a");
9726               emitcode ("movc", "a,@a+dptr");
9727               if (!ifx)
9728               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9729               emitcode ("inc", "dptr");
9730             }
9731           else
9732             {
9733               emitcode ("mov", "a,#0x%02x", offset);
9734               emitcode ("movc", "a,@a+dptr");
9735               if (!ifx)
9736               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9737             }
9738         }
9739     }
9740
9741   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9742     {
9743     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9744     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9745     pi->generated = 1;
9746   }
9747
9748   if (ifx && !ifx->generated)
9749     {
9750       genIfxJump (ifx, "a", left, NULL, result);
9751     }
9752
9753   freeAsmop (left, NULL, ic, TRUE);
9754   freeAsmop (result, NULL, ic, TRUE);
9755 }
9756
9757 /*-----------------------------------------------------------------*/
9758 /* genGenPointerGet - gget value from generic pointer space        */
9759 /*-----------------------------------------------------------------*/
9760 static void
9761 genGenPointerGet (operand * left,
9762                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9763 {
9764   int size, offset;
9765   sym_link *retype = getSpec (operandType (result));
9766
9767   D(emitcode (";     genGenPointerGet",""));
9768
9769   aopOp (left, ic, FALSE);
9770   loadDptrFromOperand (left, TRUE);
9771
9772   /* so dptr know contains the address */
9773   aopOp (result, ic, FALSE);
9774
9775   /* if bit then unpack */
9776   if (IS_BITFIELD (retype))
9777     genUnpackBits (result, "dptr", GPOINTER, ifx);
9778   else
9779     {
9780       size = AOP_SIZE (result);
9781       offset = 0;
9782
9783       while (size--)
9784         {
9785           emitcode ("lcall", "__gptrget");
9786           if (!ifx)
9787           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9788           if (size || pi)
9789             emitcode ("inc", "dptr");
9790         }
9791     }
9792
9793   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9794     {
9795     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9796     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9797     pi->generated = 1;
9798   }
9799
9800   if (ifx && !ifx->generated)
9801     {
9802       genIfxJump (ifx, "a", left, NULL, result);
9803     }
9804
9805
9806   freeAsmop (left, NULL, ic, TRUE);
9807   freeAsmop (result, NULL, ic, TRUE);
9808 }
9809
9810 /*-----------------------------------------------------------------*/
9811 /* genPointerGet - generate code for pointer get                   */
9812 /*-----------------------------------------------------------------*/
9813 static void
9814 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9815 {
9816   operand *left, *result;
9817   sym_link *type, *etype;
9818   int p_type;
9819
9820   D(emitcode (";     genPointerGet",""));
9821
9822   left = IC_LEFT (ic);
9823   result = IC_RESULT (ic);
9824
9825   if (getSize (operandType (result))>1)
9826     ifx = NULL;
9827
9828   /* depending on the type of pointer we need to
9829      move it to the correct pointer register */
9830   type = operandType (left);
9831   etype = getSpec (type);
9832   /* if left is of type of pointer then it is simple */
9833   if (IS_PTR (type) && !IS_FUNC (type->next))
9834     p_type = DCL_TYPE (type);
9835   else
9836     {
9837       /* we have to go by the storage class */
9838       p_type = PTR_TYPE (SPEC_OCLS (etype));
9839     }
9840
9841   /* special case when cast remat */
9842   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9843       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9844           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9845           type = operandType (left);
9846           p_type = DCL_TYPE (type);
9847   }
9848   /* now that we have the pointer type we assign
9849      the pointer values */
9850   switch (p_type)
9851     {
9852
9853     case POINTER:
9854     case IPOINTER:
9855       genNearPointerGet (left, result, ic, pi, ifx);
9856       break;
9857
9858     case PPOINTER:
9859       genPagedPointerGet (left, result, ic, pi, ifx);
9860       break;
9861
9862     case FPOINTER:
9863       genFarPointerGet (left, result, ic, pi, ifx);
9864       break;
9865
9866     case CPOINTER:
9867       genCodePointerGet (left, result, ic, pi, ifx);
9868       break;
9869
9870     case GPOINTER:
9871       genGenPointerGet (left, result, ic, pi, ifx);
9872       break;
9873     }
9874
9875 }
9876
9877
9878
9879 /*-----------------------------------------------------------------*/
9880 /* genPackBits - generates code for packed bit storage             */
9881 /*-----------------------------------------------------------------*/
9882 static void
9883 genPackBits (sym_link * etype,
9884              operand * right,
9885              char *rname, int p_type)
9886 {
9887   int offset = 0;       /* source byte offset */
9888   int rlen = 0;         /* remaining bitfield length */
9889   int blen;             /* bitfield length */
9890   int bstr;             /* bitfield starting bit within byte */
9891   int litval;           /* source literal value (if AOP_LIT) */
9892   unsigned char mask;   /* bitmask within current byte */
9893
9894   D(emitcode (";     genPackBits",""));
9895
9896   blen = SPEC_BLEN (etype);
9897   bstr = SPEC_BSTR (etype);
9898
9899   /* If the bitfield length is less than a byte */
9900   if (blen < 8)
9901     {
9902       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9903               (unsigned char) (0xFF >> (8 - bstr)));
9904
9905       if (AOP_TYPE (right) == AOP_LIT)
9906         {
9907           /* Case with a bitfield length <8 and literal source
9908           */
9909           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9910           litval <<= bstr;
9911           litval &= (~mask) & 0xff;
9912           emitPtrByteGet (rname, p_type, FALSE);
9913           if ((mask|litval)!=0xff)
9914             emitcode ("anl","a,#0x%02x", mask);
9915           if (litval)
9916             emitcode ("orl","a,#0x%02x", litval);
9917         }
9918       else
9919         {
9920           if ((blen==1) && (p_type!=GPOINTER))
9921             {
9922               /* Case with a bitfield length == 1 and no generic pointer
9923               */
9924               if (AOP_TYPE (right) == AOP_CRY)
9925                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9926               else
9927                 {
9928                   MOVA (aopGet (right, 0, FALSE, FALSE));
9929                   emitcode ("rrc","a");
9930                 }
9931               emitPtrByteGet (rname, p_type, FALSE);
9932               emitcode ("mov","acc.%d,c",bstr);
9933             }
9934           else
9935             {
9936               bool pushedB;
9937               /* Case with a bitfield length < 8 and arbitrary source
9938               */
9939               MOVA (aopGet (right, 0, FALSE, FALSE));
9940               /* shift and mask source value */
9941               AccLsh (bstr);
9942               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9943
9944               pushedB = pushB ();
9945               /* transfer A to B and get next byte */
9946               emitPtrByteGet (rname, p_type, TRUE);
9947
9948               emitcode ("anl", "a,#0x%02x", mask);
9949               emitcode ("orl", "a,b");
9950               if (p_type == GPOINTER)
9951                 emitcode ("pop", "b");
9952
9953               popB (pushedB);
9954            }
9955         }
9956
9957       emitPtrByteSet (rname, p_type, "a");
9958       return;
9959     }
9960
9961   /* Bit length is greater than 7 bits. In this case, copy  */
9962   /* all except the partial byte at the end                 */
9963   for (rlen=blen;rlen>=8;rlen-=8)
9964     {
9965       emitPtrByteSet (rname, p_type,
9966                       aopGet (right, offset++, FALSE, TRUE) );
9967       if (rlen>8)
9968         emitcode ("inc", "%s", rname);
9969     }
9970
9971   /* If there was a partial byte at the end */
9972   if (rlen)
9973     {
9974       mask = (((unsigned char) -1 << rlen) & 0xff);
9975
9976       if (AOP_TYPE (right) == AOP_LIT)
9977         {
9978           /* Case with partial byte and literal source
9979           */
9980           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9981           litval >>= (blen-rlen);
9982           litval &= (~mask) & 0xff;
9983           emitPtrByteGet (rname, p_type, FALSE);
9984           if ((mask|litval)!=0xff)
9985             emitcode ("anl","a,#0x%02x", mask);
9986           if (litval)
9987             emitcode ("orl","a,#0x%02x", litval);
9988         }
9989       else
9990         {
9991           bool pushedB;
9992           /* Case with partial byte and arbitrary source
9993           */
9994           MOVA (aopGet (right, offset++, FALSE, FALSE));
9995           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9996
9997           pushedB = pushB ();
9998           /* transfer A to B and get next byte */
9999           emitPtrByteGet (rname, p_type, TRUE);
10000
10001           emitcode ("anl", "a,#0x%02x", mask);
10002           emitcode ("orl", "a,b");
10003           if (p_type == GPOINTER)
10004             emitcode ("pop", "b");
10005
10006           popB (pushedB);
10007         }
10008       emitPtrByteSet (rname, p_type, "a");
10009     }
10010
10011 }
10012
10013
10014 /*-----------------------------------------------------------------*/
10015 /* genDataPointerSet - remat pointer to data space                 */
10016 /*-----------------------------------------------------------------*/
10017 static void
10018 genDataPointerSet (operand * right,
10019                    operand * result,
10020                    iCode * ic)
10021 {
10022   int size, offset = 0;
10023   char *l, buffer[256];
10024
10025   D(emitcode (";     genDataPointerSet",""));
10026
10027   aopOp (right, ic, FALSE);
10028
10029   l = aopGet (result, 0, FALSE, TRUE);
10030   size = AOP_SIZE (right);
10031   while (size--)
10032     {
10033       if (offset)
10034         sprintf (buffer, "(%s + %d)", l + 1, offset);
10035       else
10036         sprintf (buffer, "%s", l + 1);
10037       emitcode ("mov", "%s,%s", buffer,
10038                 aopGet (right, offset++, FALSE, FALSE));
10039     }
10040
10041   freeAsmop (right, NULL, ic, TRUE);
10042   freeAsmop (result, NULL, ic, TRUE);
10043 }
10044
10045 /*-----------------------------------------------------------------*/
10046 /* genNearPointerSet - emitcode for near pointer put                */
10047 /*-----------------------------------------------------------------*/
10048 static void
10049 genNearPointerSet (operand * right,
10050                    operand * result,
10051                    iCode * ic,
10052                    iCode * pi)
10053 {
10054   asmop *aop = NULL;
10055   regs *preg = NULL;
10056   char *rname, *l;
10057   sym_link *retype, *letype;
10058   sym_link *ptype = operandType (result);
10059
10060   D(emitcode (";     genNearPointerSet",""));
10061
10062   retype = getSpec (operandType (right));
10063   letype = getSpec (ptype);
10064   aopOp (result, ic, FALSE);
10065
10066   /* if the result is rematerializable &
10067      in data space & not a bit variable */
10068   if (AOP_TYPE (result) == AOP_IMMD &&
10069       DCL_TYPE (ptype) == POINTER &&
10070       !IS_BITVAR (retype) &&
10071       !IS_BITVAR (letype))
10072     {
10073       genDataPointerSet (right, result, ic);
10074       return;
10075     }
10076
10077   /* if the value is already in a pointer register
10078      then don't need anything more */
10079   if (!AOP_INPREG (AOP (result)))
10080     {
10081         if (
10082             //AOP_TYPE (result) == AOP_STK
10083             IS_AOP_PREG(result)
10084             )
10085         {
10086             // Aha, it is a pointer, just in disguise.
10087             rname = aopGet (result, 0, FALSE, FALSE);
10088             if (*rname != '@')
10089             {
10090                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10091                         __FILE__, __LINE__);
10092             }
10093             else
10094             {
10095                 // Expected case.
10096                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10097                 rname++;  // skip the '@'.
10098             }
10099         }
10100         else
10101         {
10102             /* otherwise get a free pointer register */
10103             aop = newAsmop (0);
10104             preg = getFreePtr (ic, &aop, FALSE);
10105             emitcode ("mov", "%s,%s",
10106                       preg->name,
10107                       aopGet (result, 0, FALSE, TRUE));
10108             rname = preg->name;
10109         }
10110     }
10111     else
10112     {
10113         rname = aopGet (result, 0, FALSE, FALSE);
10114     }
10115
10116   aopOp (right, ic, FALSE);
10117
10118   /* if bitfield then unpack the bits */
10119   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10120     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10121   else
10122     {
10123       /* we have can just get the values */
10124       int size = AOP_SIZE (right);
10125       int offset = 0;
10126
10127       while (size--)
10128         {
10129           l = aopGet (right, offset, FALSE, TRUE);
10130           if (*l == '@')
10131             {
10132               MOVA (l);
10133               emitcode ("mov", "@%s,a", rname);
10134             }
10135           else
10136             emitcode ("mov", "@%s,%s", rname, l);
10137           if (size || pi)
10138             emitcode ("inc", "%s", rname);
10139           offset++;
10140         }
10141     }
10142
10143   /* now some housekeeping stuff */
10144   if (aop) /* we had to allocate for this iCode */
10145     {
10146       if (pi)
10147         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10148       freeAsmop (NULL, aop, ic, TRUE);
10149     }
10150   else
10151     {
10152       /* we did not allocate which means left
10153          already in a pointer register, then
10154          if size > 0 && this could be used again
10155          we have to point it back to where it
10156          belongs */
10157       if ((AOP_SIZE (right) > 1 &&
10158            !OP_SYMBOL (result)->remat &&
10159            (OP_SYMBOL (result)->liveTo > ic->seq ||
10160             ic->depth)) &&
10161           !pi)
10162         {
10163           int size = AOP_SIZE (right) - 1;
10164           while (size--)
10165             emitcode ("dec", "%s", rname);
10166         }
10167     }
10168
10169   /* done */
10170   if (pi) pi->generated = 1;
10171   freeAsmop (result, NULL, ic, TRUE);
10172   freeAsmop (right, NULL, ic, TRUE);
10173 }
10174
10175 /*-----------------------------------------------------------------*/
10176 /* genPagedPointerSet - emitcode for Paged pointer put             */
10177 /*-----------------------------------------------------------------*/
10178 static void
10179 genPagedPointerSet (operand * right,
10180                     operand * result,
10181                     iCode * ic,
10182                     iCode * pi)
10183 {
10184   asmop *aop = NULL;
10185   regs *preg = NULL;
10186   char *rname, *l;
10187   sym_link *retype, *letype;
10188
10189   D(emitcode (";     genPagedPointerSet",""));
10190
10191   retype = getSpec (operandType (right));
10192   letype = getSpec (operandType (result));
10193
10194   aopOp (result, ic, FALSE);
10195
10196   /* if the value is already in a pointer register
10197      then don't need anything more */
10198   if (!AOP_INPREG (AOP (result)))
10199     {
10200       /* otherwise get a free pointer register */
10201       aop = newAsmop (0);
10202       preg = getFreePtr (ic, &aop, FALSE);
10203       emitcode ("mov", "%s,%s",
10204                 preg->name,
10205                 aopGet (result, 0, FALSE, TRUE));
10206       rname = preg->name;
10207     }
10208   else
10209     rname = aopGet (result, 0, FALSE, FALSE);
10210
10211   aopOp (right, ic, FALSE);
10212
10213   /* if bitfield then unpack the bits */
10214   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10215     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10216   else
10217     {
10218       /* we have can just get the values */
10219       int size = AOP_SIZE (right);
10220       int offset = 0;
10221
10222       while (size--)
10223         {
10224           l = aopGet (right, offset, FALSE, TRUE);
10225
10226           MOVA (l);
10227           emitcode ("movx", "@%s,a", rname);
10228
10229           if (size || pi)
10230             emitcode ("inc", "%s", rname);
10231
10232           offset++;
10233         }
10234     }
10235
10236   /* now some housekeeping stuff */
10237   if (aop) /* we had to allocate for this iCode */
10238     {
10239       if (pi)
10240         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10241       freeAsmop (NULL, aop, ic, TRUE);
10242     }
10243   else
10244     {
10245       /* we did not allocate which means left
10246          already in a pointer register, then
10247          if size > 0 && this could be used again
10248          we have to point it back to where it
10249          belongs */
10250       if (AOP_SIZE (right) > 1 &&
10251           !OP_SYMBOL (result)->remat &&
10252           (OP_SYMBOL (result)->liveTo > ic->seq ||
10253            ic->depth))
10254         {
10255           int size = AOP_SIZE (right) - 1;
10256           while (size--)
10257             emitcode ("dec", "%s", rname);
10258         }
10259     }
10260
10261   /* done */
10262   if (pi) pi->generated = 1;
10263   freeAsmop (result, NULL, ic, TRUE);
10264   freeAsmop (right, NULL, ic, TRUE);
10265
10266
10267 }
10268
10269 /*-----------------------------------------------------------------*/
10270 /* genFarPointerSet - set value from far space                     */
10271 /*-----------------------------------------------------------------*/
10272 static void
10273 genFarPointerSet (operand * right,
10274                   operand * result, iCode * ic, iCode * pi)
10275 {
10276   int size, offset;
10277   sym_link *retype = getSpec (operandType (right));
10278   sym_link *letype = getSpec (operandType (result));
10279
10280   D(emitcode (";     genFarPointerSet",""));
10281
10282   aopOp (result, ic, FALSE);
10283   loadDptrFromOperand (result, FALSE);
10284
10285   /* so dptr know contains the address */
10286   aopOp (right, ic, FALSE);
10287
10288   /* if bit then unpack */
10289   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10290     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10291   else
10292     {
10293       size = AOP_SIZE (right);
10294       offset = 0;
10295
10296       while (size--)
10297         {
10298           char *l = aopGet (right, offset++, FALSE, FALSE);
10299           MOVA (l);
10300           emitcode ("movx", "@dptr,a");
10301           if (size || pi)
10302             emitcode ("inc", "dptr");
10303         }
10304     }
10305   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10306     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10307     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10308     pi->generated=1;
10309   }
10310   freeAsmop (result, NULL, ic, TRUE);
10311   freeAsmop (right, NULL, ic, TRUE);
10312 }
10313
10314 /*-----------------------------------------------------------------*/
10315 /* genGenPointerSet - set value from generic pointer space         */
10316 /*-----------------------------------------------------------------*/
10317 static void
10318 genGenPointerSet (operand * right,
10319                   operand * result, iCode * ic, iCode * pi)
10320 {
10321   int size, offset;
10322   sym_link *retype = getSpec (operandType (right));
10323   sym_link *letype = getSpec (operandType (result));
10324
10325   D(emitcode (";     genGenPointerSet",""));
10326
10327   aopOp (result, ic, FALSE);
10328   loadDptrFromOperand (result, TRUE);
10329
10330   /* so dptr know contains the address */
10331   aopOp (right, ic, FALSE);
10332
10333   /* if bit then unpack */
10334   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10335     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10336   else
10337     {
10338       size = AOP_SIZE (right);
10339       offset = 0;
10340
10341       while (size--)
10342         {
10343           char *l = aopGet (right, offset++, FALSE, FALSE);
10344           MOVA (l);
10345           emitcode ("lcall", "__gptrput");
10346           if (size || pi)
10347             emitcode ("inc", "dptr");
10348         }
10349     }
10350
10351   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10352     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10353     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10354     pi->generated=1;
10355   }
10356   freeAsmop (result, NULL, ic, TRUE);
10357   freeAsmop (right, NULL, ic, TRUE);
10358 }
10359
10360 /*-----------------------------------------------------------------*/
10361 /* genPointerSet - stores the value into a pointer location        */
10362 /*-----------------------------------------------------------------*/
10363 static void
10364 genPointerSet (iCode * ic, iCode *pi)
10365 {
10366   operand *right, *result;
10367   sym_link *type, *etype;
10368   int p_type;
10369
10370   D(emitcode (";     genPointerSet",""));
10371
10372   right = IC_RIGHT (ic);
10373   result = IC_RESULT (ic);
10374
10375   /* depending on the type of pointer we need to
10376      move it to the correct pointer register */
10377   type = operandType (result);
10378   etype = getSpec (type);
10379   /* if left is of type of pointer then it is simple */
10380   if (IS_PTR (type) && !IS_FUNC (type->next))
10381     {
10382       p_type = DCL_TYPE (type);
10383     }
10384   else
10385     {
10386       /* we have to go by the storage class */
10387       p_type = PTR_TYPE (SPEC_OCLS (etype));
10388     }
10389
10390   /* special case when cast remat */
10391   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10392       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10393           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10394           type = operandType (result);
10395           p_type = DCL_TYPE (type);
10396   }
10397   /* now that we have the pointer type we assign
10398      the pointer values */
10399   switch (p_type)
10400     {
10401
10402     case POINTER:
10403     case IPOINTER:
10404       genNearPointerSet (right, result, ic, pi);
10405       break;
10406
10407     case PPOINTER:
10408       genPagedPointerSet (right, result, ic, pi);
10409       break;
10410
10411     case FPOINTER:
10412       genFarPointerSet (right, result, ic, pi);
10413       break;
10414
10415     case GPOINTER:
10416       genGenPointerSet (right, result, ic, pi);
10417       break;
10418
10419     default:
10420       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10421               "genPointerSet: illegal pointer type");
10422     }
10423
10424 }
10425
10426 /*-----------------------------------------------------------------*/
10427 /* genIfx - generate code for Ifx statement                        */
10428 /*-----------------------------------------------------------------*/
10429 static void
10430 genIfx (iCode * ic, iCode * popIc)
10431 {
10432   operand *cond = IC_COND (ic);
10433   int isbit = 0;
10434   char *dup = NULL;
10435
10436   D(emitcode (";     genIfx",""));
10437
10438   aopOp (cond, ic, FALSE);
10439
10440   /* get the value into acc */
10441   if (AOP_TYPE (cond) != AOP_CRY)
10442     toBoolean (cond);
10443   else
10444     {
10445       isbit = 1;
10446       if (AOP(cond)->aopu.aop_dir)
10447         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10448     }
10449   /* the result is now in the accumulator or a directly addressable bit */
10450   freeAsmop (cond, NULL, ic, TRUE);
10451
10452   /* if there was something to be popped then do it */
10453   if (popIc)
10454     genIpop (popIc);
10455
10456   /* if the condition is a bit variable */
10457   if (isbit && dup)
10458     genIfxJump(ic, dup, NULL, NULL, NULL);
10459   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10460     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10461   else if (isbit && !IS_ITEMP (cond))
10462     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10463   else
10464     genIfxJump (ic, "a", NULL, NULL, NULL);
10465
10466   ic->generated = 1;
10467 }
10468
10469 /*-----------------------------------------------------------------*/
10470 /* genAddrOf - generates code for address of                       */
10471 /*-----------------------------------------------------------------*/
10472 static void
10473 genAddrOf (iCode * ic)
10474 {
10475   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10476   int size, offset;
10477
10478   D(emitcode (";     genAddrOf",""));
10479
10480   aopOp (IC_RESULT (ic), ic, FALSE);
10481
10482   /* if the operand is on the stack then we
10483      need to get the stack offset of this
10484      variable */
10485   if (sym->onStack)
10486     {
10487       /* if it has an offset then we need to compute
10488          it */
10489       if (sym->stack)
10490         {
10491           emitcode ("mov", "a,%s", SYM_BP (sym));
10492           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10493                                          ((char) (sym->stack - _G.nRegsSaved)) :
10494                                          ((char) sym->stack)) & 0xff);
10495           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10496         }
10497       else
10498         {
10499           /* we can just move _bp */
10500           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10501         }
10502       /* fill the result with zero */
10503       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10504
10505       offset = 1;
10506       while (size--)
10507         {
10508           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10509         }
10510
10511       goto release;
10512     }
10513
10514   /* object not on stack then we need the name */
10515   size = AOP_SIZE (IC_RESULT (ic));
10516   offset = 0;
10517
10518   while (size--)
10519     {
10520       char s[SDCC_NAME_MAX];
10521       if (offset)
10522         sprintf (s, "#(%s >> %d)",
10523                  sym->rname,
10524                  offset * 8);
10525       else
10526         sprintf (s, "#%s", sym->rname);
10527       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10528     }
10529
10530 release:
10531   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10532
10533 }
10534
10535 /*-----------------------------------------------------------------*/
10536 /* genFarFarAssign - assignment when both are in far space         */
10537 /*-----------------------------------------------------------------*/
10538 static void
10539 genFarFarAssign (operand * result, operand * right, iCode * ic)
10540 {
10541   int size = AOP_SIZE (right);
10542   int offset = 0;
10543   char *l;
10544
10545   D(emitcode (";     genFarFarAssign",""));
10546
10547   /* first push the right side on to the stack */
10548   while (size--)
10549     {
10550       l = aopGet (right, offset++, FALSE, FALSE);
10551       MOVA (l);
10552       emitcode ("push", "acc");
10553     }
10554
10555   freeAsmop (right, NULL, ic, FALSE);
10556   /* now assign DPTR to result */
10557   aopOp (result, ic, FALSE);
10558   size = AOP_SIZE (result);
10559   while (size--)
10560     {
10561       emitcode ("pop", "acc");
10562       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10563     }
10564   freeAsmop (result, NULL, ic, FALSE);
10565
10566 }
10567
10568 /*-----------------------------------------------------------------*/
10569 /* genAssign - generate code for assignment                        */
10570 /*-----------------------------------------------------------------*/
10571 static void
10572 genAssign (iCode * ic)
10573 {
10574   operand *result, *right;
10575   int size, offset;
10576   unsigned long lit = 0L;
10577
10578   D(emitcode(";     genAssign",""));
10579
10580   result = IC_RESULT (ic);
10581   right = IC_RIGHT (ic);
10582
10583   /* if they are the same */
10584   if (operandsEqu (result, right) &&
10585       !isOperandVolatile (result, FALSE) &&
10586       !isOperandVolatile (right, FALSE))
10587     return;
10588
10589   aopOp (right, ic, FALSE);
10590
10591   /* special case both in far space */
10592   if (AOP_TYPE (right) == AOP_DPTR &&
10593       IS_TRUE_SYMOP (result) &&
10594       isOperandInFarSpace (result))
10595     {
10596
10597       genFarFarAssign (result, right, ic);
10598       return;
10599     }
10600
10601   aopOp (result, ic, TRUE);
10602
10603   /* if they are the same registers */
10604   if (sameRegs (AOP (right), AOP (result)) &&
10605       !isOperandVolatile (result, FALSE) &&
10606       !isOperandVolatile (right, FALSE))
10607     goto release;
10608
10609   /* if the result is a bit */
10610   if (AOP_TYPE (result) == AOP_CRY)
10611     {
10612
10613       /* if the right size is a literal then
10614          we know what the value is */
10615       if (AOP_TYPE (right) == AOP_LIT)
10616         {
10617           if (((int) operandLitValue (right)))
10618             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10619           else
10620             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10621           goto release;
10622         }
10623
10624       /* the right is also a bit variable */
10625       if (AOP_TYPE (right) == AOP_CRY)
10626         {
10627           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10628           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10629           goto release;
10630         }
10631
10632       /* we need to or */
10633       toBoolean (right);
10634       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10635       goto release;
10636     }
10637
10638   /* bit variables done */
10639   /* general case */
10640   size = AOP_SIZE (result);
10641   offset = 0;
10642   if (AOP_TYPE (right) == AOP_LIT)
10643     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10644   if ((size > 1) &&
10645       (AOP_TYPE (result) != AOP_REG) &&
10646       (AOP_TYPE (right) == AOP_LIT) &&
10647       !IS_FLOAT (operandType (right)) &&
10648       (lit < 256L))
10649     {
10650       while ((size) && (lit))
10651         {
10652           aopPut (result,
10653                   aopGet (right, offset, FALSE, FALSE),
10654                   offset,
10655                   isOperandVolatile (result, FALSE));
10656           lit >>= 8;
10657           offset++;
10658           size--;
10659         }
10660       emitcode ("clr", "a");
10661       while (size--)
10662         {
10663           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10664           offset++;
10665         }
10666     }
10667   else
10668     {
10669       while (size--)
10670         {
10671           aopPut (result,
10672                   aopGet (right, offset, FALSE, FALSE),
10673                   offset,
10674                   isOperandVolatile (result, FALSE));
10675           offset++;
10676         }
10677     }
10678
10679 release:
10680   freeAsmop (right, NULL, ic, TRUE);
10681   freeAsmop (result, NULL, ic, TRUE);
10682 }
10683
10684 /*-----------------------------------------------------------------*/
10685 /* genJumpTab - generates code for jump table                      */
10686 /*-----------------------------------------------------------------*/
10687 static void
10688 genJumpTab (iCode * ic)
10689 {
10690   symbol *jtab,*jtablo,*jtabhi;
10691   char *l;
10692   unsigned int count;
10693
10694   D(emitcode (";     genJumpTab",""));
10695
10696   count = elementsInSet( IC_JTLABELS (ic) );
10697
10698   if( count <= 16 )
10699     {
10700       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10701          if the switch argument is in a register.
10702          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10703       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10704          How will multiply by three be updated ???*/
10705       aopOp (IC_JTCOND (ic), ic, FALSE);
10706       /* get the condition into accumulator */
10707       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10708       MOVA (l);
10709       /* multiply by three */
10710       emitcode ("add", "a,acc");
10711       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10712       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10713
10714       jtab = newiTempLabel (NULL);
10715       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10716       emitcode ("jmp", "@a+dptr");
10717       emitcode ("", "%05d$:", jtab->key + 100);
10718       /* now generate the jump labels */
10719       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10720            jtab = setNextItem (IC_JTLABELS (ic)))
10721         emitcode ("ljmp", "%05d$", jtab->key + 100);
10722     }
10723   else
10724     {
10725       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10726          if the switch argument is in a register.
10727          For n>6 this algorithm may be more compact */
10728       jtablo = newiTempLabel (NULL);
10729       jtabhi = newiTempLabel (NULL);
10730
10731       /* get the condition into accumulator.
10732          Using b as temporary storage, if register push/pop is needed */
10733       aopOp (IC_JTCOND (ic), ic, FALSE);
10734       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10735       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10736           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10737         {
10738           // (MB) what if B is in use???
10739           wassertl(!BINUSE, "B was in use");
10740           emitcode ("mov", "b,%s", l);
10741           l = "b";
10742         }
10743       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10744       MOVA (l);
10745       if( count <= 112 )
10746         {
10747           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10748           emitcode ("movc", "a,@a+pc");
10749           emitcode ("push", "acc");
10750
10751           MOVA (l);
10752           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10753           emitcode ("movc", "a,@a+pc");
10754           emitcode ("push", "acc");
10755         }
10756       else
10757         {
10758           /* this scales up to n<=255, but needs two more bytes
10759              and changes dptr */
10760           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10761           emitcode ("movc", "a,@a+dptr");
10762           emitcode ("push", "acc");
10763
10764           MOVA (l);
10765           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10766           emitcode ("movc", "a,@a+dptr");
10767           emitcode ("push", "acc");
10768         }
10769
10770       emitcode ("ret", "");
10771
10772       /* now generate jump table, LSB */
10773       emitcode ("", "%05d$:", jtablo->key + 100);
10774       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10775            jtab = setNextItem (IC_JTLABELS (ic)))
10776         emitcode (".db", "%05d$", jtab->key + 100);
10777
10778       /* now generate jump table, MSB */
10779       emitcode ("", "%05d$:", jtabhi->key + 100);
10780       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10781            jtab = setNextItem (IC_JTLABELS (ic)))
10782          emitcode (".db", "%05d$>>8", jtab->key + 100);
10783     }
10784 }
10785
10786 /*-----------------------------------------------------------------*/
10787 /* genCast - gen code for casting                                  */
10788 /*-----------------------------------------------------------------*/
10789 static void
10790 genCast (iCode * ic)
10791 {
10792   operand *result = IC_RESULT (ic);
10793   sym_link *ctype = operandType (IC_LEFT (ic));
10794   sym_link *rtype = operandType (IC_RIGHT (ic));
10795   operand *right = IC_RIGHT (ic);
10796   int size, offset;
10797
10798   D(emitcode(";     genCast",""));
10799
10800   /* if they are equivalent then do nothing */
10801   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10802     return;
10803
10804   aopOp (right, ic, FALSE);
10805   aopOp (result, ic, FALSE);
10806
10807   /* if the result is a bit (and not a bitfield) */
10808   // if (AOP_TYPE (result) == AOP_CRY)
10809   if (IS_BITVAR (OP_SYMBOL (result)->type)
10810       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10811     {
10812       /* if the right size is a literal then
10813          we know what the value is */
10814       if (AOP_TYPE (right) == AOP_LIT)
10815         {
10816           if (((int) operandLitValue (right)))
10817             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10818           else
10819             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10820
10821           goto release;
10822         }
10823
10824       /* the right is also a bit variable */
10825       if (AOP_TYPE (right) == AOP_CRY)
10826         {
10827           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10828           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10829           goto release;
10830         }
10831
10832       /* we need to or */
10833       toBoolean (right);
10834       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10835       goto release;
10836     }
10837
10838
10839   /* if they are the same size : or less */
10840   if (AOP_SIZE (result) <= AOP_SIZE (right))
10841     {
10842
10843       /* if they are in the same place */
10844       if (sameRegs (AOP (right), AOP (result)))
10845         goto release;
10846
10847       /* if they in different places then copy */
10848       size = AOP_SIZE (result);
10849       offset = 0;
10850       while (size--)
10851         {
10852           aopPut (result,
10853                   aopGet (right, offset, FALSE, FALSE),
10854                   offset,
10855                   isOperandVolatile (result, FALSE));
10856           offset++;
10857         }
10858       goto release;
10859     }
10860
10861
10862   /* if the result is of type pointer */
10863   if (IS_PTR (ctype))
10864     {
10865
10866       int p_type;
10867       sym_link *type = operandType (right);
10868       sym_link *etype = getSpec (type);
10869
10870       /* pointer to generic pointer */
10871       if (IS_GENPTR (ctype))
10872         {
10873           if (IS_PTR (type))
10874             p_type = DCL_TYPE (type);
10875           else
10876             {
10877               if (SPEC_SCLS(etype)==S_REGISTER) {
10878                 // let's assume it is a generic pointer
10879                 p_type=GPOINTER;
10880               } else {
10881                 /* we have to go by the storage class */
10882                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10883               }
10884             }
10885
10886           /* the first two bytes are known */
10887           size = GPTRSIZE - 1;
10888           offset = 0;
10889           while (size--)
10890             {
10891               aopPut (result,
10892                       aopGet (right, offset, FALSE, FALSE),
10893                       offset,
10894                       isOperandVolatile (result, FALSE));
10895               offset++;
10896             }
10897           /* the last byte depending on type */
10898             {
10899                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10900                 char gpValStr[10];
10901
10902                 if (gpVal == -1)
10903                 {
10904                     // pointerTypeToGPByte will have bitched.
10905                     exit(1);
10906                 }
10907
10908                 sprintf(gpValStr, "#0x%x", gpVal);
10909                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10910             }
10911           goto release;
10912         }
10913
10914       /* just copy the pointers */
10915       size = AOP_SIZE (result);
10916       offset = 0;
10917       while (size--)
10918         {
10919           aopPut (result,
10920                   aopGet (right, offset, FALSE, FALSE),
10921                   offset,
10922                   isOperandVolatile (result, FALSE));
10923           offset++;
10924         }
10925       goto release;
10926     }
10927
10928   /* so we now know that the size of destination is greater
10929      than the size of the source */
10930   /* we move to result for the size of source */
10931   size = AOP_SIZE (right);
10932   offset = 0;
10933   while (size--)
10934     {
10935       aopPut (result,
10936               aopGet (right, offset, FALSE, FALSE),
10937               offset,
10938               isOperandVolatile (result, FALSE));
10939       offset++;
10940     }
10941
10942   /* now depending on the sign of the source && destination */
10943   size = AOP_SIZE (result) - AOP_SIZE (right);
10944   /* if unsigned or not an integral type */
10945   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10946     {
10947       while (size--)
10948         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10949     }
10950   else
10951     {
10952       /* we need to extend the sign :{ */
10953       char *l = aopGet (right, AOP_SIZE (right) - 1,
10954                         FALSE, FALSE);
10955       MOVA (l);
10956       emitcode ("rlc", "a");
10957       emitcode ("subb", "a,acc");
10958       while (size--)
10959         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10960     }
10961
10962   /* we are done hurray !!!! */
10963
10964 release:
10965   freeAsmop (right, NULL, ic, TRUE);
10966   freeAsmop (result, NULL, ic, TRUE);
10967
10968 }
10969
10970 /*-----------------------------------------------------------------*/
10971 /* genDjnz - generate decrement & jump if not zero instrucion      */
10972 /*-----------------------------------------------------------------*/
10973 static int
10974 genDjnz (iCode * ic, iCode * ifx)
10975 {
10976   symbol *lbl, *lbl1;
10977   if (!ifx)
10978     return 0;
10979
10980   D(emitcode (";     genDjnz",""));
10981
10982   /* if the if condition has a false label
10983      then we cannot save */
10984   if (IC_FALSE (ifx))
10985     return 0;
10986
10987   /* if the minus is not of the form
10988      a = a - 1 */
10989   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10990       !IS_OP_LITERAL (IC_RIGHT (ic)))
10991     return 0;
10992
10993   if (operandLitValue (IC_RIGHT (ic)) != 1)
10994     return 0;
10995
10996   /* if the size of this greater than one then no
10997      saving */
10998   if (getSize (operandType (IC_RESULT (ic))) > 1)
10999     return 0;
11000
11001   /* otherwise we can save BIG */
11002   lbl = newiTempLabel (NULL);
11003   lbl1 = newiTempLabel (NULL);
11004
11005   aopOp (IC_RESULT (ic), ic, FALSE);
11006
11007   if (AOP_NEEDSACC(IC_RESULT(ic)))
11008   {
11009       /* If the result is accessed indirectly via
11010        * the accumulator, we must explicitly write
11011        * it back after the decrement.
11012        */
11013       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11014
11015       if (strcmp(rByte, "a"))
11016       {
11017            /* Something is hopelessly wrong */
11018            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11019                    __FILE__, __LINE__);
11020            /* We can just give up; the generated code will be inefficient,
11021             * but what the hey.
11022             */
11023            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11024            return 0;
11025       }
11026       emitcode ("dec", "%s", rByte);
11027       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
11028       emitcode ("jnz", "%05d$", lbl->key + 100);
11029   }
11030   else if (IS_AOP_PREG (IC_RESULT (ic)))
11031     {
11032       emitcode ("dec", "%s",
11033                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11034       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11035       emitcode ("jnz", "%05d$", lbl->key + 100);
11036     }
11037   else
11038     {
11039       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11040                 lbl->key + 100);
11041     }
11042   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11043   emitcode ("", "%05d$:", lbl->key + 100);
11044   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11045   emitcode ("", "%05d$:", lbl1->key + 100);
11046
11047   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11048   ifx->generated = 1;
11049   return 1;
11050 }
11051
11052 /*-----------------------------------------------------------------*/
11053 /* genReceive - generate code for a receive iCode                  */
11054 /*-----------------------------------------------------------------*/
11055 static void
11056 genReceive (iCode * ic)
11057 {
11058   int size = getSize (operandType (IC_RESULT (ic)));
11059   int offset = 0;
11060
11061   D(emitcode (";     genReceive",""));
11062
11063   if (ic->argreg == 1)
11064     { /* first parameter */
11065       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11066            isOperandInPagedSpace (IC_RESULT (ic))) &&
11067           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11068            IS_TRUE_SYMOP (IC_RESULT (ic))))
11069         {
11070           regs *tempRegs[4];
11071           int receivingA = 0;
11072           int roffset = 0;
11073
11074           for (offset = 0; offset<size; offset++)
11075             if (!strcmp (fReturn[offset], "a"))
11076               receivingA = 1;
11077
11078           if (!receivingA)
11079             {
11080               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11081                 {
11082                   for (offset = size-1; offset>0; offset--)
11083                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11084                   emitcode("mov","a,%s", fReturn[0]);
11085                   _G.accInUse++;
11086                   aopOp (IC_RESULT (ic), ic, FALSE);
11087                   _G.accInUse--;
11088                   aopPut (IC_RESULT (ic), "a", offset,
11089                           isOperandVolatile (IC_RESULT (ic), FALSE));
11090                   for (offset = 1; offset<size; offset++)
11091                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
11092                             isOperandVolatile (IC_RESULT (ic), FALSE));
11093                   goto release;
11094                 }
11095             }
11096           else
11097             {
11098               if (getTempRegs(tempRegs, size, ic))
11099                 {
11100                   for (offset = 0; offset<size; offset++)
11101                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11102                   aopOp (IC_RESULT (ic), ic, FALSE);
11103                   for (offset = 0; offset<size; offset++)
11104                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
11105                             isOperandVolatile (IC_RESULT (ic), FALSE));
11106                   goto release;
11107                 }
11108             }
11109
11110           offset = fReturnSizeMCS51 - size;
11111           while (size--)
11112             {
11113               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11114                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11115               offset++;
11116             }
11117           aopOp (IC_RESULT (ic), ic, FALSE);
11118           size = AOP_SIZE (IC_RESULT (ic));
11119           offset = 0;
11120           while (size--)
11121             {
11122               emitcode ("pop", "acc");
11123               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11124             }
11125         }
11126       else
11127         {
11128           _G.accInUse++;
11129           aopOp (IC_RESULT (ic), ic, FALSE);
11130           _G.accInUse--;
11131           assignResultValue (IC_RESULT (ic), NULL);
11132         }
11133     }
11134   else if (ic->argreg > 12)
11135     { /* bit parameters */
11136       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11137         {
11138           aopOp (IC_RESULT (ic), ic, FALSE);
11139           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11140           outBitC(IC_RESULT (ic));
11141         }
11142     }
11143   else
11144     { /* other parameters */
11145       int rb1off ;
11146       aopOp (IC_RESULT (ic), ic, FALSE);
11147       rb1off = ic->argreg;
11148       while (size--)
11149         {
11150           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11151         }
11152     }
11153
11154 release:
11155   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11156 }
11157
11158 /*-----------------------------------------------------------------*/
11159 /* genDummyRead - generate code for dummy read of volatiles        */
11160 /*-----------------------------------------------------------------*/
11161 static void
11162 genDummyRead (iCode * ic)
11163 {
11164   operand *op;
11165   int size, offset;
11166
11167   D(emitcode(";     genDummyRead",""));
11168
11169   op = IC_RIGHT (ic);
11170   if (op && IS_SYMOP (op))
11171     {
11172       aopOp (op, ic, FALSE);
11173
11174       /* if the result is a bit */
11175       if (AOP_TYPE (op) == AOP_CRY)
11176         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11177       else
11178         {
11179           /* bit variables done */
11180           /* general case */
11181           size = AOP_SIZE (op);
11182           offset = 0;
11183           while (size--)
11184           {
11185             MOVA (aopGet (op, offset, FALSE, FALSE));
11186             offset++;
11187           }
11188         }
11189
11190       freeAsmop (op, NULL, ic, TRUE);
11191     }
11192
11193   op = IC_LEFT (ic);
11194   if (op && IS_SYMOP (op))
11195     {
11196       aopOp (op, ic, FALSE);
11197
11198       /* if the result is a bit */
11199       if (AOP_TYPE (op) == AOP_CRY)
11200         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11201       else
11202         {
11203           /* bit variables done */
11204           /* general case */
11205           size = AOP_SIZE (op);
11206           offset = 0;
11207           while (size--)
11208           {
11209             MOVA (aopGet (op, offset, FALSE, FALSE));
11210             offset++;
11211           }
11212         }
11213
11214       freeAsmop (op, NULL, ic, TRUE);
11215     }
11216 }
11217
11218 /*-----------------------------------------------------------------*/
11219 /* genCritical - generate code for start of a critical sequence    */
11220 /*-----------------------------------------------------------------*/
11221 static void
11222 genCritical (iCode *ic)
11223 {
11224   symbol *tlbl = newiTempLabel (NULL);
11225
11226   D(emitcode(";     genCritical",""));
11227
11228   if (IC_RESULT (ic))
11229     {
11230       aopOp (IC_RESULT (ic), ic, TRUE);
11231       aopPut (IC_RESULT (ic), one, 0, 0);
11232       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11233       aopPut (IC_RESULT (ic), zero, 0, 0);
11234       emitcode ("", "%05d$:", (tlbl->key + 100));
11235       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11236     }
11237   else
11238     {
11239       emitcode ("setb", "c");
11240       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11241       emitcode ("clr", "c");
11242       emitcode ("", "%05d$:", (tlbl->key + 100));
11243       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11244     }
11245 }
11246
11247 /*-----------------------------------------------------------------*/
11248 /* genEndCritical - generate code for end of a critical sequence   */
11249 /*-----------------------------------------------------------------*/
11250 static void
11251 genEndCritical (iCode *ic)
11252 {
11253   D(emitcode(";     genEndCritical",""));
11254
11255   if (IC_RIGHT (ic))
11256     {
11257       aopOp (IC_RIGHT (ic), ic, FALSE);
11258       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11259         {
11260           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11261           emitcode ("mov", "ea,c");
11262         }
11263       else
11264         {
11265           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11266             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11267           emitcode ("rrc", "a");
11268           emitcode ("mov", "ea,c");
11269         }
11270       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11271     }
11272   else
11273     {
11274       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11275       emitcode ("mov", "ea,c");
11276     }
11277 }
11278
11279 /*-----------------------------------------------------------------*/
11280 /* gen51Code - generate code for 8051 based controllers            */
11281 /*-----------------------------------------------------------------*/
11282 void
11283 gen51Code (iCode * lic)
11284 {
11285   iCode *ic;
11286   int cln = 0;
11287   /* int cseq = 0; */
11288
11289   _G.currentFunc = NULL;
11290   lineHead = lineCurr = NULL;
11291
11292   /* print the allocation information */
11293   if (allocInfo && currFunc)
11294     printAllocInfo (currFunc, codeOutFile);
11295   /* if debug information required */
11296   if (options.debug && currFunc)
11297     {
11298       debugFile->writeFunction (currFunc, lic);
11299     }
11300   /* stack pointer name */
11301   if (options.useXstack)
11302     spname = "_spx";
11303   else
11304     spname = "sp";
11305
11306
11307   for (ic = lic; ic; ic = ic->next)
11308     {
11309       _G.current_iCode = ic;
11310
11311       if (ic->lineno && cln != ic->lineno)
11312         {
11313           if (options.debug)
11314             {
11315               debugFile->writeCLine (ic);
11316             }
11317           if (!options.noCcodeInAsm) {
11318             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11319                       printCLine(ic->filename, ic->lineno));
11320           }
11321           cln = ic->lineno;
11322         }
11323       #if 0
11324       if (ic->seqPoint && ic->seqPoint != cseq)
11325         {
11326           emitcode ("", "; sequence point %d", ic->seqPoint);
11327           cseq = ic->seqPoint;
11328         }
11329       #endif
11330       if (options.iCodeInAsm) {
11331         char regsInUse[80];
11332         int i;
11333
11334         for (i=0; i<8; i++) {
11335           sprintf (&regsInUse[i],
11336                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
11337         }
11338         regsInUse[i]=0;
11339         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11340       }
11341       /* if the result is marked as
11342          spilt and rematerializable or code for
11343          this has already been generated then
11344          do nothing */
11345       if (resultRemat (ic) || ic->generated)
11346         continue;
11347
11348       /* depending on the operation */
11349       switch (ic->op)
11350         {
11351         case '!':
11352           genNot (ic);
11353           break;
11354
11355         case '~':
11356           genCpl (ic);
11357           break;
11358
11359         case UNARYMINUS:
11360           genUminus (ic);
11361           break;
11362
11363         case IPUSH:
11364           genIpush (ic);
11365           break;
11366
11367         case IPOP:
11368           /* IPOP happens only when trying to restore a
11369              spilt live range, if there is an ifx statement
11370              following this pop then the if statement might
11371              be using some of the registers being popped which
11372              would destory the contents of the register so
11373              we need to check for this condition and handle it */
11374           if (ic->next &&
11375               ic->next->op == IFX &&
11376               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11377             genIfx (ic->next, ic);
11378           else
11379             genIpop (ic);
11380           break;
11381
11382         case CALL:
11383           genCall (ic);
11384           break;
11385
11386         case PCALL:
11387           genPcall (ic);
11388           break;
11389
11390         case FUNCTION:
11391           genFunction (ic);
11392           break;
11393
11394         case ENDFUNCTION:
11395           genEndFunction (ic);
11396           break;
11397
11398         case RETURN:
11399           genRet (ic);
11400           break;
11401
11402         case LABEL:
11403           genLabel (ic);
11404           break;
11405
11406         case GOTO:
11407           genGoto (ic);
11408           break;
11409
11410         case '+':
11411           genPlus (ic);
11412           break;
11413
11414         case '-':
11415           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11416             genMinus (ic);
11417           break;
11418
11419         case '*':
11420           genMult (ic);
11421           break;
11422
11423         case '/':
11424           genDiv (ic);
11425           break;
11426
11427         case '%':
11428           genMod (ic);
11429           break;
11430
11431         case '>':
11432           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11433           break;
11434
11435         case '<':
11436           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11437           break;
11438
11439         case LE_OP:
11440         case GE_OP:
11441         case NE_OP:
11442
11443           /* note these two are xlated by algebraic equivalence
11444              during parsing SDCC.y */
11445           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11446                   "got '>=' or '<=' shouldn't have come here");
11447           break;
11448
11449         case EQ_OP:
11450           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11451           break;
11452
11453         case AND_OP:
11454           genAndOp (ic);
11455           break;
11456
11457         case OR_OP:
11458           genOrOp (ic);
11459           break;
11460
11461         case '^':
11462           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11463           break;
11464
11465         case '|':
11466           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11467           break;
11468
11469         case BITWISEAND:
11470           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11471           break;
11472
11473         case INLINEASM:
11474           genInline (ic);
11475           break;
11476
11477         case RRC:
11478           genRRC (ic);
11479           break;
11480
11481         case RLC:
11482           genRLC (ic);
11483           break;
11484
11485         case GETHBIT:
11486           genGetHbit (ic);
11487           break;
11488
11489         case GETABIT:
11490           genGetAbit (ic);
11491           break;
11492
11493         case GETBYTE:
11494           genGetByte (ic);
11495           break;
11496
11497         case GETWORD:
11498           genGetWord (ic);
11499           break;
11500
11501         case LEFT_OP:
11502           genLeftShift (ic);
11503           break;
11504
11505         case RIGHT_OP:
11506           genRightShift (ic);
11507           break;
11508
11509         case GET_VALUE_AT_ADDRESS:
11510           genPointerGet (ic,
11511                          hasInc (IC_LEFT (ic), ic,
11512                                  getSize (operandType (IC_RESULT (ic)))),
11513                          ifxForOp (IC_RESULT (ic), ic) );
11514           break;
11515
11516         case '=':
11517           if (POINTER_SET (ic))
11518             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11519           else
11520             genAssign (ic);
11521           break;
11522
11523         case IFX:
11524           genIfx (ic, NULL);
11525           break;
11526
11527         case ADDRESS_OF:
11528           genAddrOf (ic);
11529           break;
11530
11531         case JUMPTABLE:
11532           genJumpTab (ic);
11533           break;
11534
11535         case CAST:
11536           genCast (ic);
11537           break;
11538
11539         case RECEIVE:
11540           genReceive (ic);
11541           break;
11542
11543         case SEND:
11544           addSet (&_G.sendSet, ic);
11545           break;
11546
11547         case DUMMY_READ_VOLATILE:
11548           genDummyRead (ic);
11549           break;
11550
11551         case CRITICAL:
11552           genCritical (ic);
11553           break;
11554
11555         case ENDCRITICAL:
11556           genEndCritical (ic);
11557           break;
11558
11559         case SWAP:
11560           genSwap (ic);
11561           break;
11562
11563         default:
11564           ic = ic;
11565         }
11566     }
11567
11568   _G.current_iCode = NULL;
11569
11570   /* now we are ready to call the
11571      peep hole optimizer */
11572   if (!options.nopeep)
11573     peepHole (&lineHead);
11574
11575   /* now do the actual printing */
11576   printLine (lineHead, codeOutFile);
11577   return;
11578 }