* src/mcs51/gen.c (genMinus): fix for undetected bug introduced 3 months
[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 1;
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 /* aopPut - puts a string for a aop and indicates if acc is in use */
1355 /*-----------------------------------------------------------------*/
1356 static bool
1357 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1358 {
1359   char *d = buffer;
1360   bool accuse = FALSE;
1361   asmop * aop = AOP (result);
1362
1363   if (aop->size && offset > (aop->size - 1))
1364     {
1365       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1366               "aopPut got offset > aop->size");
1367       exit (1);
1368     }
1369
1370   /* will assign value to value */
1371   /* depending on where it is ofcourse */
1372   switch (aop->type)
1373     {
1374     case AOP_DUMMY:
1375       MOVA (s);         /* read s in case it was volatile */
1376       accuse = TRUE;
1377       break;
1378
1379     case AOP_DIR:
1380       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1381         sprintf (d, "(%s >> %d)",
1382                  aop->aopu.aop_dir, offset * 8);
1383       else if (offset)
1384         sprintf (d, "(%s + %d)",
1385                  aop->aopu.aop_dir, offset);
1386       else
1387         sprintf (d, "%s", aop->aopu.aop_dir);
1388
1389       if (strcmp (d, s) ||
1390           bvolatile)
1391           emitcode ("mov", "%s,%s", d, s);
1392       if (!strcmp (d, "acc"))
1393           accuse = TRUE;
1394
1395       break;
1396
1397     case AOP_REG:
1398       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1399           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1400         {
1401           if (*s == '@' ||
1402               strcmp (s, "r0") == 0 ||
1403               strcmp (s, "r1") == 0 ||
1404               strcmp (s, "r2") == 0 ||
1405               strcmp (s, "r3") == 0 ||
1406               strcmp (s, "r4") == 0 ||
1407               strcmp (s, "r5") == 0 ||
1408               strcmp (s, "r6") == 0 ||
1409               strcmp (s, "r7") == 0)
1410             emitcode ("mov", "%s,%s",
1411                       aop->aopu.aop_reg[offset]->dname, s);
1412           else
1413             emitcode ("mov", "%s,%s",
1414                       aop->aopu.aop_reg[offset]->name, s);
1415         }
1416       break;
1417
1418     case AOP_DPTR:
1419       if (aop->code)
1420         {
1421           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1422                   "aopPut writing to code space");
1423           exit (1);
1424         }
1425
1426       while (offset > aop->coff)
1427         {
1428           aop->coff++;
1429           emitcode ("inc", "dptr");
1430         }
1431
1432       while (offset < aop->coff)
1433         {
1434           aop->coff--;
1435           emitcode ("lcall", "__decdptr");
1436         }
1437
1438       aop->coff = offset;
1439
1440       /* if not in accumulator */
1441       MOVA (s);
1442
1443       emitcode ("movx", "@dptr,a");
1444       break;
1445
1446     case AOP_R0:
1447     case AOP_R1:
1448       while (offset > aop->coff)
1449         {
1450           aop->coff++;
1451           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1452         }
1453       while (offset < aop->coff)
1454         {
1455           aop->coff--;
1456           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1457         }
1458       aop->coff = offset;
1459
1460       if (aop->paged)
1461         {
1462           MOVA (s);
1463           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1464
1465         }
1466       else if (*s == '@')
1467         {
1468           MOVA (s);
1469           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1470         }
1471       else if (strcmp (s, "r0") == 0 ||
1472                strcmp (s, "r1") == 0 ||
1473                strcmp (s, "r2") == 0 ||
1474                strcmp (s, "r3") == 0 ||
1475                strcmp (s, "r4") == 0 ||
1476                strcmp (s, "r5") == 0 ||
1477                strcmp (s, "r6") == 0 ||
1478                strcmp (s, "r7") == 0)
1479         {
1480           char buffer[10];
1481           sprintf (buffer, "a%s", s);
1482           emitcode ("mov", "@%s,%s",
1483                     aop->aopu.aop_ptr->name, buffer);
1484         }
1485       else
1486         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1487
1488       break;
1489
1490     case AOP_STK:
1491       if (strcmp (s, "a") == 0)
1492         emitcode ("push", "acc");
1493       else
1494         if (*s=='@') {
1495           MOVA(s);
1496           emitcode ("push", "acc");
1497         } else {
1498           emitcode ("push", s);
1499         }
1500
1501       break;
1502
1503     case AOP_CRY:
1504       /* if not bit variable */
1505       if (!aop->aopu.aop_dir)
1506         {
1507           /* inefficient: move carry into A and use jz/jnz */
1508           emitcode ("clr", "a");
1509           emitcode ("rlc", "a");
1510           accuse = TRUE;
1511         }
1512       else
1513         {
1514           if (s == zero)
1515             emitcode ("clr", "%s", aop->aopu.aop_dir);
1516           else if (s == one)
1517             emitcode ("setb", "%s", aop->aopu.aop_dir);
1518           else if (!strcmp (s, "c"))
1519             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1520           else if (strcmp (s, aop->aopu.aop_dir))
1521             {
1522               MOVA (s);
1523               /* set C, if a >= 1 */
1524               emitcode ("add", "a,#0xff");
1525               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1526             }
1527         }
1528       break;
1529
1530     case AOP_STR:
1531       aop->coff = offset;
1532       if (strcmp (aop->aopu.aop_str[offset], s) ||
1533           bvolatile)
1534         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1535       break;
1536
1537     case AOP_ACC:
1538       accuse = TRUE;
1539       aop->coff = offset;
1540       if (!offset && (strcmp (s, "acc") == 0) &&
1541           !bvolatile)
1542         break;
1543
1544       if (strcmp (aop->aopu.aop_str[offset], s) &&
1545           !bvolatile)
1546         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1547       break;
1548
1549     default:
1550       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1551               "aopPut got unsupported aop->type");
1552       exit (1);
1553     }
1554
1555     return accuse;
1556 }
1557
1558
1559 #if 0
1560 /*-----------------------------------------------------------------*/
1561 /* pointToEnd :- points to the last byte of the operand            */
1562 /*-----------------------------------------------------------------*/
1563 static void
1564 pointToEnd (asmop * aop)
1565 {
1566   int count;
1567   if (!aop)
1568     return;
1569
1570   aop->coff = count = (aop->size - 1);
1571   switch (aop->type)
1572     {
1573     case AOP_R0:
1574     case AOP_R1:
1575       while (count--)
1576         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1577       break;
1578     case AOP_DPTR:
1579       while (count--)
1580         emitcode ("inc", "dptr");
1581       break;
1582     }
1583
1584 }
1585 #endif
1586
1587 /*-----------------------------------------------------------------*/
1588 /* reAdjustPreg - points a register back to where it should        */
1589 /*-----------------------------------------------------------------*/
1590 static void
1591 reAdjustPreg (asmop * aop)
1592 {
1593   if ((aop->coff==0) || aop->size <= 1)
1594     return;
1595
1596   switch (aop->type)
1597     {
1598     case AOP_R0:
1599     case AOP_R1:
1600       while (aop->coff--)
1601         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1602       break;
1603     case AOP_DPTR:
1604       while (aop->coff--)
1605         {
1606           emitcode ("lcall", "__decdptr");
1607         }
1608       break;
1609     }
1610   aop->coff = 0;
1611 }
1612
1613 /*-----------------------------------------------------------------*/
1614 /* opIsGptr: returns non-zero if the passed operand is       */
1615 /* a generic pointer type.             */
1616 /*-----------------------------------------------------------------*/
1617 static int
1618 opIsGptr (operand * op)
1619 {
1620   sym_link *type = operandType (op);
1621
1622   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1623     {
1624       return 1;
1625     }
1626   return 0;
1627 }
1628
1629 /*-----------------------------------------------------------------*/
1630 /* getDataSize - get the operand data size                         */
1631 /*-----------------------------------------------------------------*/
1632 static int
1633 getDataSize (operand * op)
1634 {
1635   int size;
1636   size = AOP_SIZE (op);
1637   if (size == GPTRSIZE)
1638     {
1639       sym_link *type = operandType (op);
1640       if (IS_GENPTR (type))
1641         {
1642           /* generic pointer; arithmetic operations
1643            * should ignore the high byte (pointer type).
1644            */
1645           size--;
1646         }
1647     }
1648   return size;
1649 }
1650
1651 /*-----------------------------------------------------------------*/
1652 /* outAcc - output Acc                                             */
1653 /*-----------------------------------------------------------------*/
1654 static void
1655 outAcc (operand * result)
1656 {
1657   int size, offset;
1658   size = getDataSize (result);
1659   if (size)
1660     {
1661       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1662       size--;
1663       offset = 1;
1664       /* unsigned or positive */
1665       while (size--)
1666         {
1667           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1668         }
1669     }
1670 }
1671
1672 /*-----------------------------------------------------------------*/
1673 /* outBitC - output a bit C                                        */
1674 /*-----------------------------------------------------------------*/
1675 static void
1676 outBitC (operand * result)
1677 {
1678   /* if the result is bit */
1679   if (AOP_TYPE (result) == AOP_CRY)
1680     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1681   else
1682     {
1683       emitcode ("clr", "a");
1684       emitcode ("rlc", "a");
1685       outAcc (result);
1686     }
1687 }
1688
1689 /*-----------------------------------------------------------------*/
1690 /* toBoolean - emit code for orl a,operator(sizeop)                */
1691 /*-----------------------------------------------------------------*/
1692 static void
1693 toBoolean (operand * oper)
1694 {
1695   int size = AOP_SIZE (oper) - 1;
1696   int offset = 1;
1697   bool AccUsed = FALSE;
1698   bool pushedB;
1699
1700   while (!AccUsed && size--)
1701     {
1702       AccUsed |= aopGetUsesAcc(oper, offset++);
1703     }
1704
1705   size = AOP_SIZE (oper) - 1;
1706   offset = 1;
1707   MOVA (aopGet (oper, 0, FALSE, FALSE));
1708   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1709     {
1710       pushedB = pushB ();
1711       emitcode("mov", "b,a");
1712       while (--size)
1713         {
1714           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1715           emitcode ("orl", "b,a");
1716         }
1717       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1718       emitcode ("orl", "a,b");
1719       popB (pushedB);
1720     }
1721   else
1722     {
1723       while (size--)
1724         {
1725           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1726         }
1727     }
1728 }
1729
1730
1731 /*-----------------------------------------------------------------*/
1732 /* genNot - generate code for ! operation                          */
1733 /*-----------------------------------------------------------------*/
1734 static void
1735 genNot (iCode * ic)
1736 {
1737   symbol *tlbl;
1738
1739   D(emitcode (";     genNot",""));
1740
1741   /* assign asmOps to operand & result */
1742   aopOp (IC_LEFT (ic), ic, FALSE);
1743   aopOp (IC_RESULT (ic), ic, TRUE);
1744
1745   /* if in bit space then a special case */
1746   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1747     {
1748       /* if left==result then cpl bit */
1749       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1750         {
1751           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1752         }
1753       else
1754         {
1755           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1756           emitcode ("cpl", "c");
1757           outBitC (IC_RESULT (ic));
1758         }
1759       goto release;
1760     }
1761
1762   toBoolean (IC_LEFT (ic));
1763
1764   /* set C, if a == 0 */
1765   tlbl = newiTempLabel (NULL);
1766   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1767   emitcode ("", "%05d$:", tlbl->key + 100);
1768   outBitC (IC_RESULT (ic));
1769
1770 release:
1771   /* release the aops */
1772   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1773   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1774 }
1775
1776
1777 /*-----------------------------------------------------------------*/
1778 /* genCpl - generate code for complement                           */
1779 /*-----------------------------------------------------------------*/
1780 static void
1781 genCpl (iCode * ic)
1782 {
1783   int offset = 0;
1784   int size;
1785   symbol *tlbl;
1786   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1787
1788   D(emitcode (";", "genCpl"));
1789
1790   /* assign asmOps to operand & result */
1791   aopOp (IC_LEFT (ic), ic, FALSE);
1792   aopOp (IC_RESULT (ic), ic, TRUE);
1793
1794   /* special case if in bit space */
1795   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1796     {
1797       char *l;
1798
1799       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1800           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1801         {
1802           /* promotion rules are responsible for this strange result:
1803              bit -> int -> ~int -> bit
1804              uchar -> int -> ~int -> bit
1805           */
1806           werror(W_COMPLEMENT);
1807           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1808           goto release;
1809         }
1810
1811       tlbl=newiTempLabel(NULL);
1812       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1813       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1814           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1815           IS_AOP_PREG (IC_LEFT (ic)))
1816         {
1817           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1818         }
1819       else
1820         {
1821           MOVA (l);
1822           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1823         }
1824       emitcode ("", "%05d$:", tlbl->key + 100);
1825       outBitC (IC_RESULT(ic));
1826       goto release;
1827     }
1828
1829   size = AOP_SIZE (IC_RESULT (ic));
1830   while (size--)
1831     {
1832       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1833       MOVA (l);
1834       emitcode ("cpl", "a");
1835       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1836     }
1837
1838
1839 release:
1840   /* release the aops */
1841   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1842   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1843 }
1844
1845 /*-----------------------------------------------------------------*/
1846 /* genUminusFloat - unary minus for floating points                */
1847 /*-----------------------------------------------------------------*/
1848 static void
1849 genUminusFloat (operand * op, operand * result)
1850 {
1851   int size, offset = 0;
1852   char *l;
1853
1854   D(emitcode (";     genUminusFloat",""));
1855
1856   /* for this we just copy and then flip the bit */
1857
1858   size = AOP_SIZE (op) - 1;
1859
1860   while (size--)
1861     {
1862       aopPut (result,
1863               aopGet (op, offset, FALSE, FALSE),
1864               offset,
1865               isOperandVolatile (result, FALSE));
1866       offset++;
1867     }
1868
1869   l = aopGet (op, offset, FALSE, FALSE);
1870
1871   MOVA (l);
1872
1873   emitcode ("cpl", "acc.7");
1874   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1875 }
1876
1877 /*-----------------------------------------------------------------*/
1878 /* genUminus - unary minus code generation                         */
1879 /*-----------------------------------------------------------------*/
1880 static void
1881 genUminus (iCode * ic)
1882 {
1883   int offset, size;
1884   sym_link *optype, *rtype;
1885
1886
1887   D(emitcode (";     genUminus",""));
1888
1889   /* assign asmops */
1890   aopOp (IC_LEFT (ic), ic, FALSE);
1891   aopOp (IC_RESULT (ic), ic, TRUE);
1892
1893   /* if both in bit space then special
1894      case */
1895   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1896       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1897     {
1898
1899       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1900       emitcode ("cpl", "c");
1901       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1902       goto release;
1903     }
1904
1905   optype = operandType (IC_LEFT (ic));
1906   rtype = operandType (IC_RESULT (ic));
1907
1908   /* if float then do float stuff */
1909   if (IS_FLOAT (optype))
1910     {
1911       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1912       goto release;
1913     }
1914
1915   /* otherwise subtract from zero */
1916   size = AOP_SIZE (IC_LEFT (ic));
1917   offset = 0;
1918   //CLRC ;
1919   while (size--)
1920     {
1921       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1922       if (!strcmp (l, "a"))
1923         {
1924           if (offset == 0)
1925             SETC;
1926           emitcode ("cpl", "a");
1927           emitcode ("addc", "a,#0");
1928         }
1929       else
1930         {
1931           if (offset == 0)
1932             CLRC;
1933           emitcode ("clr", "a");
1934           emitcode ("subb", "a,%s", l);
1935         }
1936       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1937     }
1938
1939   /* if any remaining bytes in the result */
1940   /* we just need to propagate the sign   */
1941   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1942     {
1943       emitcode ("rlc", "a");
1944       emitcode ("subb", "a,acc");
1945       while (size--)
1946         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1947     }
1948
1949 release:
1950   /* release the aops */
1951   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1952   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1953 }
1954
1955 /*-----------------------------------------------------------------*/
1956 /* saveRegisters - will look for a call and save the registers     */
1957 /*-----------------------------------------------------------------*/
1958 static void
1959 saveRegisters (iCode * lic)
1960 {
1961   int i;
1962   iCode *ic;
1963   bitVect *rsave;
1964
1965   /* look for call */
1966   for (ic = lic; ic; ic = ic->next)
1967     if (ic->op == CALL || ic->op == PCALL)
1968       break;
1969
1970   if (!ic)
1971     {
1972       fprintf (stderr, "found parameter push with no function call\n");
1973       return;
1974     }
1975
1976   /* if the registers have been saved already or don't need to be then
1977      do nothing */
1978   if (ic->regsSaved)
1979     return;
1980   if (IS_SYMOP(IC_LEFT(ic)) &&
1981       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1982        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1983     return;
1984
1985   /* save the registers in use at this time but skip the
1986      ones for the result */
1987   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1988                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1989
1990   ic->regsSaved = 1;
1991   if (options.useXstack)
1992     {
1993       int count = bitVectnBitsOn (rsave);
1994
1995       if (count == 1)
1996         {
1997           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
1998           if (reg->type == REG_BIT)
1999             {
2000               emitcode ("mov", "a,%s", reg->base);
2001             }
2002           else
2003             {
2004               emitcode ("mov", "a,%s", reg->name);
2005             }
2006           emitcode ("mov", "r0,%s", spname);
2007           emitcode ("inc", "%s", spname);// allocate before use
2008           emitcode ("movx", "@r0,a");
2009           if (bitVectBitValue (rsave, R0_IDX))
2010             emitcode ("mov", "r0,a");
2011         }
2012       else if (count != 0)
2013         {
2014           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2015           int nBits = bitVectnBitsOn (rsavebits);
2016
2017           if (nBits != 0)
2018             {
2019               count = count - nBits + 1;
2020               /* remove all but the first bits as they are pushed all at once */
2021               rsave = bitVectCplAnd (rsave, rsavebits);
2022               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2023             }
2024
2025           if (bitVectBitValue (rsave, R0_IDX))
2026             {
2027               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2028             }
2029           emitcode ("mov", "r0,%s", spname);
2030           MOVA ("r0");
2031           emitcode ("add", "a,#%d", count);
2032           emitcode ("mov", "%s,a", spname);
2033           for (i = 0; i < mcs51_nRegs; i++)
2034             {
2035               if (bitVectBitValue (rsave, i))
2036                 {
2037                   regs * reg = mcs51_regWithIdx (i);
2038                   if (i == R0_IDX)
2039                     {
2040                       emitcode ("pop", "acc");
2041                       emitcode ("push", "acc");
2042                     }
2043                   else if (reg->type == REG_BIT)
2044                     {
2045                       emitcode ("mov", "a,%s", reg->base);
2046                     }
2047                   else
2048                     {
2049                       emitcode ("mov", "a,%s", reg->name);
2050                     }
2051                   emitcode ("movx", "@r0,a");
2052                   if (--count)
2053                     {
2054                       emitcode ("inc", "r0");
2055                     }
2056                 }
2057             }
2058           if (bitVectBitValue (rsave, R0_IDX))
2059             {
2060               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2061             }
2062         }
2063     }
2064   else
2065     {
2066       bool bits_pushed = FALSE;
2067       for (i = 0; i < mcs51_nRegs; i++)
2068         {
2069           if (bitVectBitValue (rsave, i))
2070             {
2071               bits_pushed = pushReg (i, bits_pushed);
2072             }
2073         }
2074     }
2075 }
2076
2077 /*-----------------------------------------------------------------*/
2078 /* unsaveRegisters - pop the pushed registers                      */
2079 /*-----------------------------------------------------------------*/
2080 static void
2081 unsaveRegisters (iCode * ic)
2082 {
2083   int i;
2084   bitVect *rsave;
2085
2086   /* restore the registers in use at this time but skip the
2087      ones for the result */
2088   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2089                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2090
2091   if (options.useXstack)
2092     {
2093       int count = bitVectnBitsOn (rsave);
2094
2095       if (count == 1)
2096         {
2097           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2098           emitcode ("mov", "r0,%s", spname);
2099           emitcode ("dec", "r0");
2100           emitcode ("movx", "a,@r0");
2101           if (reg->type == REG_BIT)
2102             {
2103               emitcode ("mov", "%s,a", reg->base);
2104             }
2105           else
2106             {
2107               emitcode ("mov", "%s,a", reg->name);
2108             }
2109           emitcode ("dec", "%s", spname);
2110         }
2111       else if (count != 0)
2112         {
2113           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2114           int nBits = bitVectnBitsOn (rsavebits);
2115
2116           if (nBits != 0)
2117             {
2118               count = count - nBits + 1;
2119               /* remove all but the first bits as they are popped all at once */
2120               rsave = bitVectCplAnd (rsave, rsavebits);
2121               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2122             }
2123
2124           emitcode ("mov", "r0,%s", spname);
2125           for (i = mcs51_nRegs; i >= 0; i--)
2126             {
2127               if (bitVectBitValue (rsave, i))
2128                 {
2129                   regs * reg = mcs51_regWithIdx (i);
2130                   emitcode ("dec", "r0");
2131                   emitcode ("movx", "a,@r0");
2132                   if (i == R0_IDX)
2133                     {
2134                       emitcode ("push", "acc");
2135                     }
2136                   else if (reg->type == REG_BIT)
2137                     {
2138                       emitcode ("mov", "%s,a", reg->base);
2139                     }
2140                   else
2141                     {
2142                       emitcode ("mov", "%s,a", reg->name);
2143                     }
2144                 }
2145             }
2146           emitcode ("mov", "%s,r0", spname);
2147           if (bitVectBitValue (rsave, R0_IDX))
2148             {
2149               emitcode ("pop", "ar0");
2150             }
2151         }
2152     }
2153   else
2154     {
2155       bool bits_popped = FALSE;
2156       for (i = mcs51_nRegs; i >= 0; i--)
2157         {
2158           if (bitVectBitValue (rsave, i))
2159             {
2160               bits_popped = popReg (i, bits_popped);
2161             }
2162         }
2163     }
2164 }
2165
2166
2167 /*-----------------------------------------------------------------*/
2168 /* pushSide -                                                      */
2169 /*-----------------------------------------------------------------*/
2170 static void
2171 pushSide (operand * oper, int size)
2172 {
2173   int offset = 0;
2174   while (size--)
2175     {
2176       char *l = aopGet (oper, offset++, FALSE, TRUE);
2177       if (AOP_TYPE (oper) != AOP_REG &&
2178           AOP_TYPE (oper) != AOP_DIR &&
2179           strcmp (l, "a"))
2180         {
2181           MOVA (l);
2182           emitcode ("push", "acc");
2183         }
2184       else
2185         {
2186           emitcode ("push", "%s", l);
2187         }
2188     }
2189 }
2190
2191 /*-----------------------------------------------------------------*/
2192 /* assignResultValue - also indicates if acc is in use afterwards  */
2193 /*-----------------------------------------------------------------*/
2194 static bool
2195 assignResultValue (operand * oper, operand * func)
2196 {
2197   int offset = 0;
2198   int size = AOP_SIZE (oper);
2199   bool accuse = FALSE;
2200
2201   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2202     {
2203       outBitC (oper);
2204       return FALSE;
2205     }
2206
2207   while (size--)
2208     {
2209       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2210       offset++;
2211     }
2212   return accuse;
2213 }
2214
2215
2216 /*-----------------------------------------------------------------*/
2217 /* genXpush - pushes onto the external stack                       */
2218 /*-----------------------------------------------------------------*/
2219 static void
2220 genXpush (iCode * ic)
2221 {
2222   asmop *aop = newAsmop (0);
2223   regs *r;
2224   int size, offset = 0;
2225
2226   D(emitcode (";     genXpush",""));
2227
2228   aopOp (IC_LEFT (ic), ic, FALSE);
2229   r = getFreePtr (ic, &aop, FALSE);
2230
2231   size = AOP_SIZE (IC_LEFT (ic));
2232
2233   if (size == 1)
2234     {
2235       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2236       emitcode ("mov", "%s,%s", r->name, spname);
2237       emitcode ("inc", "%s", spname); // allocate space first
2238       emitcode ("movx", "@%s,a", r->name);
2239     }
2240   else
2241     {
2242       // allocate space first
2243       emitcode ("mov", "%s,%s", r->name, spname);
2244       MOVA (r->name);
2245       emitcode ("add", "a,#%d", size);
2246       emitcode ("mov", "%s,a", spname);
2247
2248       while (size--)
2249         {
2250           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2251           emitcode ("movx", "@%s,a", r->name);
2252           emitcode ("inc", "%s", r->name);
2253         }
2254     }
2255
2256   freeAsmop (NULL, aop, ic, TRUE);
2257   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2258 }
2259
2260 /*-----------------------------------------------------------------*/
2261 /* genIpush - generate code for pushing this gets a little complex */
2262 /*-----------------------------------------------------------------*/
2263 static void
2264 genIpush (iCode * ic)
2265 {
2266   int size, offset = 0;
2267   char *l;
2268   char *prev = "";
2269
2270   D(emitcode (";     genIpush",""));
2271
2272   /* if this is not a parm push : ie. it is spill push
2273      and spill push is always done on the local stack */
2274   if (!ic->parmPush)
2275     {
2276
2277       /* and the item is spilt then do nothing */
2278       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2279         return;
2280
2281       aopOp (IC_LEFT (ic), ic, FALSE);
2282       size = AOP_SIZE (IC_LEFT (ic));
2283       /* push it on the stack */
2284       while (size--)
2285         {
2286           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2287           if (*l == '#')
2288             {
2289               MOVA (l);
2290               l = "acc";
2291             }
2292           emitcode ("push", "%s", l);
2293         }
2294       return;
2295     }
2296
2297   /* this is a parameter push: in this case we call
2298      the routine to find the call and save those
2299      registers that need to be saved */
2300   saveRegisters (ic);
2301
2302   /* if use external stack then call the external
2303      stack pushing routine */
2304   if (options.useXstack)
2305     {
2306       genXpush (ic);
2307       return;
2308     }
2309
2310   /* then do the push */
2311   aopOp (IC_LEFT (ic), ic, FALSE);
2312
2313   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2314   size = AOP_SIZE (IC_LEFT (ic));
2315
2316   while (size--)
2317     {
2318       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2319       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2320           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2321           strcmp (l, "a"))
2322         {
2323           if (strcmp (l, prev) || *l == '@')
2324             MOVA (l);
2325           emitcode ("push", "acc");
2326         }
2327       else
2328         {
2329           emitcode ("push", "%s", l);
2330         }
2331       prev = l;
2332     }
2333
2334   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2335 }
2336
2337 /*-----------------------------------------------------------------*/
2338 /* genIpop - recover the registers: can happen only for spilling   */
2339 /*-----------------------------------------------------------------*/
2340 static void
2341 genIpop (iCode * ic)
2342 {
2343   int size, offset;
2344
2345   D(emitcode (";     genIpop",""));
2346
2347   /* if the temp was not pushed then */
2348   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2349     return;
2350
2351   aopOp (IC_LEFT (ic), ic, FALSE);
2352   size = AOP_SIZE (IC_LEFT (ic));
2353   offset = (size - 1);
2354   while (size--)
2355     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2356                                    FALSE, TRUE));
2357
2358   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2359 }
2360
2361 /*-----------------------------------------------------------------*/
2362 /* saveRBank - saves an entire register bank on the stack          */
2363 /*-----------------------------------------------------------------*/
2364 static void
2365 saveRBank (int bank, iCode * ic, bool pushPsw)
2366 {
2367   int i;
2368   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2369   asmop *aop = NULL;
2370   regs *r = NULL;
2371
2372   if (options.useXstack)
2373     {
2374       if (!ic)
2375       {
2376           /* Assume r0 is available for use. */
2377           r = mcs51_regWithIdx (R0_IDX);;
2378       }
2379       else
2380       {
2381           aop = newAsmop (0);
2382           r = getFreePtr (ic, &aop, FALSE);
2383       }
2384       // allocate space first
2385       emitcode ("mov", "%s,%s", r->name, spname);
2386       MOVA (r->name);
2387       emitcode ("add", "a,#%d", count);
2388       emitcode ("mov", "%s,a", spname);
2389     }
2390
2391   for (i = 0; i < mcs51_nRegs; i++)
2392     {
2393       if (options.useXstack)
2394         {
2395           emitcode ("mov", "a,(%s+%d)",
2396                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2397           emitcode ("movx", "@%s,a", r->name);
2398           if (--count)
2399             emitcode ("inc", "%s", r->name);
2400         }
2401       else
2402         emitcode ("push", "(%s+%d)",
2403                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2404     }
2405
2406   if (pushPsw)
2407     {
2408       if (options.useXstack)
2409         {
2410           emitcode ("mov", "a,psw");
2411           emitcode ("movx", "@%s,a", r->name);
2412
2413         }
2414       else
2415         {
2416           emitcode ("push", "psw");
2417         }
2418
2419       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2420     }
2421
2422   if (aop)
2423     {
2424       freeAsmop (NULL, aop, ic, TRUE);
2425     }
2426
2427   if (ic)
2428   {
2429     ic->bankSaved = 1;
2430   }
2431 }
2432
2433 /*-----------------------------------------------------------------*/
2434 /* unsaveRBank - restores the register bank from stack             */
2435 /*-----------------------------------------------------------------*/
2436 static void
2437 unsaveRBank (int bank, iCode * ic, bool popPsw)
2438 {
2439   int i;
2440   asmop *aop = NULL;
2441   regs *r = NULL;
2442
2443   if (options.useXstack)
2444     {
2445       if (!ic)
2446         {
2447           /* Assume r0 is available for use. */
2448           r = mcs51_regWithIdx (R0_IDX);;
2449         }
2450       else
2451         {
2452           aop = newAsmop (0);
2453           r = getFreePtr (ic, &aop, FALSE);
2454         }
2455       emitcode ("mov", "%s,%s", r->name, spname);
2456     }
2457
2458   if (popPsw)
2459     {
2460       if (options.useXstack)
2461         {
2462           emitcode ("dec", "%s", r->name);
2463           emitcode ("movx", "a,@%s", r->name);
2464           emitcode ("mov", "psw,a");
2465         }
2466       else
2467         {
2468           emitcode ("pop", "psw");
2469         }
2470     }
2471
2472   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2473     {
2474       if (options.useXstack)
2475         {
2476           emitcode ("dec", "%s", r->name);
2477           emitcode ("movx", "a,@%s", r->name);
2478           emitcode ("mov", "(%s+%d),a",
2479                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2480         }
2481       else
2482         {
2483           emitcode ("pop", "(%s+%d)",
2484                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2485         }
2486     }
2487
2488   if (options.useXstack)
2489     {
2490       emitcode ("mov", "%s,%s", spname, r->name);
2491     }
2492
2493   if (aop)
2494     {
2495       freeAsmop (NULL, aop, ic, TRUE);
2496     }
2497 }
2498
2499 /*-----------------------------------------------------------------*/
2500 /* genSend - gen code for SEND                                     */
2501 /*-----------------------------------------------------------------*/
2502 static void genSend(set *sendSet)
2503 {
2504   iCode *sic;
2505   int bit_count = 0;
2506
2507   /* first we do all bit parameters */
2508   for (sic = setFirstItem (sendSet); sic;
2509        sic = setNextItem (sendSet))
2510     {
2511       aopOp (IC_LEFT (sic), sic, FALSE);
2512
2513       if (sic->argreg > 12)
2514         {
2515           int bit = sic->argreg-13;
2516
2517           /* if left is a literal then
2518              we know what the value is */
2519           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2520             {
2521               if (((int) operandLitValue (IC_LEFT (sic))))
2522                   emitcode ("setb", "b[%d]", bit);
2523               else
2524                   emitcode ("clr", "b[%d]", bit);
2525             }
2526           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2527             {
2528               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2529                 if (strcmp (l, "c"))
2530                     emitcode ("mov", "c,%s", l);
2531                 emitcode ("mov", "b[%d],c", bit);
2532             }
2533           else
2534             {
2535               /* we need to or */
2536               toBoolean (IC_LEFT (sic));
2537               /* set C, if a >= 1 */
2538               emitcode ("add", "a,#0xff");
2539               emitcode ("mov", "b[%d],c", bit);
2540             }
2541           bit_count++;
2542           BitBankUsed = 1;
2543         }
2544       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2545     }
2546
2547   if (bit_count)
2548     {
2549       saveRegisters (setFirstItem (sendSet));
2550       emitcode ("mov", "bits,b");
2551     }
2552
2553   /* then we do all other parameters */
2554   for (sic = setFirstItem (sendSet); sic;
2555        sic = setNextItem (sendSet))
2556     {
2557       int size, offset = 0;
2558       aopOp (IC_LEFT (sic), sic, FALSE);
2559       size = AOP_SIZE (IC_LEFT (sic));
2560
2561       if (sic->argreg == 1)
2562         {
2563           while (size--)
2564             {
2565               char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2566               if (strcmp (l, fReturn[offset]))
2567                   emitcode ("mov", "%s,%s", fReturn[offset], l);
2568               offset++;
2569             }
2570         }
2571       else if (sic->argreg <= 12)
2572         {
2573           while (size--)
2574             {
2575               emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2576                         aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2577               offset++;
2578             }
2579         }
2580       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2581     }
2582 }
2583
2584 /*-----------------------------------------------------------------*/
2585 /* selectRegBank - emit code to select the register bank           */
2586 /*-----------------------------------------------------------------*/
2587 static void
2588 selectRegBank (short bank, bool keepFlags)
2589 {
2590   /* if f.e. result is in carry */
2591   if (keepFlags)
2592     {
2593       emitcode ("anl", "psw,#0xE7");
2594       if (bank)
2595         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2596     }
2597   else
2598     {
2599       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2600     }
2601 }
2602
2603 /*-----------------------------------------------------------------*/
2604 /* genCall - generates a call statement                            */
2605 /*-----------------------------------------------------------------*/
2606 static void
2607 genCall (iCode * ic)
2608 {
2609   sym_link *dtype;
2610   sym_link *etype;
2611 //  bool restoreBank = FALSE;
2612   bool swapBanks = FALSE;
2613   bool accuse = FALSE;
2614   bool accPushed = FALSE;
2615   bool resultInF0 = FALSE;
2616
2617   D(emitcode(";     genCall",""));
2618
2619   dtype = operandType (IC_LEFT (ic));
2620   etype = getSpec(dtype);
2621   /* if send set is not empty then assign */
2622   if (_G.sendSet)
2623     {
2624         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2625             genSend(reverseSet(_G.sendSet));
2626         } else {
2627             genSend(_G.sendSet);
2628         }
2629
2630       _G.sendSet = NULL;
2631     }
2632
2633   /* if we are calling a not _naked function that is not using
2634      the same register bank then we need to save the
2635      destination registers on the stack */
2636   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2637       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2638        !IFFUNC_ISISR (dtype))
2639     {
2640       swapBanks = TRUE;
2641     }
2642
2643   /* if caller saves & we have not saved then */
2644   if (!ic->regsSaved)
2645       saveRegisters (ic);
2646
2647   if (swapBanks)
2648     {
2649         emitcode ("mov", "psw,#0x%02x",
2650            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2651     }
2652
2653   /* make the call */
2654   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2655     {
2656       if (IFFUNC_CALLEESAVES(dtype))
2657         {
2658           werror (E_BANKED_WITH_CALLEESAVES);
2659         }
2660       else
2661         {
2662           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2663                      OP_SYMBOL (IC_LEFT (ic))->rname :
2664                      OP_SYMBOL (IC_LEFT (ic))->name);
2665
2666           emitcode ("mov", "r0,#%s", l);
2667           emitcode ("mov", "r1,#(%s >> 8)", l);
2668           emitcode ("mov", "r2,#(%s >> 16)", l);
2669           emitcode ("lcall", "__sdcc_banked_call");
2670         }
2671     }
2672   else
2673     {
2674       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2675                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2676                                 OP_SYMBOL (IC_LEFT (ic))->name));
2677     }
2678
2679   if (swapBanks)
2680     {
2681       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2682     }
2683
2684   /* if we need assign a result value */
2685   if ((IS_ITEMP (IC_RESULT (ic)) &&
2686        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2687        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2688         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2689         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2690       IS_TRUE_SYMOP (IC_RESULT (ic)))
2691     {
2692
2693       _G.accInUse++;
2694       aopOp (IC_RESULT (ic), ic, FALSE);
2695       _G.accInUse--;
2696
2697       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2698
2699       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2700     }
2701
2702   /* adjust the stack for parameters if required */
2703   if (ic->parmBytes)
2704     {
2705       int i;
2706       if (ic->parmBytes > 3)
2707         {
2708           if (accuse)
2709             {
2710               emitcode ("push", "acc");
2711               accPushed = TRUE;
2712             }
2713           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2714               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2715             {
2716               emitcode ("mov", "F0,c");
2717               resultInF0 = TRUE;
2718             }
2719
2720           emitcode ("mov", "a,%s", spname);
2721           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2722           emitcode ("mov", "%s,a", spname);
2723
2724           /* unsaveRegisters from xstack needs acc, but */
2725           /* unsaveRegisters from stack needs this popped */
2726           if (accPushed && !options.useXstack)
2727             {
2728               emitcode ("pop", "acc");
2729               accPushed = FALSE;
2730             }
2731         }
2732       else
2733         for (i = 0; i < ic->parmBytes; i++)
2734           emitcode ("dec", "%s", spname);
2735     }
2736
2737   /* if we had saved some registers then unsave them */
2738   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2739     {
2740       if (accuse && !accPushed && options.useXstack)
2741         {
2742           /* xstack needs acc, but doesn't touch normal stack */
2743           emitcode ("push", "acc");
2744           accPushed = TRUE;
2745         }
2746       unsaveRegisters (ic);
2747     }
2748
2749 //  /* if register bank was saved then pop them */
2750 //  if (restoreBank)
2751 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2752
2753   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2754     {
2755       if (resultInF0)
2756           emitcode ("mov", "c,F0");
2757
2758       aopOp (IC_RESULT (ic), ic, FALSE);
2759       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2760       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2761     }
2762
2763   if (accPushed)
2764     emitcode ("pop", "acc");
2765 }
2766
2767 /*-----------------------------------------------------------------*/
2768 /* -10l - generates a call by pointer statement                */
2769 /*-----------------------------------------------------------------*/
2770 static void
2771 genPcall (iCode * ic)
2772 {
2773   sym_link *dtype;
2774   sym_link *etype;
2775   symbol *rlbl = newiTempLabel (NULL);
2776 //  bool restoreBank=FALSE;
2777   bool swapBanks = FALSE;
2778   bool resultInF0 = FALSE;
2779
2780   D(emitcode(";     genPCall",""));
2781
2782   dtype = operandType (IC_LEFT (ic))->next;
2783   etype = getSpec(dtype);
2784   /* if caller saves & we have not saved then */
2785   if (!ic->regsSaved)
2786     saveRegisters (ic);
2787
2788   /* if we are calling a not _naked function that is not using
2789      the same register bank then we need to save the
2790      destination registers on the stack */
2791   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2792       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2793       !IFFUNC_ISISR (dtype))
2794     {
2795 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2796 //    restoreBank=TRUE;
2797       swapBanks = TRUE;
2798       // need caution message to user here
2799     }
2800
2801   if (IS_LITERAL(etype))
2802     {
2803       /* if send set is not empty then assign */
2804       if (_G.sendSet)
2805         {
2806           genSend(reverseSet(_G.sendSet));
2807           _G.sendSet = NULL;
2808         }
2809
2810       if (swapBanks)
2811         {
2812           emitcode ("mov", "psw,#0x%02x",
2813            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2814         }
2815
2816       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2817         {
2818           if (IFFUNC_CALLEESAVES(dtype))
2819             {
2820               werror (E_BANKED_WITH_CALLEESAVES);
2821             }
2822           else
2823             {
2824               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2825
2826               emitcode ("mov", "r0,#%s", l);
2827               emitcode ("mov", "r1,#(%s >> 8)", l);
2828               emitcode ("mov", "r2,#(%s >> 16)", l);
2829               emitcode ("lcall", "__sdcc_banked_call");
2830             }
2831         }
2832       else
2833         {
2834           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2835         }
2836     }
2837   else
2838     {
2839       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2840         {
2841           if (IFFUNC_CALLEESAVES(dtype))
2842             {
2843               werror (E_BANKED_WITH_CALLEESAVES);
2844             }
2845           else
2846             {
2847               aopOp (IC_LEFT (ic), ic, FALSE);
2848
2849               if (!swapBanks)
2850                 {
2851                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2852                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2853                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2854                 }
2855               else
2856                 {
2857                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2858                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2859                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2860                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2861                 }
2862
2863               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2864
2865               /* if send set is not empty then assign */
2866               if (_G.sendSet)
2867                 {
2868                   genSend(reverseSet(_G.sendSet));
2869                   _G.sendSet = NULL;
2870                 }
2871
2872               if (swapBanks)
2873                 {
2874                   emitcode ("mov", "psw,#0x%02x",
2875                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2876                 }
2877
2878               /* make the call */
2879               emitcode ("lcall", "__sdcc_banked_call");
2880             }
2881         }
2882       else
2883         {
2884           /* push the return address on to the stack */
2885           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2886           emitcode ("push", "acc");
2887           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2888           emitcode ("push", "acc");
2889
2890           /* now push the calling address */
2891           aopOp (IC_LEFT (ic), ic, FALSE);
2892
2893           pushSide (IC_LEFT (ic), FPTRSIZE);
2894
2895           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2896
2897           /* if send set is not empty the assign */
2898           if (_G.sendSet)
2899             {
2900               genSend(reverseSet(_G.sendSet));
2901               _G.sendSet = NULL;
2902             }
2903
2904           if (swapBanks)
2905             {
2906               emitcode ("mov", "psw,#0x%02x",
2907                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2908             }
2909
2910           /* make the call */
2911           emitcode ("ret", "");
2912           emitcode ("", "%05d$:", (rlbl->key + 100));
2913         }
2914     }
2915   if (swapBanks)
2916     {
2917       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2918     }
2919
2920   /* if we need assign a result value */
2921   if ((IS_ITEMP (IC_RESULT (ic)) &&
2922        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2923        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2924         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2925       IS_TRUE_SYMOP (IC_RESULT (ic)))
2926     {
2927
2928       _G.accInUse++;
2929       aopOp (IC_RESULT (ic), ic, FALSE);
2930       _G.accInUse--;
2931
2932       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2933
2934       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2935     }
2936
2937   /* adjust the stack for parameters if required */
2938   if (ic->parmBytes)
2939     {
2940       int i;
2941       if (ic->parmBytes > 3)
2942         {
2943           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2944               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2945             {
2946               emitcode ("mov", "F0,c");
2947               resultInF0 = TRUE;
2948             }
2949
2950           emitcode ("mov", "a,%s", spname);
2951           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2952           emitcode ("mov", "%s,a", spname);
2953         }
2954       else
2955         for (i = 0; i < ic->parmBytes; i++)
2956           emitcode ("dec", "%s", spname);
2957
2958     }
2959
2960 //  /* if register bank was saved then unsave them */
2961 //  if (restoreBank)
2962 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2963
2964   /* if we had saved some registers then unsave them */
2965   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2966     unsaveRegisters (ic);
2967
2968   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2969     {
2970       if (resultInF0)
2971           emitcode ("mov", "c,F0");
2972
2973       aopOp (IC_RESULT (ic), ic, FALSE);
2974       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2975       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2976     }
2977 }
2978
2979 /*-----------------------------------------------------------------*/
2980 /* resultRemat - result  is rematerializable                       */
2981 /*-----------------------------------------------------------------*/
2982 static int
2983 resultRemat (iCode * ic)
2984 {
2985   if (SKIP_IC (ic) || ic->op == IFX)
2986     return 0;
2987
2988   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2989     {
2990       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2991       if (sym->remat && !POINTER_SET (ic))
2992         return 1;
2993     }
2994
2995   return 0;
2996 }
2997
2998 #if defined(__BORLANDC__) || defined(_MSC_VER)
2999 #define STRCASECMP stricmp
3000 #else
3001 #define STRCASECMP strcasecmp
3002 #endif
3003
3004 /*-----------------------------------------------------------------*/
3005 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3006 /*-----------------------------------------------------------------*/
3007 static int
3008 regsCmp(void *p1, void *p2)
3009 {
3010   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3011 }
3012
3013 static bool
3014 inExcludeList (char *s)
3015 {
3016   const char *p = setFirstItem(options.excludeRegsSet);
3017
3018   if (p == NULL || STRCASECMP(p, "none") == 0)
3019     return FALSE;
3020
3021
3022   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3023 }
3024
3025 /*-----------------------------------------------------------------*/
3026 /* genFunction - generated code for function entry                 */
3027 /*-----------------------------------------------------------------*/
3028 static void
3029 genFunction (iCode * ic)
3030 {
3031   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3032   sym_link *ftype;
3033   bool     switchedPSW = FALSE;
3034   int      calleesaves_saved_register = -1;
3035   int      stackAdjust = sym->stack;
3036   int      accIsFree = sym->recvSize < 4;
3037   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3038   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3039
3040   _G.nRegsSaved = 0;
3041   /* create the function header */
3042   emitcode (";", "-----------------------------------------");
3043   emitcode (";", " function %s", sym->name);
3044   emitcode (";", "-----------------------------------------");
3045
3046   emitcode ("", "%s:", sym->rname);
3047   ftype = operandType (IC_LEFT (ic));
3048   _G.currentFunc = sym;
3049
3050   if (IFFUNC_ISNAKED(ftype))
3051   {
3052       emitcode(";", "naked function: no prologue.");
3053       return;
3054   }
3055
3056   /* here we need to generate the equates for the
3057      register bank if required */
3058   if (FUNC_REGBANK (ftype) != rbank)
3059     {
3060       int i;
3061
3062       rbank = FUNC_REGBANK (ftype);
3063       for (i = 0; i < mcs51_nRegs; i++)
3064         {
3065           if (regs8051[i].type != REG_BIT)
3066             {
3067               if (strcmp (regs8051[i].base, "0") == 0)
3068                 emitcode ("", "%s = 0x%02x",
3069                           regs8051[i].dname,
3070                           8 * rbank + regs8051[i].offset);
3071               else
3072                 emitcode ("", "%s = %s + 0x%02x",
3073                           regs8051[i].dname,
3074                           regs8051[i].base,
3075                           8 * rbank + regs8051[i].offset);
3076             }
3077         }
3078     }
3079
3080   /* if this is an interrupt service routine then
3081      save acc, b, dpl, dph  */
3082   if (IFFUNC_ISISR (sym->type))
3083     {
3084
3085       if (!inExcludeList ("acc"))
3086         emitcode ("push", "acc");
3087       if (!inExcludeList ("b"))
3088         emitcode ("push", "b");
3089       if (!inExcludeList ("dpl"))
3090         emitcode ("push", "dpl");
3091       if (!inExcludeList ("dph"))
3092         emitcode ("push", "dph");
3093       /* if this isr has no bank i.e. is going to
3094          run with bank 0 , then we need to save more
3095          registers :-) */
3096       if (!FUNC_REGBANK (sym->type))
3097         {
3098
3099           /* if this function does not call any other
3100              function then we can be economical and
3101              save only those registers that are used */
3102           if (!IFFUNC_HASFCALL(sym->type))
3103             {
3104               int i;
3105
3106               /* if any registers used */
3107               if (sym->regsUsed)
3108                 {
3109                   bool bits_pushed = FALSE;
3110                   /* save the registers used */
3111                   for (i = 0; i < sym->regsUsed->size; i++)
3112                     {
3113                       if (bitVectBitValue (sym->regsUsed, i))
3114                         bits_pushed = pushReg (i, bits_pushed);
3115                     }
3116                 }
3117             }
3118           else
3119             {
3120
3121               /* this function has a function call. We cannot
3122                  determines register usage so we will have to push the
3123                  entire bank */
3124                 saveRBank (0, ic, FALSE);
3125                 if (options.parms_in_bank1) {
3126                     int i;
3127                     for (i=0; i < 8 ; i++ ) {
3128                         emitcode ("push","%s",rb1regs[i]);
3129                     }
3130                 }
3131             }
3132         }
3133         else
3134         {
3135             /* This ISR uses a non-zero bank.
3136              *
3137              * We assume that the bank is available for our
3138              * exclusive use.
3139              *
3140              * However, if this ISR calls a function which uses some
3141              * other bank, we must save that bank entirely.
3142              */
3143             unsigned long banksToSave = 0;
3144
3145             if (IFFUNC_HASFCALL(sym->type))
3146             {
3147
3148 #define MAX_REGISTER_BANKS 4
3149
3150                 iCode *i;
3151                 int ix;
3152
3153                 for (i = ic; i; i = i->next)
3154                 {
3155                     if (i->op == ENDFUNCTION)
3156                     {
3157                         /* we got to the end OK. */
3158                         break;
3159                     }
3160
3161                     if (i->op == CALL)
3162                     {
3163                         sym_link *dtype;
3164
3165                         dtype = operandType (IC_LEFT(i));
3166                         if (dtype
3167                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3168                         {
3169                              /* Mark this bank for saving. */
3170                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3171                              {
3172                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3173                              }
3174                              else
3175                              {
3176                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3177                              }
3178
3179                              /* And note that we don't need to do it in
3180                               * genCall.
3181                               */
3182                              i->bankSaved = 1;
3183                         }
3184                     }
3185                     if (i->op == PCALL)
3186                     {
3187                         /* This is a mess; we have no idea what
3188                          * register bank the called function might
3189                          * use.
3190                          *
3191                          * The only thing I can think of to do is
3192                          * throw a warning and hope.
3193                          */
3194                         werror(W_FUNCPTR_IN_USING_ISR);
3195                     }
3196                 }
3197
3198                 if (banksToSave && options.useXstack)
3199                 {
3200                     /* Since we aren't passing it an ic,
3201                      * saveRBank will assume r0 is available to abuse.
3202                      *
3203                      * So switch to our (trashable) bank now, so
3204                      * the caller's R0 isn't trashed.
3205                      */
3206                     emitcode ("push", "psw");
3207                     emitcode ("mov", "psw,#0x%02x",
3208                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3209                     switchedPSW = TRUE;
3210                 }
3211
3212                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3213                 {
3214                      if (banksToSave & (1 << ix))
3215                      {
3216                          saveRBank(ix, NULL, FALSE);
3217                      }
3218                 }
3219             }
3220             // TODO: this needs a closer look
3221             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3222         }
3223
3224       /* Set the register bank to the desired value if nothing else */
3225       /* has done so yet. */
3226       if (!switchedPSW)
3227         {
3228           emitcode ("push", "psw");
3229           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3230         }
3231     }
3232   else
3233     {
3234       /* This is a non-ISR function. The caller has already switched register */
3235       /* banks, if necessary, so just handle the callee-saves option. */
3236
3237       /* if callee-save to be used for this function
3238          then save the registers being used in this function */
3239       if (IFFUNC_CALLEESAVES(sym->type))
3240         {
3241           int i;
3242
3243           /* if any registers used */
3244           if (sym->regsUsed)
3245             {
3246               bool bits_pushed = FALSE;
3247               /* save the registers used */
3248               for (i = 0; i < sym->regsUsed->size; i++)
3249                 {
3250                   if (bitVectBitValue (sym->regsUsed, i))
3251                     {
3252                       /* remember one saved register for later usage */
3253                       if (calleesaves_saved_register < 0)
3254                         calleesaves_saved_register = i;
3255                       bits_pushed = pushReg (i, bits_pushed);
3256                       _G.nRegsSaved++;
3257                     }
3258                 }
3259             }
3260         }
3261     }
3262
3263
3264   if (fReentrant)
3265     {
3266       if (options.useXstack)
3267         {
3268           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3269             {
3270               emitcode ("mov", "r0,%s", spname);
3271               emitcode ("inc", "%s", spname);
3272               emitcode ("xch", "a,_bpx");
3273               emitcode ("movx", "@r0,a");
3274               emitcode ("inc", "r0");
3275               emitcode ("mov", "a,r0");
3276               emitcode ("xch", "a,_bpx");
3277             }
3278           if (sym->stack)
3279             {
3280               emitcode ("push", "_bp");     /* save the callers stack  */
3281               emitcode ("mov", "_bp,sp");
3282             }
3283         }
3284       else
3285         {
3286           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3287             {
3288               /* set up the stack */
3289               emitcode ("push", "_bp");     /* save the callers stack  */
3290               emitcode ("mov", "_bp,sp");
3291             }
3292         }
3293     }
3294
3295   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3296   /* before setting up the stack frame completely. */
3297   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3298     {
3299       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3300
3301       if (rsym->isitmp)
3302         {
3303           if (rsym && rsym->regType == REG_CND)
3304             rsym = NULL;
3305           if (rsym && (rsym->accuse || rsym->ruonly))
3306             rsym = NULL;
3307           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3308             rsym = rsym->usl.spillLoc;
3309         }
3310
3311       /* If the RECEIVE operand immediately spills to the first entry on the */
3312       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3313       /* rather than the usual @r0/r1 machinations. */
3314       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3315         {
3316           int ofs;
3317
3318           _G.current_iCode = ric;
3319           D(emitcode (";     genReceive",""));
3320           for (ofs=0; ofs < sym->recvSize; ofs++)
3321             {
3322               if (!strcmp (fReturn[ofs], "a"))
3323                 emitcode ("push", "acc");
3324               else
3325                 emitcode ("push", fReturn[ofs]);
3326             }
3327           stackAdjust -= sym->recvSize;
3328           if (stackAdjust<0)
3329             {
3330               assert (stackAdjust>=0);
3331               stackAdjust = 0;
3332             }
3333           _G.current_iCode = ic;
3334           ric->generated = 1;
3335           accIsFree = 1;
3336         }
3337       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3338       /* to free up the accumulator. */
3339       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3340         {
3341           int ofs;
3342
3343           _G.current_iCode = ric;
3344           D(emitcode (";     genReceive",""));
3345           for (ofs=0; ofs < sym->recvSize; ofs++)
3346             {
3347               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3348             }
3349           _G.current_iCode = ic;
3350           ric->generated = 1;
3351           accIsFree = 1;
3352         }
3353     }
3354
3355   /* adjust the stack for the function */
3356   if (stackAdjust)
3357     {
3358       int i = stackAdjust;
3359       if (i > 256)
3360         werror (W_STACK_OVERFLOW, sym->name);
3361
3362       if (i > 3 && accIsFree)
3363         {
3364           emitcode ("mov", "a,sp");
3365           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3366           emitcode ("mov", "sp,a");
3367         }
3368       else if (i > 5)
3369         {
3370           /* The accumulator is not free, so we will need another register */
3371           /* to clobber. No need to worry about a possible conflict with */
3372           /* the above early RECEIVE optimizations since they would have */
3373           /* freed the accumulator if they were generated. */
3374
3375           if (IFFUNC_CALLEESAVES(sym->type))
3376             {
3377               /* if it's a callee-saves function we need a saved register */
3378               if (calleesaves_saved_register >= 0)
3379                 {
3380                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3381                   emitcode ("mov", "a,sp");
3382                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3383                   emitcode ("mov", "sp,a");
3384                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3385                 }
3386               else
3387                 /* do it the hard way */
3388                 while (i--)
3389                   emitcode ("inc", "sp");
3390             }
3391           else
3392             {
3393               /* not callee-saves, we can clobber r0 */
3394               emitcode ("mov", "r0,a");
3395               emitcode ("mov", "a,sp");
3396               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3397               emitcode ("mov", "sp,a");
3398               emitcode ("mov", "a,r0");
3399             }
3400         }
3401       else
3402         while (i--)
3403           emitcode ("inc", "sp");
3404     }
3405
3406   if (sym->xstack)
3407     {
3408       char i = ((char) sym->xstack & 0xff);
3409
3410       if (i > 3 && accIsFree)
3411         {
3412           emitcode ("mov", "a,_spx");
3413           emitcode ("add", "a,#0x%02x", i);
3414           emitcode ("mov", "_spx,a");
3415         }
3416       else if (i > 5)
3417         {
3418           emitcode ("push", "acc");
3419           emitcode ("mov", "a,_spx");
3420           emitcode ("add", "a,#0x%02x", i);
3421           emitcode ("mov", "_spx,a");
3422           emitcode ("pop", "acc");
3423         }
3424       else
3425         {
3426           while (i--)
3427             emitcode ("inc", "_spx");
3428         }
3429     }
3430
3431   /* if critical function then turn interrupts off */
3432   if (IFFUNC_ISCRITICAL (ftype))
3433     {
3434       symbol *tlbl = newiTempLabel (NULL);
3435       emitcode ("setb", "c");
3436       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3437       emitcode ("clr", "c");
3438       emitcode ("", "%05d$:", (tlbl->key + 100));
3439       emitcode ("push", "psw"); /* save old ea via c in psw */
3440     }
3441 }
3442
3443 /*-----------------------------------------------------------------*/
3444 /* genEndFunction - generates epilogue for functions               */
3445 /*-----------------------------------------------------------------*/
3446 static void
3447 genEndFunction (iCode * ic)
3448 {
3449   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3450   lineNode *lnp = lineCurr;
3451   bitVect  *regsUsed;
3452   bitVect  *regsUsedPrologue;
3453   bitVect  *regsUnneeded;
3454   int      idx;
3455
3456   _G.currentFunc = NULL;
3457   if (IFFUNC_ISNAKED(sym->type))
3458   {
3459       emitcode(";", "naked function: no epilogue.");
3460       if (options.debug && currFunc)
3461         debugFile->writeEndFunction (currFunc, ic, 0);
3462       return;
3463   }
3464
3465   if (IFFUNC_ISCRITICAL (sym->type))
3466     {
3467       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3468         {
3469           emitcode ("rlc", "a");   /* save c in a */
3470           emitcode ("pop", "psw"); /* restore ea via c in psw */
3471           emitcode ("mov", "ea,c");
3472           emitcode ("rrc", "a");   /* restore c from a */
3473         }
3474       else
3475         {
3476           emitcode ("pop", "psw"); /* restore ea via c in psw */
3477           emitcode ("mov", "ea,c");
3478         }
3479     }
3480
3481   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3482     {
3483       if (options.useXstack)
3484         {
3485           if (sym->stack)
3486             {
3487               emitcode ("mov", "sp,_bp");
3488               emitcode ("pop", "_bp");
3489             }
3490           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3491             {
3492               emitcode ("xch", "a,_bpx");
3493               emitcode ("mov", "r0,a");
3494               emitcode ("dec", "r0");
3495               emitcode ("movx", "a,@r0");
3496               emitcode ("xch", "a,_bpx");
3497               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3498             }
3499         }
3500       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3501         {
3502           emitcode ("mov", "sp,_bp");
3503           emitcode ("pop", "_bp");
3504         }
3505     }
3506
3507   /* restore the register bank  */
3508   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3509   {
3510     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3511      || !options.useXstack)
3512     {
3513         /* Special case of ISR using non-zero bank with useXstack
3514          * is handled below.
3515          */
3516         emitcode ("pop", "psw");
3517     }
3518   }
3519
3520   if (IFFUNC_ISISR (sym->type))
3521     {
3522
3523       /* now we need to restore the registers */
3524       /* if this isr has no bank i.e. is going to
3525          run with bank 0 , then we need to save more
3526          registers :-) */
3527       if (!FUNC_REGBANK (sym->type))
3528         {
3529           /* if this function does not call any other
3530              function then we can be economical and
3531              save only those registers that are used */
3532           if (!IFFUNC_HASFCALL(sym->type))
3533             {
3534               int i;
3535
3536               /* if any registers used */
3537               if (sym->regsUsed)
3538                 {
3539                   bool bits_popped = FALSE;
3540                   /* save the registers used */
3541                   for (i = sym->regsUsed->size; i >= 0; i--)
3542                     {
3543                       if (bitVectBitValue (sym->regsUsed, i))
3544                         bits_popped = popReg (i, bits_popped);
3545                     }
3546                 }
3547             }
3548           else
3549             {
3550               if (options.parms_in_bank1) {
3551                   int i;
3552                   for (i = 7 ; i >= 0 ; i-- ) {
3553                       emitcode ("pop","%s",rb1regs[i]);
3554                   }
3555               }
3556               /* this function has  a function call cannot
3557                  determines register usage so we will have to pop the
3558                  entire bank */
3559               unsaveRBank (0, ic, FALSE);
3560             }
3561         }
3562         else
3563         {
3564             /* This ISR uses a non-zero bank.
3565              *
3566              * Restore any register banks saved by genFunction
3567              * in reverse order.
3568              */
3569             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3570             int ix;
3571
3572             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3573             {
3574                 if (savedBanks & (1 << ix))
3575                 {
3576                     unsaveRBank(ix, NULL, FALSE);
3577                 }
3578             }
3579
3580             if (options.useXstack)
3581             {
3582                 /* Restore bank AFTER calling unsaveRBank,
3583                  * since it can trash r0.
3584                  */
3585                 emitcode ("pop", "psw");
3586             }
3587         }
3588
3589       if (!inExcludeList ("dph"))
3590         emitcode ("pop", "dph");
3591       if (!inExcludeList ("dpl"))
3592         emitcode ("pop", "dpl");
3593       if (!inExcludeList ("b"))
3594         emitcode ("pop", "b");
3595       if (!inExcludeList ("acc"))
3596         emitcode ("pop", "acc");
3597
3598       /* if debug then send end of function */
3599       if (options.debug && currFunc)
3600         {
3601           debugFile->writeEndFunction (currFunc, ic, 1);
3602         }
3603
3604       emitcode ("reti", "");
3605     }
3606   else
3607     {
3608       if (IFFUNC_CALLEESAVES(sym->type))
3609         {
3610           int i;
3611
3612           /* if any registers used */
3613           if (sym->regsUsed)
3614             {
3615               /* save the registers used */
3616               for (i = sym->regsUsed->size; i >= 0; i--)
3617                 {
3618                   if (bitVectBitValue (sym->regsUsed, i) ||
3619                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3620                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3621                 }
3622             }
3623           else if (mcs51_ptrRegReq)
3624             {
3625               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3626               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3627             }
3628
3629         }
3630
3631       /* if debug then send end of function */
3632       if (options.debug && currFunc)
3633         {
3634           debugFile->writeEndFunction (currFunc, ic, 1);
3635         }
3636
3637       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3638         {
3639           emitcode ("ljmp", "__sdcc_banked_ret");
3640         }
3641       else
3642         {
3643           emitcode ("ret", "");
3644         }
3645     }
3646
3647   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3648     return;
3649
3650   /* If this was an interrupt handler using bank 0 that called another */
3651   /* function, then all registers must be saved; nothing to optimized. */
3652   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3653       && !FUNC_REGBANK(sym->type))
3654     return;
3655
3656   /* There are no push/pops to optimize if not callee-saves or ISR */
3657   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3658     return;
3659
3660   /* If there were stack parameters, we cannot optimize without also    */
3661   /* fixing all of the stack offsets; this is too dificult to consider. */
3662   if (FUNC_HASSTACKPARM(sym->type))
3663     return;
3664
3665   /* Compute the registers actually used */
3666   regsUsed = newBitVect (mcs51_nRegs);
3667   regsUsedPrologue = newBitVect (mcs51_nRegs);
3668   while (lnp)
3669     {
3670       if (lnp->ic && lnp->ic->op == FUNCTION)
3671         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3672       else
3673         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3674
3675       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3676           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3677         break;
3678       if (!lnp->prev)
3679         break;
3680       lnp = lnp->prev;
3681     }
3682
3683   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3684       && !bitVectBitValue (regsUsed, CND_IDX))
3685     {
3686       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3687       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3688           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3689         bitVectUnSetBit (regsUsed, CND_IDX);
3690     }
3691   else
3692     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3693
3694   /* If this was an interrupt handler that called another function */
3695   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3696   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3697     {
3698       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3699       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3700       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3701       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3702       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3703     }
3704
3705   /* Remove the unneeded push/pops */
3706   regsUnneeded = newBitVect (mcs51_nRegs);
3707   while (lnp)
3708     {
3709       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3710         {
3711           if (!strncmp(lnp->line, "push", 4))
3712             {
3713               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3714               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3715                 {
3716                   connectLine (lnp->prev, lnp->next);
3717                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3718                 }
3719             }
3720           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3721             {
3722               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3723               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3724                 {
3725                   connectLine (lnp->prev, lnp->next);
3726                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3727                 }
3728             }
3729         }
3730       lnp = lnp->next;
3731     }
3732
3733   for (idx = 0; idx < regsUnneeded->size; idx++)
3734     if (bitVectBitValue (regsUnneeded, idx))
3735       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3736
3737   freeBitVect (regsUnneeded);
3738   freeBitVect (regsUsed);
3739   freeBitVect (regsUsedPrologue);
3740 }
3741
3742 /*-----------------------------------------------------------------*/
3743 /* genRet - generate code for return statement                     */
3744 /*-----------------------------------------------------------------*/
3745 static void
3746 genRet (iCode * ic)
3747 {
3748   int size, offset = 0, pushed = 0;
3749
3750   D(emitcode (";     genRet",""));
3751
3752   /* if we have no return value then
3753      just generate the "ret" */
3754   if (!IC_LEFT (ic))
3755     goto jumpret;
3756
3757   /* we have something to return then
3758      move the return value into place */
3759   aopOp (IC_LEFT (ic), ic, FALSE);
3760   size = AOP_SIZE (IC_LEFT (ic));
3761
3762
3763   if (IS_BIT(_G.currentFunc->etype))
3764     {
3765       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3766       size = 0;
3767     }
3768
3769   while (size--)
3770     {
3771       char *l;
3772       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3773         {
3774           /* #NOCHANGE */
3775           l = aopGet (IC_LEFT (ic), offset++,
3776                       FALSE, TRUE);
3777           emitcode ("push", "%s", l);
3778           pushed++;
3779         }
3780       else
3781         {
3782           l = aopGet (IC_LEFT (ic), offset,
3783                       FALSE, FALSE);
3784           if (strcmp (fReturn[offset], l))
3785             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3786         }
3787     }
3788
3789   while (pushed)
3790     {
3791       pushed--;
3792       if (strcmp (fReturn[pushed], "a"))
3793         emitcode ("pop", fReturn[pushed]);
3794       else
3795         emitcode ("pop", "acc");
3796     }
3797   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3798
3799 jumpret:
3800   /* generate a jump to the return label
3801      if the next is not the return statement */
3802   if (!(ic->next && ic->next->op == LABEL &&
3803         IC_LABEL (ic->next) == returnLabel))
3804
3805     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3806
3807 }
3808
3809 /*-----------------------------------------------------------------*/
3810 /* genLabel - generates a label                                    */
3811 /*-----------------------------------------------------------------*/
3812 static void
3813 genLabel (iCode * ic)
3814 {
3815   /* special case never generate */
3816   if (IC_LABEL (ic) == entryLabel)
3817     return;
3818
3819   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3820 }
3821
3822 /*-----------------------------------------------------------------*/
3823 /* genGoto - generates a ljmp                                      */
3824 /*-----------------------------------------------------------------*/
3825 static void
3826 genGoto (iCode * ic)
3827 {
3828   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3829 }
3830
3831 /*-----------------------------------------------------------------*/
3832 /* findLabelBackwards: walks back through the iCode chain looking  */
3833 /* for the given label. Returns number of iCode instructions     */
3834 /* between that label and given ic.          */
3835 /* Returns zero if label not found.          */
3836 /*-----------------------------------------------------------------*/
3837 static int
3838 findLabelBackwards (iCode * ic, int key)
3839 {
3840   int count = 0;
3841
3842   while (ic->prev)
3843     {
3844       ic = ic->prev;
3845       count++;
3846
3847       /* If we have any pushes or pops, we cannot predict the distance.
3848          I don't like this at all, this should be dealt with in the
3849          back-end */
3850       if (ic->op == IPUSH || ic->op == IPOP) {
3851         return 0;
3852       }
3853
3854       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3855         {
3856           return count;
3857         }
3858     }
3859
3860   return 0;
3861 }
3862
3863 /*-----------------------------------------------------------------*/
3864 /* genPlusIncr :- does addition with increment if possible         */
3865 /*-----------------------------------------------------------------*/
3866 static bool
3867 genPlusIncr (iCode * ic)
3868 {
3869   unsigned int icount;
3870   unsigned int size = getDataSize (IC_RESULT (ic));
3871
3872   /* will try to generate an increment */
3873   /* if the right side is not a literal
3874      we cannot */
3875   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3876     return FALSE;
3877
3878   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3879
3880   D(emitcode (";     genPlusIncr",""));
3881
3882   /* if increment >=16 bits in register or direct space */
3883   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3884       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3885       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3886       (size > 1) &&
3887       (icount == 1))
3888     {
3889       symbol *tlbl;
3890       int emitTlbl;
3891       int labelRange;
3892
3893       /* If the next instruction is a goto and the goto target
3894        * is < 10 instructions previous to this, we can generate
3895        * jumps straight to that target.
3896        */
3897       if (ic->next && ic->next->op == GOTO
3898           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3899           && labelRange <= 10)
3900         {
3901           emitcode (";", "tail increment optimized");
3902           tlbl = IC_LABEL (ic->next);
3903           emitTlbl = 0;
3904         }
3905       else
3906         {
3907           tlbl = newiTempLabel (NULL);
3908           emitTlbl = 1;
3909         }
3910       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3911       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3912           IS_AOP_PREG (IC_RESULT (ic)))
3913         emitcode ("cjne", "%s,#0x00,%05d$",
3914                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3915                   tlbl->key + 100);
3916       else
3917         {
3918           emitcode ("clr", "a");
3919           emitcode ("cjne", "a,%s,%05d$",
3920                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3921                     tlbl->key + 100);
3922         }
3923
3924       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3925       if (size > 2)
3926         {
3927           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3928               IS_AOP_PREG (IC_RESULT (ic)))
3929             emitcode ("cjne", "%s,#0x00,%05d$",
3930                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3931                       tlbl->key + 100);
3932           else
3933             emitcode ("cjne", "a,%s,%05d$",
3934                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3935                       tlbl->key + 100);
3936
3937           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3938         }
3939       if (size > 3)
3940         {
3941           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3942               IS_AOP_PREG (IC_RESULT (ic)))
3943             emitcode ("cjne", "%s,#0x00,%05d$",
3944                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3945                       tlbl->key + 100);
3946           else
3947             {
3948               emitcode ("cjne", "a,%s,%05d$",
3949                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3950                         tlbl->key + 100);
3951             }
3952           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
3953         }
3954
3955       if (emitTlbl)
3956         {
3957           emitcode ("", "%05d$:", tlbl->key + 100);
3958         }
3959       return TRUE;
3960     }
3961
3962   /* if result is dptr */
3963   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
3964       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
3965       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
3966       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
3967     {
3968       if (aopGetUsesAcc (IC_LEFT (ic), 0))
3969         return FALSE;
3970
3971       if (icount > 9)
3972         return FALSE;
3973
3974       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
3975         return FALSE;
3976
3977       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
3978       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
3979       while (icount--)
3980         emitcode ("inc", "dptr");
3981
3982       return TRUE;
3983     }
3984
3985   /* if the literal value of the right hand side
3986      is greater than 4 then it is not worth it */
3987   if (icount > 4)
3988     return FALSE;
3989
3990   /* if the sizes are greater than 1 then we cannot */
3991   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3992       AOP_SIZE (IC_LEFT (ic)) > 1)
3993     return FALSE;
3994
3995   /* we can if the aops of the left & result match or
3996      if they are in registers and the registers are the
3997      same */
3998   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3999     {
4000
4001       if (icount > 3)
4002         {
4003           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4004           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4005           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4006         }
4007       else
4008         {
4009
4010           while (icount--)
4011             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4012         }
4013
4014       return TRUE;
4015     }
4016
4017   return FALSE;
4018 }
4019
4020 /*-----------------------------------------------------------------*/
4021 /* outBitAcc - output a bit in acc                                 */
4022 /*-----------------------------------------------------------------*/
4023 static void
4024 outBitAcc (operand * result)
4025 {
4026   symbol *tlbl = newiTempLabel (NULL);
4027   /* if the result is a bit */
4028   if (AOP_TYPE (result) == AOP_CRY)
4029     {
4030       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4031     }
4032   else
4033     {
4034       emitcode ("jz", "%05d$", tlbl->key + 100);
4035       emitcode ("mov", "a,%s", one);
4036       emitcode ("", "%05d$:", tlbl->key + 100);
4037       outAcc (result);
4038     }
4039 }
4040
4041 /*-----------------------------------------------------------------*/
4042 /* genPlusBits - generates code for addition of two bits           */
4043 /*-----------------------------------------------------------------*/
4044 static void
4045 genPlusBits (iCode * ic)
4046 {
4047   D(emitcode (";     genPlusBits",""));
4048
4049   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4050     {
4051       symbol *lbl = newiTempLabel (NULL);
4052       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4053       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4054       emitcode ("cpl", "c");
4055       emitcode ("", "%05d$:", (lbl->key + 100));
4056       outBitC (IC_RESULT (ic));
4057     }
4058   else
4059     {
4060       emitcode ("clr", "a");
4061       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4062       emitcode ("rlc", "a");
4063       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4064       emitcode ("addc", "a,#0x00");
4065       outAcc (IC_RESULT (ic));
4066     }
4067 }
4068
4069 #if 0
4070 /* This is the original version of this code.
4071
4072  * This is being kept around for reference,
4073  * because I am not entirely sure I got it right...
4074  */
4075 static void
4076 adjustArithmeticResult (iCode * ic)
4077 {
4078   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4079       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4080       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4081     aopPut (IC_RESULT (ic),
4082             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4083             2,
4084             isOperandVolatile (IC_RESULT (ic), FALSE));
4085
4086   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4087       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4088       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4089     aopPut (IC_RESULT (ic),
4090             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4091             2,
4092             isOperandVolatile (IC_RESULT (ic), FALSE));
4093
4094   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4095       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4096       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4097       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4098       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4099     {
4100       char buffer[5];
4101       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4102       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4103     }
4104 }
4105 #else
4106 /* This is the pure and virtuous version of this code.
4107  * I'm pretty certain it's right, but not enough to toss the old
4108  * code just yet...
4109  */
4110 static void
4111 adjustArithmeticResult (iCode * ic)
4112 {
4113   if (opIsGptr (IC_RESULT (ic)) &&
4114       opIsGptr (IC_LEFT (ic)) &&
4115       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4116     {
4117       aopPut (IC_RESULT (ic),
4118               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4119               GPTRSIZE - 1,
4120               isOperandVolatile (IC_RESULT (ic), FALSE));
4121     }
4122
4123   if (opIsGptr (IC_RESULT (ic)) &&
4124       opIsGptr (IC_RIGHT (ic)) &&
4125       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4126     {
4127       aopPut (IC_RESULT (ic),
4128               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4129               GPTRSIZE - 1,
4130               isOperandVolatile (IC_RESULT (ic), FALSE));
4131     }
4132
4133   if (opIsGptr (IC_RESULT (ic)) &&
4134       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4135       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4136       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4137       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4138     {
4139       char buffer[5];
4140       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4141       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4142     }
4143 }
4144 #endif
4145
4146 /*-----------------------------------------------------------------*/
4147 /* genPlus - generates code for addition                           */
4148 /*-----------------------------------------------------------------*/
4149 static void
4150 genPlus (iCode * ic)
4151 {
4152   int size, offset = 0;
4153   int skip_bytes = 0;
4154   char *add = "add";
4155   operand *leftOp, *rightOp;
4156   operand * op;
4157
4158   /* special cases :- */
4159
4160   D(emitcode (";     genPlus",""));
4161
4162   aopOp (IC_LEFT (ic), ic, FALSE);
4163   aopOp (IC_RIGHT (ic), ic, FALSE);
4164   aopOp (IC_RESULT (ic), ic, TRUE);
4165
4166   /* if literal, literal on the right or
4167      if left requires ACC or right is already
4168      in ACC */
4169   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4170       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4171       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4172     {
4173       operand *t = IC_RIGHT (ic);
4174       IC_RIGHT (ic) = IC_LEFT (ic);
4175       IC_LEFT (ic) = t;
4176     }
4177
4178   /* if both left & right are in bit
4179      space */
4180   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4181       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4182     {
4183       genPlusBits (ic);
4184       goto release;
4185     }
4186
4187   /* if left in bit space & right literal */
4188   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4189       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4190     {
4191       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4192       /* if result in bit space */
4193       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4194         {
4195           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4196             emitcode ("cpl", "c");
4197           outBitC (IC_RESULT (ic));
4198         }
4199       else
4200         {
4201           size = getDataSize (IC_RESULT (ic));
4202           while (size--)
4203             {
4204               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4205               emitcode ("addc", "a,#00");
4206               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4207             }
4208         }
4209       goto release;
4210     }
4211
4212   /* if I can do an increment instead
4213      of add then GOOD for ME */
4214   if (genPlusIncr (ic) == TRUE)
4215     goto release;
4216
4217   size = getDataSize (IC_RESULT (ic));
4218   leftOp = IC_LEFT(ic);
4219   rightOp = IC_RIGHT(ic);
4220   op=IC_LEFT(ic);
4221
4222   /* if this is an add for an array access
4223      at a 256 byte boundary */
4224   if ( 2 == size
4225        && AOP_TYPE (op) == AOP_IMMD
4226        && IS_SYMOP (op)
4227        && IS_SPEC (OP_SYM_ETYPE (op))
4228        && SPEC_ABSA (OP_SYM_ETYPE (op))
4229        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4230      )
4231     {
4232       D(emitcode (";     genPlus aligned array",""));
4233       aopPut (IC_RESULT (ic),
4234               aopGet (rightOp, 0, FALSE, FALSE),
4235               0,
4236               isOperandVolatile (IC_RESULT (ic), FALSE));
4237
4238       if( 1 == getDataSize (IC_RIGHT (ic)) )
4239         {
4240           aopPut (IC_RESULT (ic),
4241                   aopGet (leftOp, 1, FALSE, FALSE),
4242                   1,
4243                   isOperandVolatile (IC_RESULT (ic), FALSE));
4244         }
4245       else
4246         {
4247           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4248           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4249           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4250         }
4251       goto release;
4252     }
4253
4254   /* if the lower bytes of a literal are zero skip the addition */
4255   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4256     {
4257        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4258               (skip_bytes+1 < size))
4259          {
4260            skip_bytes++;
4261          }
4262        if (skip_bytes)
4263          D(emitcode (";     genPlus shortcut",""));
4264     }
4265
4266   while (size--)
4267     {
4268       if( offset >= skip_bytes )
4269         {
4270           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4271             {
4272               bool pushedB;
4273               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4274               pushedB = pushB ();
4275               emitcode("xch", "a,b");
4276               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4277               emitcode (add, "a,b");
4278               popB (pushedB);
4279             }
4280           else if (aopGetUsesAcc (leftOp, offset))
4281             {
4282               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4283               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4284             }
4285           else
4286             {
4287               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4288               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4289             }
4290           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4291           add = "addc";  /* further adds must propagate carry */
4292         }
4293       else
4294         {
4295           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4296               isOperandVolatile (IC_RESULT (ic), FALSE))
4297             {
4298               /* just move */
4299               aopPut (IC_RESULT (ic),
4300                       aopGet (leftOp, offset, FALSE, FALSE),
4301                       offset,
4302                       isOperandVolatile (IC_RESULT (ic), FALSE));
4303             }
4304         }
4305       offset++;
4306     }
4307
4308   adjustArithmeticResult (ic);
4309
4310 release:
4311   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4312   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4313   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4314 }
4315
4316 /*-----------------------------------------------------------------*/
4317 /* genMinusDec :- does subtraction with decrement if possible      */
4318 /*-----------------------------------------------------------------*/
4319 static bool
4320 genMinusDec (iCode * ic)
4321 {
4322   unsigned int icount;
4323   unsigned int size = getDataSize (IC_RESULT (ic));
4324
4325   /* will try to generate an increment */
4326   /* if the right side is not a literal
4327      we cannot */
4328   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4329     return FALSE;
4330
4331   /* if the literal value of the right hand side
4332      is greater than 4 then it is not worth it */
4333   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4334     return FALSE;
4335
4336   D(emitcode (";     genMinusDec",""));
4337
4338   /* if decrement >=16 bits in register or direct space */
4339   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4340       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4341       (size > 1) &&
4342       (icount == 1))
4343     {
4344       symbol *tlbl;
4345       int emitTlbl;
4346       int labelRange;
4347
4348       /* If the next instruction is a goto and the goto target
4349        * is <= 10 instructions previous to this, we can generate
4350        * jumps straight to that target.
4351        */
4352       if (ic->next && ic->next->op == GOTO
4353           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4354           && labelRange <= 10)
4355         {
4356           emitcode (";", "tail decrement optimized");
4357           tlbl = IC_LABEL (ic->next);
4358           emitTlbl = 0;
4359         }
4360       else
4361         {
4362           tlbl = newiTempLabel (NULL);
4363           emitTlbl = 1;
4364         }
4365
4366       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4367       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4368           IS_AOP_PREG (IC_RESULT (ic)))
4369         emitcode ("cjne", "%s,#0xff,%05d$"
4370                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4371                   ,tlbl->key + 100);
4372       else
4373         {
4374           emitcode ("mov", "a,#0xff");
4375           emitcode ("cjne", "a,%s,%05d$"
4376                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4377                     ,tlbl->key + 100);
4378         }
4379       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4380       if (size > 2)
4381         {
4382           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4383               IS_AOP_PREG (IC_RESULT (ic)))
4384             emitcode ("cjne", "%s,#0xff,%05d$"
4385                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4386                       ,tlbl->key + 100);
4387           else
4388             {
4389               emitcode ("cjne", "a,%s,%05d$"
4390                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4391                         ,tlbl->key + 100);
4392             }
4393           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4394         }
4395       if (size > 3)
4396         {
4397           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4398               IS_AOP_PREG (IC_RESULT (ic)))
4399             emitcode ("cjne", "%s,#0xff,%05d$"
4400                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4401                       ,tlbl->key + 100);
4402           else
4403             {
4404               emitcode ("cjne", "a,%s,%05d$"
4405                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4406                         ,tlbl->key + 100);
4407             }
4408           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4409         }
4410       if (emitTlbl)
4411         {
4412           emitcode ("", "%05d$:", tlbl->key + 100);
4413         }
4414       return TRUE;
4415     }
4416
4417   /* if the sizes are greater than 1 then we cannot */
4418   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4419       AOP_SIZE (IC_LEFT (ic)) > 1)
4420     return FALSE;
4421
4422   /* we can if the aops of the left & result match or
4423      if they are in registers and the registers are the
4424      same */
4425   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4426     {
4427
4428       while (icount--)
4429         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4430
4431       return TRUE;
4432     }
4433
4434   return FALSE;
4435 }
4436
4437 /*-----------------------------------------------------------------*/
4438 /* addSign - complete with sign                                    */
4439 /*-----------------------------------------------------------------*/
4440 static void
4441 addSign (operand * result, int offset, int sign)
4442 {
4443   int size = (getDataSize (result) - offset);
4444   if (size > 0)
4445     {
4446       if (sign)
4447         {
4448           emitcode ("rlc", "a");
4449           emitcode ("subb", "a,acc");
4450           while (size--)
4451             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4452         }
4453       else
4454         while (size--)
4455           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4456     }
4457 }
4458
4459 /*-----------------------------------------------------------------*/
4460 /* genMinusBits - generates code for subtraction  of two bits      */
4461 /*-----------------------------------------------------------------*/
4462 static void
4463 genMinusBits (iCode * ic)
4464 {
4465   symbol *lbl = newiTempLabel (NULL);
4466
4467   D(emitcode (";     genMinusBits",""));
4468
4469   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4470     {
4471       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4472       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4473       emitcode ("cpl", "c");
4474       emitcode ("", "%05d$:", (lbl->key + 100));
4475       outBitC (IC_RESULT (ic));
4476     }
4477   else
4478     {
4479       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4480       emitcode ("subb", "a,acc");
4481       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4482       emitcode ("inc", "a");
4483       emitcode ("", "%05d$:", (lbl->key + 100));
4484       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4485       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4486     }
4487 }
4488
4489 /*-----------------------------------------------------------------*/
4490 /* genMinus - generates code for subtraction                       */
4491 /*-----------------------------------------------------------------*/
4492 static void
4493 genMinus (iCode * ic)
4494 {
4495   int size, offset = 0;
4496
4497   D(emitcode (";     genMinus",""));
4498
4499   aopOp (IC_LEFT (ic), ic, FALSE);
4500   aopOp (IC_RIGHT (ic), ic, FALSE);
4501   aopOp (IC_RESULT (ic), ic, TRUE);
4502
4503   /* special cases :- */
4504   /* if both left & right are in bit space */
4505   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4506       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4507     {
4508       genMinusBits (ic);
4509       goto release;
4510     }
4511
4512   /* if I can do an decrement instead
4513      of subtract then GOOD for ME */
4514   if (genMinusDec (ic) == TRUE)
4515     goto release;
4516
4517   size = getDataSize (IC_RESULT (ic));
4518
4519   /* if literal, add a,#-lit, else normal subb */
4520   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4521     {
4522       unsigned long lit = 0L;
4523       bool useCarry = FALSE;
4524
4525       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4526       lit = -(long) lit;
4527
4528       while (size--)
4529         {
4530           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4531             {
4532             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4533               if (!offset && !size && lit== (unsigned long) -1)
4534                 {
4535                   emitcode ("dec", "a");
4536                 }
4537               else if (!useCarry)
4538                 {
4539                   /* first add without previous c */
4540                   emitcode ("add", "a,#0x%02x",
4541                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4542                   useCarry = TRUE;
4543                 }
4544               else
4545                 {
4546                   emitcode ("addc", "a,#0x%02x",
4547                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4548                 }
4549               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4550             }
4551           else
4552             {
4553               /* no need to add zeroes */
4554               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4555                 {
4556                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4557                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4558                 }
4559               offset++;
4560             }
4561         }
4562     }
4563   else
4564     {
4565       operand *leftOp, *rightOp;
4566
4567       leftOp = IC_LEFT(ic);
4568       rightOp = IC_RIGHT(ic);
4569
4570       while (size--)
4571         {
4572           if (aopGetUsesAcc(rightOp, offset)) {
4573             if (aopGetUsesAcc(leftOp, offset)) {
4574               bool pushedB;
4575
4576               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4577               pushedB = pushB ();
4578               emitcode ("mov", "b,a");
4579               if (offset == 0)
4580                 CLRC;
4581               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4582               emitcode ("subb", "a,b");
4583               popB (pushedB);
4584             } else {
4585               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4586               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4587               if (offset == 0) {
4588                 emitcode( "setb", "c");
4589               }
4590               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4591               emitcode("cpl", "a");
4592             }
4593           } else {
4594             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4595             if (offset == 0)
4596               CLRC;
4597             emitcode ("subb", "a,%s",
4598                       aopGet(rightOp, offset, FALSE, TRUE));
4599           }
4600
4601           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4602         }
4603     }
4604
4605
4606   adjustArithmeticResult (ic);
4607
4608 release:
4609   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4610   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4611   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4612 }
4613
4614
4615 /*-----------------------------------------------------------------*/
4616 /* genMultbits :- multiplication of bits                           */
4617 /*-----------------------------------------------------------------*/
4618 static void
4619 genMultbits (operand * left,
4620              operand * right,
4621              operand * result)
4622 {
4623   D(emitcode (";     genMultbits",""));
4624
4625   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4626   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4627   outBitC (result);
4628 }
4629
4630 /*-----------------------------------------------------------------*/
4631 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4632 /*-----------------------------------------------------------------*/
4633 static void
4634 genMultOneByte (operand * left,
4635                 operand * right,
4636                 operand * result)
4637 {
4638   symbol *lbl;
4639   int size = AOP_SIZE (result);
4640   bool runtimeSign, compiletimeSign;
4641   bool lUnsigned, rUnsigned, pushedB;
4642
4643   D(emitcode (";     genMultOneByte",""));
4644
4645   if (size < 1 || size > 2)
4646     {
4647       /* this should never happen */
4648       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4649                AOP_SIZE(result), __FILE__, lineno);
4650       exit (1);
4651     }
4652
4653   /* (if two literals: the value is computed before) */
4654   /* if one literal, literal on the right */
4655   if (AOP_TYPE (left) == AOP_LIT)
4656     {
4657       operand *t = right;
4658       right = left;
4659       left = t;
4660       /* emitcode (";", "swapped left and right"); */
4661     }
4662   /* if no literal, unsigned on the right: shorter code */
4663   if (   AOP_TYPE (right) != AOP_LIT
4664       && SPEC_USIGN (getSpec (operandType (left))))
4665     {
4666       operand *t = right;
4667       right = left;
4668       left = t;
4669     }
4670
4671   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4672   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4673
4674   pushedB = pushB ();
4675
4676   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4677                    no need to take care about the signedness! */
4678       || (lUnsigned && rUnsigned))
4679     {
4680       /* just an unsigned 8 * 8 = 8 multiply
4681          or 8u * 8u = 16u */
4682       /* emitcode (";","unsigned"); */
4683       /* TODO: check for accumulator clash between left & right aops? */
4684
4685       if (AOP_TYPE (right) == AOP_LIT)
4686         {
4687           /* moving to accumulator first helps peepholes */
4688           MOVA (aopGet (left, 0, FALSE, FALSE));
4689           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4690         }
4691       else
4692         {
4693           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4694           MOVA (aopGet (left, 0, FALSE, FALSE));
4695         }
4696
4697       emitcode ("mul", "ab");
4698       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4699       if (size == 2)
4700         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4701
4702       popB (pushedB);
4703       return;
4704     }
4705
4706   /* we have to do a signed multiply */
4707   /* emitcode (";", "signed"); */
4708
4709   /* now sign adjust for both left & right */
4710
4711   /* let's see what's needed: */
4712   /* apply negative sign during runtime */
4713   runtimeSign = FALSE;
4714   /* negative sign from literals */
4715   compiletimeSign = FALSE;
4716
4717   if (!lUnsigned)
4718     {
4719       if (AOP_TYPE(left) == AOP_LIT)
4720         {
4721           /* signed literal */
4722           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4723           if (val < 0)
4724             compiletimeSign = TRUE;
4725         }
4726       else
4727         /* signed but not literal */
4728         runtimeSign = TRUE;
4729     }
4730
4731   if (!rUnsigned)
4732     {
4733       if (AOP_TYPE(right) == AOP_LIT)
4734         {
4735           /* signed literal */
4736           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4737           if (val < 0)
4738             compiletimeSign ^= TRUE;
4739         }
4740       else
4741         /* signed but not literal */
4742         runtimeSign = TRUE;
4743     }
4744
4745   /* initialize F0, which stores the runtime sign */
4746   if (runtimeSign)
4747     {
4748       if (compiletimeSign)
4749         emitcode ("setb", "F0"); /* set sign flag */
4750       else
4751         emitcode ("clr", "F0"); /* reset sign flag */
4752     }
4753
4754   /* save the signs of the operands */
4755   if (AOP_TYPE(right) == AOP_LIT)
4756     {
4757       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4758
4759       if (!rUnsigned && val < 0)
4760         emitcode ("mov", "b,#0x%02x", -val);
4761       else
4762         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4763     }
4764   else /* ! literal */
4765     {
4766       if (rUnsigned)  /* emitcode (";", "signed"); */
4767
4768         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4769       else
4770         {
4771           MOVA (aopGet (right, 0, FALSE, FALSE));
4772           lbl = newiTempLabel (NULL);
4773           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4774           emitcode ("cpl", "F0"); /* complement sign flag */
4775           emitcode ("cpl", "a");  /* 2's complement */
4776           emitcode ("inc", "a");
4777           emitcode ("", "%05d$:", (lbl->key + 100));
4778           emitcode ("mov", "b,a");
4779         }
4780     }
4781
4782   if (AOP_TYPE(left) == AOP_LIT)
4783     {
4784       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4785
4786       if (!lUnsigned && val < 0)
4787         emitcode ("mov", "a,#0x%02x", -val);
4788       else
4789         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4790     }
4791   else /* ! literal */
4792     {
4793       MOVA (aopGet (left, 0, FALSE, FALSE));
4794
4795       if (!lUnsigned)
4796         {
4797           lbl = newiTempLabel (NULL);
4798           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4799           emitcode ("cpl", "F0"); /* complement sign flag */
4800           emitcode ("cpl", "a"); /* 2's complement */
4801           emitcode ("inc", "a");
4802           emitcode ("", "%05d$:", (lbl->key + 100));
4803         }
4804     }
4805
4806   /* now the multiplication */
4807   emitcode ("mul", "ab");
4808   if (runtimeSign || compiletimeSign)
4809     {
4810       lbl = newiTempLabel (NULL);
4811       if (runtimeSign)
4812         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4813       emitcode ("cpl", "a"); /* lsb 2's complement */
4814       if (size != 2)
4815         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4816       else
4817         {
4818           emitcode ("add", "a,#1"); /* this sets carry flag */
4819           emitcode ("xch", "a,b");
4820           emitcode ("cpl", "a"); /* msb 2's complement */
4821           emitcode ("addc", "a,#0");
4822           emitcode ("xch", "a,b");
4823         }
4824       emitcode ("", "%05d$:", (lbl->key + 100));
4825     }
4826   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4827   if (size == 2)
4828     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4829
4830   popB (pushedB);
4831 }
4832
4833 /*-----------------------------------------------------------------*/
4834 /* genMult - generates code for multiplication                     */
4835 /*-----------------------------------------------------------------*/
4836 static void
4837 genMult (iCode * ic)
4838 {
4839   operand *left = IC_LEFT (ic);
4840   operand *right = IC_RIGHT (ic);
4841   operand *result = IC_RESULT (ic);
4842
4843   D(emitcode (";     genMult",""));
4844
4845   /* assign the amsops */
4846   aopOp (left, ic, FALSE);
4847   aopOp (right, ic, FALSE);
4848   aopOp (result, ic, TRUE);
4849
4850   /* special cases first */
4851   /* both are bits */
4852   if (AOP_TYPE (left) == AOP_CRY &&
4853       AOP_TYPE (right) == AOP_CRY)
4854     {
4855       genMultbits (left, right, result);
4856       goto release;
4857     }
4858
4859   /* if both are of size == 1 */
4860 #if 0 // one of them can be a sloc shared with the result
4861     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4862 #else
4863   if (getSize(operandType(left)) == 1 &&
4864       getSize(operandType(right)) == 1)
4865 #endif
4866     {
4867       genMultOneByte (left, right, result);
4868       goto release;
4869     }
4870
4871   /* should have been converted to function call */
4872     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4873              getSize(OP_SYMBOL(right)->type));
4874   assert (0);
4875
4876 release:
4877   freeAsmop (result, NULL, ic, TRUE);
4878   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4879   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4880 }
4881
4882 /*-----------------------------------------------------------------*/
4883 /* genDivbits :- division of bits                                  */
4884 /*-----------------------------------------------------------------*/
4885 static void
4886 genDivbits (operand * left,
4887             operand * right,
4888             operand * result)
4889 {
4890   char *l;
4891   bool pushedB;
4892
4893   D(emitcode (";     genDivbits",""));
4894
4895   pushedB = pushB ();
4896
4897   /* the result must be bit */
4898   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4899   l = aopGet (left, 0, FALSE, FALSE);
4900
4901   MOVA (l);
4902
4903   emitcode ("div", "ab");
4904   emitcode ("rrc", "a");
4905
4906   popB (pushedB);
4907
4908   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4909 }
4910
4911 /*-----------------------------------------------------------------*/
4912 /* genDivOneByte : 8 bit division                                  */
4913 /*-----------------------------------------------------------------*/
4914 static void
4915 genDivOneByte (operand * left,
4916                operand * right,
4917                operand * result)
4918 {
4919   bool lUnsigned, rUnsigned, pushedB;
4920   bool runtimeSign, compiletimeSign;
4921   symbol *lbl;
4922   int size, offset;
4923
4924   D(emitcode (";     genDivOneByte",""));
4925
4926   /* Why is it necessary that genDivOneByte() can return an int result?
4927      Have a look at:
4928
4929         volatile unsigned char uc;
4930         volatile signed char sc1, sc2;
4931         volatile int i;
4932
4933         uc  = 255;
4934         sc1 = -1;
4935         i = uc / sc1;
4936
4937      Or:
4938
4939         sc1 = -128;
4940         sc2 = -1;
4941         i = sc1 / sc2;
4942
4943      In all cases a one byte result would overflow, the following cast to int
4944      would return the wrong result.
4945
4946      Two possible solution:
4947         a) cast operands to int, if ((unsigned) / (signed)) or
4948            ((signed) / (signed))
4949         b) return an 16 bit signed int; this is what we're doing here!
4950   */
4951
4952   size = AOP_SIZE (result) - 1;
4953   offset = 1;
4954   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4955   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4956
4957   pushedB = pushB ();
4958
4959   /* signed or unsigned */
4960   if (lUnsigned && rUnsigned)
4961     {
4962       /* unsigned is easy */
4963       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4964       MOVA (aopGet (left, 0, FALSE, FALSE));
4965       emitcode ("div", "ab");
4966       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4967       while (size--)
4968         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4969
4970       popB (pushedB);
4971       return;
4972     }
4973
4974   /* signed is a little bit more difficult */
4975
4976   /* now sign adjust for both left & right */
4977
4978   /* let's see what's needed: */
4979   /* apply negative sign during runtime */
4980   runtimeSign = FALSE;
4981   /* negative sign from literals */
4982   compiletimeSign = FALSE;
4983
4984   if (!lUnsigned)
4985     {
4986       if (AOP_TYPE(left) == AOP_LIT)
4987         {
4988           /* signed literal */
4989           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4990           if (val < 0)
4991             compiletimeSign = TRUE;
4992         }
4993       else
4994         /* signed but not literal */
4995         runtimeSign = TRUE;
4996     }
4997
4998   if (!rUnsigned)
4999     {
5000       if (AOP_TYPE(right) == AOP_LIT)
5001         {
5002           /* signed literal */
5003           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5004           if (val < 0)
5005             compiletimeSign ^= TRUE;
5006         }
5007       else
5008         /* signed but not literal */
5009         runtimeSign = TRUE;
5010     }
5011
5012   /* initialize F0, which stores the runtime sign */
5013   if (runtimeSign)
5014     {
5015       if (compiletimeSign)
5016         emitcode ("setb", "F0"); /* set sign flag */
5017       else
5018         emitcode ("clr", "F0"); /* reset sign flag */
5019     }
5020
5021   /* save the signs of the operands */
5022   if (AOP_TYPE(right) == AOP_LIT)
5023     {
5024       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5025
5026       if (!rUnsigned && val < 0)
5027         emitcode ("mov", "b,#0x%02x", -val);
5028       else
5029         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5030     }
5031   else /* ! literal */
5032     {
5033       if (rUnsigned)
5034         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5035       else
5036         {
5037           MOVA (aopGet (right, 0, FALSE, FALSE));
5038           lbl = newiTempLabel (NULL);
5039           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5040           emitcode ("cpl", "F0"); /* complement sign flag */
5041           emitcode ("cpl", "a");  /* 2's complement */
5042           emitcode ("inc", "a");
5043           emitcode ("", "%05d$:", (lbl->key + 100));
5044           emitcode ("mov", "b,a");
5045         }
5046     }
5047
5048   if (AOP_TYPE(left) == AOP_LIT)
5049     {
5050       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5051
5052       if (!lUnsigned && val < 0)
5053         emitcode ("mov", "a,#0x%02x", -val);
5054       else
5055         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5056     }
5057   else /* ! literal */
5058     {
5059       MOVA (aopGet (left, 0, FALSE, FALSE));
5060
5061       if (!lUnsigned)
5062         {
5063           lbl = newiTempLabel (NULL);
5064           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5065           emitcode ("cpl", "F0"); /* complement sign flag */
5066           emitcode ("cpl", "a");  /* 2's complement */
5067           emitcode ("inc", "a");
5068           emitcode ("", "%05d$:", (lbl->key + 100));
5069         }
5070     }
5071
5072   /* now the division */
5073   emitcode ("div", "ab");
5074
5075   if (runtimeSign || compiletimeSign)
5076     {
5077       lbl = newiTempLabel (NULL);
5078       if (runtimeSign)
5079         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5080       emitcode ("cpl", "a"); /* lsb 2's complement */
5081       emitcode ("inc", "a");
5082       emitcode ("", "%05d$:", (lbl->key + 100));
5083
5084       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5085       if (size > 0)
5086         {
5087           /* msb is 0x00 or 0xff depending on the sign */
5088           if (runtimeSign)
5089             {
5090               emitcode ("mov", "c,F0");
5091               emitcode ("subb", "a,acc");
5092               while (size--)
5093                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5094             }
5095           else /* compiletimeSign */
5096             while (size--)
5097               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5098         }
5099     }
5100   else
5101     {
5102       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5103       while (size--)
5104         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5105     }
5106
5107   popB (pushedB);
5108 }
5109
5110 /*-----------------------------------------------------------------*/
5111 /* genDiv - generates code for division                            */
5112 /*-----------------------------------------------------------------*/
5113 static void
5114 genDiv (iCode * ic)
5115 {
5116   operand *left = IC_LEFT (ic);
5117   operand *right = IC_RIGHT (ic);
5118   operand *result = IC_RESULT (ic);
5119
5120   D(emitcode (";     genDiv",""));
5121
5122   /* assign the amsops */
5123   aopOp (left, ic, FALSE);
5124   aopOp (right, ic, FALSE);
5125   aopOp (result, ic, TRUE);
5126
5127   /* special cases first */
5128   /* both are bits */
5129   if (AOP_TYPE (left) == AOP_CRY &&
5130       AOP_TYPE (right) == AOP_CRY)
5131     {
5132       genDivbits (left, right, result);
5133       goto release;
5134     }
5135
5136   /* if both are of size == 1 */
5137   if (AOP_SIZE (left) == 1 &&
5138       AOP_SIZE (right) == 1)
5139     {
5140       genDivOneByte (left, right, result);
5141       goto release;
5142     }
5143
5144   /* should have been converted to function call */
5145   assert (0);
5146 release:
5147   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5148   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5149   freeAsmop (result, NULL, ic, TRUE);
5150 }
5151
5152 /*-----------------------------------------------------------------*/
5153 /* genModbits :- modulus of bits                                   */
5154 /*-----------------------------------------------------------------*/
5155 static void
5156 genModbits (operand * left,
5157             operand * right,
5158             operand * result)
5159 {
5160   char *l;
5161   bool pushedB;
5162
5163   D(emitcode (";     genModbits",""));
5164
5165   pushedB = pushB ();
5166
5167   /* the result must be bit */
5168   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5169   l = aopGet (left, 0, FALSE, FALSE);
5170
5171   MOVA (l);
5172
5173   emitcode ("div", "ab");
5174   emitcode ("mov", "a,b");
5175   emitcode ("rrc", "a");
5176
5177   popB (pushedB);
5178
5179   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5180 }
5181
5182 /*-----------------------------------------------------------------*/
5183 /* genModOneByte : 8 bit modulus                                   */
5184 /*-----------------------------------------------------------------*/
5185 static void
5186 genModOneByte (operand * left,
5187                operand * right,
5188                operand * result)
5189 {
5190   bool lUnsigned, rUnsigned, pushedB;
5191   bool runtimeSign, compiletimeSign;
5192   symbol *lbl;
5193   int size, offset;
5194
5195   D(emitcode (";     genModOneByte",""));
5196
5197   size = AOP_SIZE (result) - 1;
5198   offset = 1;
5199   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5200   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5201
5202   /* if right is a literal, check it for 2^n */
5203   if (AOP_TYPE(right) == AOP_LIT)
5204     {
5205       unsigned char val = abs((int) operandLitValue(right));
5206       symbol *lbl2 = NULL;
5207
5208       switch (val)
5209         {
5210           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5211           case 2:
5212           case 4:
5213           case 8:
5214           case 16:
5215           case 32:
5216           case 64:
5217           case 128:
5218             if (lUnsigned)
5219               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5220                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5221               /* because iCode should have been changed to genAnd  */
5222               /* see file "SDCCopt.c", function "convertToFcall()" */
5223
5224             MOVA (aopGet (left, 0, FALSE, FALSE));
5225             emitcode ("mov", "c,acc.7");
5226             emitcode ("anl", "a,#0x%02x", val - 1);
5227             lbl = newiTempLabel (NULL);
5228             emitcode ("jz", "%05d$", (lbl->key + 100));
5229             emitcode ("jnc", "%05d$", (lbl->key + 100));
5230             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5231             if (size)
5232               {
5233                 int size2 = size;
5234                 int offs2 = offset;
5235
5236                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5237                 while (size2--)
5238                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5239                 lbl2 = newiTempLabel (NULL);
5240                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5241               }
5242             emitcode ("", "%05d$:", (lbl->key + 100));
5243             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5244             while (size--)
5245               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5246             if (lbl2)
5247               {
5248                 emitcode ("", "%05d$:", (lbl2->key + 100));
5249               }
5250             return;
5251
5252           default:
5253             break;
5254         }
5255     }
5256
5257   pushedB = pushB ();
5258
5259   /* signed or unsigned */
5260   if (lUnsigned && rUnsigned)
5261     {
5262       /* unsigned is easy */
5263       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5264       MOVA (aopGet (left, 0, FALSE, FALSE));
5265       emitcode ("div", "ab");
5266       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5267       while (size--)
5268         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5269
5270       popB (pushedB);
5271       return;
5272     }
5273
5274   /* signed is a little bit more difficult */
5275
5276   /* now sign adjust for both left & right */
5277
5278   /* modulus: sign of the right operand has no influence on the result! */
5279   if (AOP_TYPE(right) == AOP_LIT)
5280     {
5281       signed char val = (char) operandLitValue(right);
5282
5283       if (!rUnsigned && val < 0)
5284         emitcode ("mov", "b,#0x%02x", -val);
5285       else
5286         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5287     }
5288   else /* not literal */
5289     {
5290       if (rUnsigned)
5291         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5292       else
5293         {
5294           MOVA (aopGet (right, 0, FALSE, FALSE));
5295           lbl = newiTempLabel (NULL);
5296           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5297           emitcode ("cpl", "a"); /* 2's complement */
5298           emitcode ("inc", "a");
5299           emitcode ("", "%05d$:", (lbl->key + 100));
5300           emitcode ("mov", "b,a");
5301         }
5302     }
5303
5304   /* let's see what's needed: */
5305   /* apply negative sign during runtime */
5306   runtimeSign = FALSE;
5307   /* negative sign from literals */
5308   compiletimeSign = FALSE;
5309
5310   /* sign adjust left side */
5311   if (AOP_TYPE(left) == AOP_LIT)
5312     {
5313       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5314
5315       if (!lUnsigned && val < 0)
5316         {
5317           compiletimeSign = TRUE; /* set sign flag */
5318           emitcode ("mov", "a,#0x%02x", -val);
5319         }
5320       else
5321         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5322     }
5323   else /* ! literal */
5324     {
5325       MOVA (aopGet (left, 0, FALSE, FALSE));
5326
5327       if (!lUnsigned)
5328         {
5329           runtimeSign = TRUE;
5330           emitcode ("clr", "F0"); /* clear sign flag */
5331
5332           lbl = newiTempLabel (NULL);
5333           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5334           emitcode ("setb", "F0"); /* set sign flag */
5335           emitcode ("cpl", "a");   /* 2's complement */
5336           emitcode ("inc", "a");
5337           emitcode ("", "%05d$:", (lbl->key + 100));
5338         }
5339     }
5340
5341   /* now the modulus */
5342   emitcode ("div", "ab");
5343
5344   if (runtimeSign || compiletimeSign)
5345     {
5346       emitcode ("mov", "a,b");
5347       lbl = newiTempLabel (NULL);
5348       if (runtimeSign)
5349         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5350       emitcode ("cpl", "a"); /* 2's complement */
5351       emitcode ("inc", "a");
5352       emitcode ("", "%05d$:", (lbl->key + 100));
5353
5354       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5355       if (size > 0)
5356         {
5357           /* msb is 0x00 or 0xff depending on the sign */
5358           if (runtimeSign)
5359             {
5360               emitcode ("mov", "c,F0");
5361               emitcode ("subb", "a,acc");
5362               while (size--)
5363                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5364             }
5365           else /* compiletimeSign */
5366             while (size--)
5367               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5368         }
5369     }
5370   else
5371     {
5372       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5373       while (size--)
5374         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5375     }
5376
5377   popB (pushedB);
5378 }
5379
5380 /*-----------------------------------------------------------------*/
5381 /* genMod - generates code for division                            */
5382 /*-----------------------------------------------------------------*/
5383 static void
5384 genMod (iCode * ic)
5385 {
5386   operand *left = IC_LEFT (ic);
5387   operand *right = IC_RIGHT (ic);
5388   operand *result = IC_RESULT (ic);
5389
5390   D(emitcode (";     genMod",""));
5391
5392   /* assign the asmops */
5393   aopOp (left, ic, FALSE);
5394   aopOp (right, ic, FALSE);
5395   aopOp (result, ic, TRUE);
5396
5397   /* special cases first */
5398   /* both are bits */
5399   if (AOP_TYPE (left) == AOP_CRY &&
5400       AOP_TYPE (right) == AOP_CRY)
5401     {
5402       genModbits (left, right, result);
5403       goto release;
5404     }
5405
5406   /* if both are of size == 1 */
5407   if (AOP_SIZE (left) == 1 &&
5408       AOP_SIZE (right) == 1)
5409     {
5410       genModOneByte (left, right, result);
5411       goto release;
5412     }
5413
5414   /* should have been converted to function call */
5415   assert (0);
5416
5417 release:
5418   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5419   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5420   freeAsmop (result, NULL, ic, TRUE);
5421 }
5422
5423 /*-----------------------------------------------------------------*/
5424 /* genIfxJump :- will create a jump depending on the ifx           */
5425 /*-----------------------------------------------------------------*/
5426 static void
5427 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5428 {
5429   symbol *jlbl;
5430   symbol *tlbl = newiTempLabel (NULL);
5431   char *inst;
5432
5433   D(emitcode (";     genIfxJump",""));
5434
5435   /* if true label then we jump if condition
5436      supplied is true */
5437   if (IC_TRUE (ic))
5438     {
5439       jlbl = IC_TRUE (ic);
5440       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5441                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5442     }
5443   else
5444     {
5445       /* false label is present */
5446       jlbl = IC_FALSE (ic);
5447       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5448                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5449     }
5450   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5451     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5452   else
5453     emitcode (inst, "%05d$", tlbl->key + 100);
5454   freeForBranchAsmop (result);
5455   freeForBranchAsmop (right);
5456   freeForBranchAsmop (left);
5457   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5458   emitcode ("", "%05d$:", tlbl->key + 100);
5459
5460   /* mark the icode as generated */
5461   ic->generated = 1;
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* genCmp :- greater or less than comparison                       */
5466 /*-----------------------------------------------------------------*/
5467 static void
5468 genCmp (operand * left, operand * right,
5469         operand * result, iCode * ifx, int sign, iCode *ic)
5470 {
5471   int size, offset = 0;
5472   unsigned long lit = 0L;
5473   bool rightInB;
5474
5475   D(emitcode (";     genCmp",""));
5476
5477   /* if left & right are bit variables */
5478   if (AOP_TYPE (left) == AOP_CRY &&
5479       AOP_TYPE (right) == AOP_CRY)
5480     {
5481       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5482       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5483     }
5484   else
5485     {
5486       /* subtract right from left if at the
5487          end the carry flag is set then we know that
5488          left is greater than right */
5489       size = max (AOP_SIZE (left), AOP_SIZE (right));
5490
5491       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5492       if ((size == 1) && !sign &&
5493           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5494         {
5495           symbol *lbl = newiTempLabel (NULL);
5496           emitcode ("cjne", "%s,%s,%05d$",
5497                     aopGet (left, offset, FALSE, FALSE),
5498                     aopGet (right, offset, FALSE, FALSE),
5499                     lbl->key + 100);
5500           emitcode ("", "%05d$:", lbl->key + 100);
5501         }
5502       else
5503         {
5504           if (AOP_TYPE (right) == AOP_LIT)
5505             {
5506               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5507               /* optimize if(x < 0) or if(x >= 0) */
5508               if (lit == 0L)
5509                 {
5510                   if (!sign)
5511                     {
5512                       CLRC;
5513                     }
5514                   else
5515                     {
5516                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5517                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5518                         {
5519                           genIfxJump (ifx, "acc.7", left, right, result);
5520                           freeAsmop (right, NULL, ic, TRUE);
5521                           freeAsmop (left, NULL, ic, TRUE);
5522
5523                           return;
5524                         }
5525                       else
5526                         emitcode ("rlc", "a");
5527                     }
5528                   goto release;
5529                 }
5530             }
5531           CLRC;
5532           while (size--)
5533             {
5534               bool pushedB = FALSE;
5535               rightInB = aopGetUsesAcc(right, offset);
5536               if (rightInB)
5537                 {
5538                   pushedB = pushB ();
5539                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5540                 }
5541               MOVA (aopGet (left, offset, FALSE, FALSE));
5542               if (sign && size == 0)
5543                 {
5544                   emitcode ("xrl", "a,#0x80");
5545                   if (AOP_TYPE (right) == AOP_LIT)
5546                     {
5547                       unsigned long lit = (unsigned long)
5548                       floatFromVal (AOP (right)->aopu.aop_lit);
5549                       emitcode ("subb", "a,#0x%02x",
5550                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5551                     }
5552                   else
5553                     {
5554                       if (!rightInB)
5555                         {
5556                           pushedB = pushB ();
5557                           rightInB++;
5558                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5559                         }
5560                       emitcode ("xrl", "b,#0x80");
5561                       emitcode ("subb", "a,b");
5562                     }
5563                 }
5564               else
5565                 {
5566                   if (rightInB)
5567                     emitcode ("subb", "a,b");
5568                   else
5569                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5570                 }
5571               if (rightInB)
5572                 popB (pushedB);
5573               offset++;
5574             }
5575         }
5576     }
5577
5578 release:
5579   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5580   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5581   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5582     {
5583       outBitC (result);
5584     }
5585   else
5586     {
5587       /* if the result is used in the next
5588          ifx conditional branch then generate
5589          code a little differently */
5590       if (ifx)
5591         genIfxJump (ifx, "c", NULL, NULL, result);
5592       else
5593         outBitC (result);
5594       /* leave the result in acc */
5595     }
5596 }
5597
5598 /*-----------------------------------------------------------------*/
5599 /* genCmpGt :- greater than comparison                             */
5600 /*-----------------------------------------------------------------*/
5601 static void
5602 genCmpGt (iCode * ic, iCode * ifx)
5603 {
5604   operand *left, *right, *result;
5605   sym_link *letype, *retype;
5606   int sign;
5607
5608   D(emitcode (";     genCmpGt",""));
5609
5610   left = IC_LEFT (ic);
5611   right = IC_RIGHT (ic);
5612   result = IC_RESULT (ic);
5613
5614   letype = getSpec (operandType (left));
5615   retype = getSpec (operandType (right));
5616   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5617            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5618   /* assign the amsops */
5619   aopOp (left, ic, FALSE);
5620   aopOp (right, ic, FALSE);
5621   aopOp (result, ic, TRUE);
5622
5623   genCmp (right, left, result, ifx, sign, ic);
5624
5625   freeAsmop (result, NULL, ic, TRUE);
5626 }
5627
5628 /*-----------------------------------------------------------------*/
5629 /* genCmpLt - less than comparisons                                */
5630 /*-----------------------------------------------------------------*/
5631 static void
5632 genCmpLt (iCode * ic, iCode * ifx)
5633 {
5634   operand *left, *right, *result;
5635   sym_link *letype, *retype;
5636   int sign;
5637
5638   D(emitcode (";     genCmpLt",""));
5639
5640   left = IC_LEFT (ic);
5641   right = IC_RIGHT (ic);
5642   result = IC_RESULT (ic);
5643
5644   letype = getSpec (operandType (left));
5645   retype = getSpec (operandType (right));
5646   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5647            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5648   /* assign the amsops */
5649   aopOp (left, ic, FALSE);
5650   aopOp (right, ic, FALSE);
5651   aopOp (result, ic, TRUE);
5652
5653   genCmp (left, right, result, ifx, sign, ic);
5654
5655   freeAsmop (result, NULL, ic, TRUE);
5656 }
5657
5658 /*-----------------------------------------------------------------*/
5659 /* gencjneshort - compare and jump if not equal                    */
5660 /*-----------------------------------------------------------------*/
5661 static void
5662 gencjneshort (operand * left, operand * right, symbol * lbl)
5663 {
5664   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5665   int offset = 0;
5666   unsigned long lit = 0L;
5667
5668   /* if the left side is a literal or
5669      if the right is in a pointer register and left
5670      is not */
5671   if ((AOP_TYPE (left) == AOP_LIT) ||
5672       (AOP_TYPE (left) == AOP_IMMD) ||
5673       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5674     {
5675       operand *t = right;
5676       right = left;
5677       left = t;
5678     }
5679
5680   if (AOP_TYPE (right) == AOP_LIT)
5681     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5682
5683   /* if the right side is a literal then anything goes */
5684   if (AOP_TYPE (right) == AOP_LIT &&
5685       AOP_TYPE (left) != AOP_DIR  &&
5686       AOP_TYPE (left) != AOP_IMMD)
5687     {
5688       while (size--)
5689         {
5690           emitcode ("cjne", "%s,%s,%05d$",
5691                     aopGet (left, offset, FALSE, FALSE),
5692                     aopGet (right, offset, FALSE, FALSE),
5693                     lbl->key + 100);
5694           offset++;
5695         }
5696     }
5697
5698   /* if the right side is in a register or in direct space or
5699      if the left is a pointer register & right is not */
5700   else if (AOP_TYPE (right) == AOP_REG ||
5701            AOP_TYPE (right) == AOP_DIR ||
5702            AOP_TYPE (right) == AOP_LIT ||
5703            AOP_TYPE (right) == AOP_IMMD ||
5704            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5705            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5706     {
5707       while (size--)
5708         {
5709           MOVA (aopGet (left, offset, FALSE, FALSE));
5710           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5711               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5712             emitcode ("jnz", "%05d$", lbl->key + 100);
5713           else
5714             emitcode ("cjne", "a,%s,%05d$",
5715                       aopGet (right, offset, FALSE, TRUE),
5716                       lbl->key + 100);
5717           offset++;
5718         }
5719     }
5720   else
5721     {
5722       /* right is a pointer reg need both a & b */
5723       while (size--)
5724         {
5725           char *l;
5726           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5727           wassertl(!BINUSE, "B was in use");
5728           l = aopGet (left, offset, FALSE, FALSE);
5729           if (strcmp (l, "b"))
5730             emitcode ("mov", "b,%s", l);
5731           MOVA (aopGet (right, offset, FALSE, FALSE));
5732           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5733           offset++;
5734         }
5735     }
5736 }
5737
5738 /*-----------------------------------------------------------------*/
5739 /* gencjne - compare and jump if not equal                         */
5740 /*-----------------------------------------------------------------*/
5741 static void
5742 gencjne (operand * left, operand * right, symbol * lbl)
5743 {
5744   symbol *tlbl = newiTempLabel (NULL);
5745
5746   gencjneshort (left, right, lbl);
5747
5748   emitcode ("mov", "a,%s", one);
5749   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5750   emitcode ("", "%05d$:", lbl->key + 100);
5751   emitcode ("clr", "a");
5752   emitcode ("", "%05d$:", tlbl->key + 100);
5753 }
5754
5755 /*-----------------------------------------------------------------*/
5756 /* genCmpEq - generates code for equal to                          */
5757 /*-----------------------------------------------------------------*/
5758 static void
5759 genCmpEq (iCode * ic, iCode * ifx)
5760 {
5761   operand *left, *right, *result;
5762
5763   D(emitcode (";     genCmpEq",""));
5764
5765   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5766   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5767   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5768
5769   /* if literal, literal on the right or
5770      if the right is in a pointer register and left
5771      is not */
5772   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5773       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5774     {
5775       operand *t = IC_RIGHT (ic);
5776       IC_RIGHT (ic) = IC_LEFT (ic);
5777       IC_LEFT (ic) = t;
5778     }
5779
5780   if (ifx && !AOP_SIZE (result))
5781     {
5782       symbol *tlbl;
5783       /* if they are both bit variables */
5784       if (AOP_TYPE (left) == AOP_CRY &&
5785           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5786         {
5787           if (AOP_TYPE (right) == AOP_LIT)
5788             {
5789               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5790               if (lit == 0L)
5791                 {
5792                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5793                   emitcode ("cpl", "c");
5794                 }
5795               else if (lit == 1L)
5796                 {
5797                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5798                 }
5799               else
5800                 {
5801                   emitcode ("clr", "c");
5802                 }
5803               /* AOP_TYPE(right) == AOP_CRY */
5804             }
5805           else
5806             {
5807               symbol *lbl = newiTempLabel (NULL);
5808               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5809               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5810               emitcode ("cpl", "c");
5811               emitcode ("", "%05d$:", (lbl->key + 100));
5812             }
5813           /* if true label then we jump if condition
5814              supplied is true */
5815           tlbl = newiTempLabel (NULL);
5816           if (IC_TRUE (ifx))
5817             {
5818               emitcode ("jnc", "%05d$", tlbl->key + 100);
5819               freeForBranchAsmop (result);
5820               freeForBranchAsmop (right);
5821               freeForBranchAsmop (left);
5822               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5823             }
5824           else
5825             {
5826               emitcode ("jc", "%05d$", tlbl->key + 100);
5827               freeForBranchAsmop (result);
5828               freeForBranchAsmop (right);
5829               freeForBranchAsmop (left);
5830               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5831             }
5832           emitcode ("", "%05d$:", tlbl->key + 100);
5833         }
5834       else
5835         {
5836           tlbl = newiTempLabel (NULL);
5837           gencjneshort (left, right, tlbl);
5838           if (IC_TRUE (ifx))
5839             {
5840               freeForBranchAsmop (result);
5841               freeForBranchAsmop (right);
5842               freeForBranchAsmop (left);
5843               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5844               emitcode ("", "%05d$:", tlbl->key + 100);
5845             }
5846           else
5847             {
5848               symbol *lbl = newiTempLabel (NULL);
5849               emitcode ("sjmp", "%05d$", lbl->key + 100);
5850               emitcode ("", "%05d$:", tlbl->key + 100);
5851               freeForBranchAsmop (result);
5852               freeForBranchAsmop (right);
5853               freeForBranchAsmop (left);
5854               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5855               emitcode ("", "%05d$:", lbl->key + 100);
5856             }
5857         }
5858       /* mark the icode as generated */
5859       ifx->generated = 1;
5860       goto release;
5861     }
5862
5863   /* if they are both bit variables */
5864   if (AOP_TYPE (left) == AOP_CRY &&
5865       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5866     {
5867       if (AOP_TYPE (right) == AOP_LIT)
5868         {
5869           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5870           if (lit == 0L)
5871             {
5872               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5873               emitcode ("cpl", "c");
5874             }
5875           else if (lit == 1L)
5876             {
5877               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5878             }
5879           else
5880             {
5881               emitcode ("clr", "c");
5882             }
5883           /* AOP_TYPE(right) == AOP_CRY */
5884         }
5885       else
5886         {
5887           symbol *lbl = newiTempLabel (NULL);
5888           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5889           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5890           emitcode ("cpl", "c");
5891           emitcode ("", "%05d$:", (lbl->key + 100));
5892         }
5893       /* c = 1 if egal */
5894       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5895         {
5896           outBitC (result);
5897           goto release;
5898         }
5899       if (ifx)
5900         {
5901           genIfxJump (ifx, "c", left, right, result);
5902           goto release;
5903         }
5904       /* if the result is used in an arithmetic operation
5905          then put the result in place */
5906       outBitC (result);
5907     }
5908   else
5909     {
5910       gencjne (left, right, newiTempLabel (NULL));
5911       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5912         {
5913           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5914           goto release;
5915         }
5916       if (ifx)
5917         {
5918           genIfxJump (ifx, "a", left, right, result);
5919           goto release;
5920         }
5921       /* if the result is used in an arithmetic operation
5922          then put the result in place */
5923       if (AOP_TYPE (result) != AOP_CRY)
5924         outAcc (result);
5925       /* leave the result in acc */
5926     }
5927
5928 release:
5929   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5930   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5931   freeAsmop (result, NULL, ic, TRUE);
5932 }
5933
5934 /*-----------------------------------------------------------------*/
5935 /* ifxForOp - returns the icode containing the ifx for operand     */
5936 /*-----------------------------------------------------------------*/
5937 static iCode *
5938 ifxForOp (operand * op, iCode * ic)
5939 {
5940   /* if true symbol then needs to be assigned */
5941   if (IS_TRUE_SYMOP (op))
5942     return NULL;
5943
5944   /* if this has register type condition and
5945      the next instruction is ifx with the same operand
5946      and live to of the operand is upto the ifx only then */
5947   if (ic->next &&
5948       ic->next->op == IFX &&
5949       IC_COND (ic->next)->key == op->key &&
5950       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5951     return ic->next;
5952
5953   return NULL;
5954 }
5955
5956 /*-----------------------------------------------------------------*/
5957 /* hasInc - operand is incremented before any other use            */
5958 /*-----------------------------------------------------------------*/
5959 static iCode *
5960 hasInc (operand *op, iCode *ic,int osize)
5961 {
5962   sym_link *type = operandType(op);
5963   sym_link *retype = getSpec (type);
5964   iCode *lic = ic->next;
5965   int isize ;
5966
5967   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5968   if (!IS_SYMOP(op)) return NULL;
5969
5970   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5971   if (IS_AGGREGATE(type->next)) return NULL;
5972   if (osize != (isize = getSize(type->next))) return NULL;
5973
5974   while (lic) {
5975     /* if operand of the form op = op + <sizeof *op> */
5976     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5977         isOperandEqual(IC_RESULT(lic),op) &&
5978         isOperandLiteral(IC_RIGHT(lic)) &&
5979         operandLitValue(IC_RIGHT(lic)) == isize) {
5980       return lic;
5981     }
5982     /* if the operand used or deffed */
5983     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5984       return NULL;
5985     }
5986     /* if GOTO or IFX */
5987     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5988     lic = lic->next;
5989   }
5990   return NULL;
5991 }
5992
5993 /*-----------------------------------------------------------------*/
5994 /* genAndOp - for && operation                                     */
5995 /*-----------------------------------------------------------------*/
5996 static void
5997 genAndOp (iCode * ic)
5998 {
5999   operand *left, *right, *result;
6000   symbol *tlbl;
6001
6002   D(emitcode (";     genAndOp",""));
6003
6004   /* note here that && operations that are in an
6005      if statement are taken away by backPatchLabels
6006      only those used in arthmetic operations remain */
6007   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6008   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6009   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6010
6011   /* if both are bit variables */
6012   if (AOP_TYPE (left) == AOP_CRY &&
6013       AOP_TYPE (right) == AOP_CRY)
6014     {
6015       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6016       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6017       outBitC (result);
6018     }
6019   else
6020     {
6021       tlbl = newiTempLabel (NULL);
6022       toBoolean (left);
6023       emitcode ("jz", "%05d$", tlbl->key + 100);
6024       toBoolean (right);
6025       emitcode ("", "%05d$:", tlbl->key + 100);
6026       outBitAcc (result);
6027     }
6028
6029   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6030   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6031   freeAsmop (result, NULL, ic, TRUE);
6032 }
6033
6034
6035 /*-----------------------------------------------------------------*/
6036 /* genOrOp - for || operation                                      */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 genOrOp (iCode * ic)
6040 {
6041   operand *left, *right, *result;
6042   symbol *tlbl;
6043
6044   D(emitcode (";     genOrOp",""));
6045
6046   /* note here that || operations that are in an
6047      if statement are taken away by backPatchLabels
6048      only those used in arthmetic operations remain */
6049   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6050   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6051   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6052
6053   /* if both are bit variables */
6054   if (AOP_TYPE (left) == AOP_CRY &&
6055       AOP_TYPE (right) == AOP_CRY)
6056     {
6057       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6058       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6059       outBitC (result);
6060     }
6061   else
6062     {
6063       tlbl = newiTempLabel (NULL);
6064       toBoolean (left);
6065       emitcode ("jnz", "%05d$", tlbl->key + 100);
6066       toBoolean (right);
6067       emitcode ("", "%05d$:", tlbl->key + 100);
6068       outBitAcc (result);
6069     }
6070
6071   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6072   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6073   freeAsmop (result, NULL, ic, TRUE);
6074 }
6075
6076 /*-----------------------------------------------------------------*/
6077 /* isLiteralBit - test if lit == 2^n                               */
6078 /*-----------------------------------------------------------------*/
6079 static int
6080 isLiteralBit (unsigned long lit)
6081 {
6082   unsigned long pw[32] =
6083   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6084    0x100L, 0x200L, 0x400L, 0x800L,
6085    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6086    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6087    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6088    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6089    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6090   int idx;
6091
6092   for (idx = 0; idx < 32; idx++)
6093     if (lit == pw[idx])
6094       return idx + 1;
6095   return 0;
6096 }
6097
6098 /*-----------------------------------------------------------------*/
6099 /* continueIfTrue -                                                */
6100 /*-----------------------------------------------------------------*/
6101 static void
6102 continueIfTrue (iCode * ic)
6103 {
6104   if (IC_TRUE (ic))
6105     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6106   ic->generated = 1;
6107 }
6108
6109 /*-----------------------------------------------------------------*/
6110 /* jmpIfTrue -                                                     */
6111 /*-----------------------------------------------------------------*/
6112 static void
6113 jumpIfTrue (iCode * ic)
6114 {
6115   if (!IC_TRUE (ic))
6116     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6117   ic->generated = 1;
6118 }
6119
6120 /*-----------------------------------------------------------------*/
6121 /* jmpTrueOrFalse -                                                */
6122 /*-----------------------------------------------------------------*/
6123 static void
6124 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6125 {
6126   // ugly but optimized by peephole
6127   if (IC_TRUE (ic))
6128     {
6129       symbol *nlbl = newiTempLabel (NULL);
6130       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6131       emitcode ("", "%05d$:", tlbl->key + 100);
6132       freeForBranchAsmop (result);
6133       freeForBranchAsmop (right);
6134       freeForBranchAsmop (left);
6135       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6136       emitcode ("", "%05d$:", nlbl->key + 100);
6137     }
6138   else
6139     {
6140       freeForBranchAsmop (result);
6141       freeForBranchAsmop (right);
6142       freeForBranchAsmop (left);
6143       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6144       emitcode ("", "%05d$:", tlbl->key + 100);
6145     }
6146   ic->generated = 1;
6147 }
6148
6149 /*-----------------------------------------------------------------*/
6150 /* genAnd  - code for and                                          */
6151 /*-----------------------------------------------------------------*/
6152 static void
6153 genAnd (iCode * ic, iCode * ifx)
6154 {
6155   operand *left, *right, *result;
6156   int size, offset = 0;
6157   unsigned long lit = 0L;
6158   int bytelit = 0;
6159   char buffer[10];
6160
6161   D(emitcode (";     genAnd",""));
6162
6163   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6164   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6165   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6166
6167 #ifdef DEBUG_TYPE
6168   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6169             AOP_TYPE (result),
6170             AOP_TYPE (left), AOP_TYPE (right));
6171   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6172             AOP_SIZE (result),
6173             AOP_SIZE (left), AOP_SIZE (right));
6174 #endif
6175
6176   /* if left is a literal & right is not then exchange them */
6177   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6178       AOP_NEEDSACC (left))
6179     {
6180       operand *tmp = right;
6181       right = left;
6182       left = tmp;
6183     }
6184
6185   /* if result = right then exchange left and right */
6186   if (sameRegs (AOP (result), AOP (right)))
6187     {
6188       operand *tmp = right;
6189       right = left;
6190       left = tmp;
6191     }
6192
6193   /* if right is bit then exchange them */
6194   if (AOP_TYPE (right) == AOP_CRY &&
6195       AOP_TYPE (left) != AOP_CRY)
6196     {
6197       operand *tmp = right;
6198       right = left;
6199       left = tmp;
6200     }
6201   if (AOP_TYPE (right) == AOP_LIT)
6202     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6203
6204   size = AOP_SIZE (result);
6205
6206   // if(bit & yy)
6207   // result = bit & yy;
6208   if (AOP_TYPE (left) == AOP_CRY)
6209     {
6210       // c = bit & literal;
6211       if (AOP_TYPE (right) == AOP_LIT)
6212         {
6213           if (lit & 1)
6214             {
6215               if (size && sameRegs (AOP (result), AOP (left)))
6216                 // no change
6217                 goto release;
6218               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6219             }
6220           else
6221             {
6222               // bit(result) = 0;
6223               if (size && (AOP_TYPE (result) == AOP_CRY))
6224                 {
6225                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6226                   goto release;
6227                 }
6228               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6229                 {
6230                   jumpIfTrue (ifx);
6231                   goto release;
6232                 }
6233               emitcode ("clr", "c");
6234             }
6235         }
6236       else
6237         {
6238           if (AOP_TYPE (right) == AOP_CRY)
6239             {
6240               // c = bit & bit;
6241               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6242               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6243             }
6244           else
6245             {
6246               // c = bit & val;
6247               MOVA (aopGet (right, 0, FALSE, FALSE));
6248               // c = lsb
6249               emitcode ("rrc", "a");
6250               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6251             }
6252         }
6253       // bit = c
6254       // val = c
6255       if (size)
6256         outBitC (result);
6257       // if(bit & ...)
6258       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6259         genIfxJump (ifx, "c", left, right, result);
6260       goto release;
6261     }
6262
6263   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6264   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6265   if ((AOP_TYPE (right) == AOP_LIT) &&
6266       (AOP_TYPE (result) == AOP_CRY) &&
6267       (AOP_TYPE (left) != AOP_CRY))
6268     {
6269       int posbit = isLiteralBit (lit);
6270       /* left &  2^n */
6271       if (posbit)
6272         {
6273           posbit--;
6274           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6275           // bit = left & 2^n
6276           if (size)
6277             {
6278               switch (posbit & 0x07)
6279                 {
6280                   case 0: emitcode ("rrc", "a");
6281                           break;
6282                   case 7: emitcode ("rlc", "a");
6283                           break;
6284                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6285                           break;
6286                 }
6287             }
6288           // if(left &  2^n)
6289           else
6290             {
6291               if (ifx)
6292                 {
6293                   SNPRINTF (buffer, sizeof(buffer),
6294                             "acc.%d", posbit & 0x07);
6295                   genIfxJump (ifx, buffer, left, right, result);
6296                 }
6297               else
6298                 {// what is this case? just found it in ds390/gen.c
6299                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6300                 }
6301               goto release;
6302             }
6303         }
6304       else
6305         {
6306           symbol *tlbl = newiTempLabel (NULL);
6307           int sizel = AOP_SIZE (left);
6308           if (size)
6309             emitcode ("setb", "c");
6310           while (sizel--)
6311             {
6312               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6313                 {
6314                   MOVA (aopGet (left, offset, FALSE, FALSE));
6315                   // byte ==  2^n ?
6316                   if ((posbit = isLiteralBit (bytelit)) != 0)
6317                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6318                   else
6319                     {
6320                       if (bytelit != 0x0FFL)
6321                         emitcode ("anl", "a,%s",
6322                                   aopGet (right, offset, FALSE, TRUE));
6323                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6324                     }
6325                 }
6326               offset++;
6327             }
6328           // bit = left & literal
6329           if (size)
6330             {
6331               emitcode ("clr", "c");
6332               emitcode ("", "%05d$:", tlbl->key + 100);
6333             }
6334           // if(left & literal)
6335           else
6336             {
6337               if (ifx)
6338                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6339               else
6340                 emitcode ("", "%05d$:", tlbl->key + 100);
6341               goto release;
6342             }
6343         }
6344       outBitC (result);
6345       goto release;
6346     }
6347
6348   /* if left is same as result */
6349   if (sameRegs (AOP (result), AOP (left)))
6350     {
6351       for (; size--; offset++)
6352         {
6353           if (AOP_TYPE (right) == AOP_LIT)
6354             {
6355               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6356               if (bytelit == 0x0FF)
6357                 {
6358                   /* dummy read of volatile operand */
6359                   if (isOperandVolatile (left, FALSE))
6360                     MOVA (aopGet (left, offset, FALSE, FALSE));
6361                   else
6362                     continue;
6363                 }
6364               else if (bytelit == 0)
6365                 {
6366                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6367                 }
6368               else if (IS_AOP_PREG (result))
6369                 {
6370                   MOVA (aopGet (left, offset, FALSE, TRUE));
6371                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6372                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6373                 }
6374               else
6375                 emitcode ("anl", "%s,%s",
6376                           aopGet (left, offset, FALSE, TRUE),
6377                           aopGet (right, offset, FALSE, FALSE));
6378             }
6379           else
6380             {
6381               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
6382                 {
6383                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6384                 }
6385               else
6386                 {
6387                   MOVA (aopGet (right, offset, FALSE, FALSE));
6388                   if (IS_AOP_PREG (result))
6389                     {
6390                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6391                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6392                     }
6393                   else
6394                     emitcode ("anl", "%s,a",
6395                               aopGet (left, offset, FALSE, TRUE));
6396                 }
6397             }
6398         }
6399     }
6400   else
6401     {
6402       // left & result in different registers
6403       if (AOP_TYPE (result) == AOP_CRY)
6404         {
6405           // result = bit
6406           // if(size), result in bit
6407           // if(!size && ifx), conditional oper: if(left & right)
6408           symbol *tlbl = newiTempLabel (NULL);
6409           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6410           if (size)
6411             emitcode ("setb", "c");
6412           while (sizer--)
6413             {
6414               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6415                   && AOP_TYPE(left)==AOP_ACC)
6416                 {
6417                   if (offset)
6418                     emitcode("mov", "a,b");
6419                   emitcode ("anl", "a,%s",
6420                             aopGet (right, offset, FALSE, FALSE));
6421                 } else {
6422                   if (AOP_TYPE(left)==AOP_ACC)
6423                     {
6424                       if (!offset)
6425                         {
6426                           bool pushedB = pushB ();
6427                           emitcode("mov", "b,a");
6428                           MOVA (aopGet (right, offset, FALSE, FALSE));
6429                           emitcode("anl", "a,b");
6430                           popB (pushedB);
6431                         }
6432                       else
6433                         {
6434                           MOVA (aopGet (right, offset, FALSE, FALSE));
6435                           emitcode("anl", "a,b");
6436                         }
6437                     } else {
6438                       MOVA (aopGet (right, offset, FALSE, FALSE));
6439                       emitcode ("anl", "a,%s",
6440                                 aopGet (left, offset, FALSE, FALSE));
6441                     }
6442                 }
6443               emitcode ("jnz", "%05d$", tlbl->key + 100);
6444               offset++;
6445             }
6446           if (size)
6447             {
6448               CLRC;
6449               emitcode ("", "%05d$:", tlbl->key + 100);
6450               outBitC (result);
6451             }
6452           else if (ifx)
6453             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6454           else
6455             emitcode ("", "%05d$:", tlbl->key + 100);
6456         }
6457       else
6458         {
6459           for (; (size--); offset++)
6460             {
6461               // normal case
6462               // result = left & right
6463               if (AOP_TYPE (right) == AOP_LIT)
6464                 {
6465                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6466                   if (bytelit == 0x0FF)
6467                     {
6468                       aopPut (result,
6469                               aopGet (left, offset, FALSE, FALSE),
6470                               offset,
6471                               isOperandVolatile (result, FALSE));
6472                       continue;
6473                     }
6474                   else if (bytelit == 0)
6475                     {
6476                       /* dummy read of volatile operand */
6477                       if (isOperandVolatile (left, FALSE))
6478                         MOVA (aopGet (left, offset, FALSE, FALSE));
6479                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6480                       continue;
6481                     }
6482                   else if (AOP_TYPE (left) == AOP_ACC)
6483                     {
6484                       if (!offset)
6485                         {
6486                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6487                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6488                           continue;
6489                         }
6490                       else
6491                         {
6492                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6493                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6494                           continue;
6495                         }
6496                     }
6497                 }
6498               // faster than result <- left, anl result,right
6499               // and better if result is SFR
6500               if (AOP_TYPE (left) == AOP_ACC)
6501                 {
6502                   if (offset)
6503                     emitcode("mov", "a,b");
6504                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6505                 }
6506               else
6507                 {
6508                   MOVA (aopGet (right, offset, FALSE, FALSE));
6509                   emitcode ("anl", "a,%s",
6510                             aopGet (left, offset, FALSE, FALSE));
6511                 }
6512               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6513             }
6514         }
6515     }
6516
6517 release:
6518   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6519   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6520   freeAsmop (result, NULL, ic, TRUE);
6521 }
6522
6523 /*-----------------------------------------------------------------*/
6524 /* genOr  - code for or                                            */
6525 /*-----------------------------------------------------------------*/
6526 static void
6527 genOr (iCode * ic, iCode * ifx)
6528 {
6529   operand *left, *right, *result;
6530   int size, offset = 0;
6531   unsigned long lit = 0L;
6532   int bytelit = 0;
6533
6534   D(emitcode (";     genOr",""));
6535
6536   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6537   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6538   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6539
6540 #ifdef DEBUG_TYPE
6541   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6542             AOP_TYPE (result),
6543             AOP_TYPE (left), AOP_TYPE (right));
6544   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6545             AOP_SIZE (result),
6546             AOP_SIZE (left), AOP_SIZE (right));
6547 #endif
6548
6549   /* if left is a literal & right is not then exchange them */
6550   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6551       AOP_NEEDSACC (left))
6552     {
6553       operand *tmp = right;
6554       right = left;
6555       left = tmp;
6556     }
6557
6558   /* if result = right then exchange them */
6559   if (sameRegs (AOP (result), AOP (right)))
6560     {
6561       operand *tmp = right;
6562       right = left;
6563       left = tmp;
6564     }
6565
6566   /* if right is bit then exchange them */
6567   if (AOP_TYPE (right) == AOP_CRY &&
6568       AOP_TYPE (left) != AOP_CRY)
6569     {
6570       operand *tmp = right;
6571       right = left;
6572       left = tmp;
6573     }
6574   if (AOP_TYPE (right) == AOP_LIT)
6575     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6576
6577   size = AOP_SIZE (result);
6578
6579   // if(bit | yy)
6580   // xx = bit | yy;
6581   if (AOP_TYPE (left) == AOP_CRY)
6582     {
6583       if (AOP_TYPE (right) == AOP_LIT)
6584         {
6585           // c = bit | literal;
6586           if (lit)
6587             {
6588               // lit != 0 => result = 1
6589               if (AOP_TYPE (result) == AOP_CRY)
6590                 {
6591                   if (size)
6592                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6593                   else if (ifx)
6594                     continueIfTrue (ifx);
6595                   goto release;
6596                 }
6597               emitcode ("setb", "c");
6598             }
6599           else
6600             {
6601               // lit == 0 => result = left
6602               if (size && sameRegs (AOP (result), AOP (left)))
6603                 goto release;
6604               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6605             }
6606         }
6607       else
6608         {
6609           if (AOP_TYPE (right) == AOP_CRY)
6610             {
6611               // c = bit | bit;
6612               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6613               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6614             }
6615           else
6616             {
6617               // c = bit | val;
6618               symbol *tlbl = newiTempLabel (NULL);
6619               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6620                 emitcode ("setb", "c");
6621               emitcode ("jb", "%s,%05d$",
6622                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6623               toBoolean (right);
6624               emitcode ("jnz", "%05d$", tlbl->key + 100);
6625               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6626                 {
6627                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6628                   goto release;
6629                 }
6630               else
6631                 {
6632                   CLRC;
6633                   emitcode ("", "%05d$:", tlbl->key + 100);
6634                 }
6635             }
6636         }
6637       // bit = c
6638       // val = c
6639       if (size)
6640         outBitC (result);
6641       // if(bit | ...)
6642       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6643         genIfxJump (ifx, "c", left, right, result);
6644       goto release;
6645     }
6646
6647   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6648   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6649   if ((AOP_TYPE (right) == AOP_LIT) &&
6650       (AOP_TYPE (result) == AOP_CRY) &&
6651       (AOP_TYPE (left) != AOP_CRY))
6652     {
6653       if (lit)
6654         {
6655           // result = 1
6656           if (size)
6657             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6658           else
6659             continueIfTrue (ifx);
6660           goto release;
6661         }
6662       else
6663         {
6664           // lit = 0, result = boolean(left)
6665           if (size)
6666             emitcode ("setb", "c");
6667           toBoolean (right);
6668           if (size)
6669             {
6670               symbol *tlbl = newiTempLabel (NULL);
6671               emitcode ("jnz", "%05d$", tlbl->key + 100);
6672               CLRC;
6673               emitcode ("", "%05d$:", tlbl->key + 100);
6674             }
6675           else
6676             {
6677               genIfxJump (ifx, "a", left, right, result);
6678               goto release;
6679             }
6680         }
6681       outBitC (result);
6682       goto release;
6683     }
6684
6685   /* if left is same as result */
6686   if (sameRegs (AOP (result), AOP (left)))
6687     {
6688       for (; size--; offset++)
6689         {
6690           if (AOP_TYPE (right) == AOP_LIT)
6691             {
6692               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6693               if (bytelit == 0)
6694                 {
6695                   /* dummy read of volatile operand */
6696                   if (isOperandVolatile (left, FALSE))
6697                     MOVA (aopGet (left, offset, FALSE, FALSE));
6698                   else
6699                     continue;
6700                 }
6701               else if (bytelit == 0x0FF)
6702                 {
6703                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6704                 }
6705               else if (IS_AOP_PREG (left))
6706                 {
6707                   MOVA (aopGet (left, offset, FALSE, TRUE));
6708                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6709                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6710                 }
6711               else
6712                 {
6713                   emitcode ("orl", "%s,%s",
6714                             aopGet (left, offset, FALSE, TRUE),
6715                             aopGet (right, offset, FALSE, FALSE));
6716                 }
6717             }
6718           else
6719             {
6720               if (AOP_TYPE (left) == AOP_ACC)
6721                 {
6722                   if (offset)
6723                     emitcode("mov", "a,b");
6724                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6725                 }
6726               else
6727                 {
6728                   MOVA (aopGet (right, offset, FALSE, FALSE));
6729                   if (IS_AOP_PREG (left))
6730                     {
6731                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6732                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6733                     }
6734                   else
6735                     {
6736                       emitcode ("orl", "%s,a",
6737                                 aopGet (left, offset, FALSE, TRUE));
6738                     }
6739                 }
6740             }
6741         }
6742     }
6743   else
6744     {
6745       // left & result in different registers
6746       if (AOP_TYPE (result) == AOP_CRY)
6747         {
6748           // result = bit
6749           // if(size), result in bit
6750           // if(!size && ifx), conditional oper: if(left | right)
6751           symbol *tlbl = newiTempLabel (NULL);
6752           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6753           if (size)
6754             emitcode ("setb", "c");
6755           while (sizer--)
6756             {
6757               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6758                 if (offset)
6759                   emitcode("mov", "a,b");
6760                 emitcode ("orl", "a,%s",
6761                           aopGet (right, offset, FALSE, FALSE));
6762               } else {
6763                 MOVA (aopGet (right, offset, FALSE, FALSE));
6764                 emitcode ("orl", "a,%s",
6765                           aopGet (left, offset, FALSE, FALSE));
6766               }
6767               emitcode ("jnz", "%05d$", tlbl->key + 100);
6768               offset++;
6769             }
6770           if (size)
6771             {
6772               CLRC;
6773               emitcode ("", "%05d$:", tlbl->key + 100);
6774               outBitC (result);
6775             }
6776           else if (ifx)
6777             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6778           else
6779             emitcode ("", "%05d$:", tlbl->key + 100);
6780         }
6781       else
6782         {
6783           for (; (size--); offset++)
6784             {
6785               // normal case
6786               // result = left | right
6787               if (AOP_TYPE (right) == AOP_LIT)
6788                 {
6789                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6790                   if (bytelit == 0)
6791                     {
6792                       aopPut (result,
6793                               aopGet (left, offset, FALSE, FALSE),
6794                               offset,
6795                               isOperandVolatile (result, FALSE));
6796                       continue;
6797                     }
6798                   else if (bytelit == 0x0FF)
6799                     {
6800                       /* dummy read of volatile operand */
6801                       if (isOperandVolatile (left, FALSE))
6802                         MOVA (aopGet (left, offset, FALSE, FALSE));
6803                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6804                       continue;
6805                     }
6806                 }
6807               // faster than result <- left, anl result,right
6808               // and better if result is SFR
6809               if (AOP_TYPE (left) == AOP_ACC)
6810                 {
6811                   if (offset)
6812                     emitcode("mov", "a,b");
6813                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6814                 }
6815               else
6816                 {
6817                   MOVA (aopGet (right, offset, FALSE, FALSE));
6818                   emitcode ("orl", "a,%s",
6819                             aopGet (left, offset, FALSE, FALSE));
6820                 }
6821               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6822             }
6823         }
6824     }
6825
6826 release:
6827   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6829   freeAsmop (result, NULL, ic, TRUE);
6830 }
6831
6832 /*-----------------------------------------------------------------*/
6833 /* genXor - code for xclusive or                                   */
6834 /*-----------------------------------------------------------------*/
6835 static void
6836 genXor (iCode * ic, iCode * ifx)
6837 {
6838   operand *left, *right, *result;
6839   int size, offset = 0;
6840   unsigned long lit = 0L;
6841   int bytelit = 0;
6842
6843   D(emitcode (";     genXor",""));
6844
6845   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6846   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6847   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6848
6849 #ifdef DEBUG_TYPE
6850   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6851             AOP_TYPE (result),
6852             AOP_TYPE (left), AOP_TYPE (right));
6853   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6854             AOP_SIZE (result),
6855             AOP_SIZE (left), AOP_SIZE (right));
6856 #endif
6857
6858   /* if left is a literal & right is not ||
6859      if left needs acc & right does not */
6860   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6861       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6862     {
6863       operand *tmp = right;
6864       right = left;
6865       left = tmp;
6866     }
6867
6868   /* if result = right then exchange them */
6869   if (sameRegs (AOP (result), AOP (right)))
6870     {
6871       operand *tmp = right;
6872       right = left;
6873       left = tmp;
6874     }
6875
6876   /* if right is bit then exchange them */
6877   if (AOP_TYPE (right) == AOP_CRY &&
6878       AOP_TYPE (left) != AOP_CRY)
6879     {
6880       operand *tmp = right;
6881       right = left;
6882       left = tmp;
6883     }
6884   if (AOP_TYPE (right) == AOP_LIT)
6885     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6886
6887   size = AOP_SIZE (result);
6888
6889   // if(bit ^ yy)
6890   // xx = bit ^ yy;
6891   if (AOP_TYPE (left) == AOP_CRY)
6892     {
6893       if (AOP_TYPE (right) == AOP_LIT)
6894         {
6895           // c = bit & literal;
6896           if (lit >> 1)
6897             {
6898               // lit>>1  != 0 => result = 1
6899               if (AOP_TYPE (result) == AOP_CRY)
6900                 {
6901                   if (size)
6902                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6903                   else if (ifx)
6904                     continueIfTrue (ifx);
6905                   goto release;
6906                 }
6907               emitcode ("setb", "c");
6908             }
6909           else
6910             {
6911               // lit == (0 or 1)
6912               if (lit == 0)
6913                 {
6914                   // lit == 0, result = left
6915                   if (size && sameRegs (AOP (result), AOP (left)))
6916                     goto release;
6917                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6918                 }
6919               else
6920                 {
6921                   // lit == 1, result = not(left)
6922                   if (size && sameRegs (AOP (result), AOP (left)))
6923                     {
6924                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6925                       goto release;
6926                     }
6927                   else
6928                     {
6929                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6930                       emitcode ("cpl", "c");
6931                     }
6932                 }
6933             }
6934
6935         }
6936       else
6937         {
6938           // right != literal
6939           symbol *tlbl = newiTempLabel (NULL);
6940           if (AOP_TYPE (right) == AOP_CRY)
6941             {
6942               // c = bit ^ bit;
6943               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6944             }
6945           else
6946             {
6947               int sizer = AOP_SIZE (right);
6948               // c = bit ^ val
6949               // if val>>1 != 0, result = 1
6950               emitcode ("setb", "c");
6951               while (sizer)
6952                 {
6953                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6954                   if (sizer == 1)
6955                     // test the msb of the lsb
6956                     emitcode ("anl", "a,#0xfe");
6957                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6958                   sizer--;
6959                 }
6960               // val = (0,1)
6961               emitcode ("rrc", "a");
6962             }
6963           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6964           emitcode ("cpl", "c");
6965           emitcode ("", "%05d$:", (tlbl->key + 100));
6966         }
6967       // bit = c
6968       // val = c
6969       if (size)
6970         outBitC (result);
6971       // if(bit | ...)
6972       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6973         genIfxJump (ifx, "c", left, right, result);
6974       goto release;
6975     }
6976
6977   /* if left is same as result */
6978   if (sameRegs (AOP (result), AOP (left)))
6979     {
6980       for (; size--; offset++)
6981         {
6982           if (AOP_TYPE (right) == AOP_LIT)
6983             {
6984               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6985               if (bytelit == 0)
6986                 {
6987                   /* dummy read of volatile operand */
6988                   if (isOperandVolatile (left, FALSE))
6989                     MOVA (aopGet (left, offset, FALSE, FALSE));
6990                   else
6991                     continue;
6992                 }
6993               else if (IS_AOP_PREG (left))
6994                 {
6995                   MOVA (aopGet (left, offset, FALSE, TRUE));
6996                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6997                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6998                 }
6999               else
7000                 {
7001                   emitcode ("xrl", "%s,%s",
7002                             aopGet (left, offset, FALSE, TRUE),
7003                             aopGet (right, offset, FALSE, FALSE));
7004                 }
7005             }
7006           else
7007             {
7008               if (AOP_TYPE (left) == AOP_ACC)
7009                 {
7010                   if (offset)
7011                     emitcode("mov", "a,b");
7012                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7013                 }
7014               else
7015                 {
7016                   MOVA (aopGet (right, offset, FALSE, FALSE));
7017                   if (IS_AOP_PREG (left))
7018                     {
7019                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7020                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7021                     }
7022                   else
7023                     emitcode ("xrl", "%s,a",
7024                               aopGet (left, offset, FALSE, TRUE));
7025                 }
7026             }
7027         }
7028     }
7029   else
7030     {
7031       // left & result in different registers
7032       if (AOP_TYPE (result) == AOP_CRY)
7033         {
7034           // result = bit
7035           // if(size), result in bit
7036           // if(!size && ifx), conditional oper: if(left ^ right)
7037           symbol *tlbl = newiTempLabel (NULL);
7038           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7039           if (size)
7040             emitcode ("setb", "c");
7041           while (sizer--)
7042             {
7043               if ((AOP_TYPE (right) == AOP_LIT) &&
7044                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7045                 {
7046                   MOVA (aopGet (left, offset, FALSE, FALSE));
7047                 }
7048               else
7049                 {
7050                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7051                     if (offset)
7052                       emitcode("mov", "a,b");
7053                     emitcode ("xrl", "a,%s",
7054                               aopGet (right, offset, FALSE, FALSE));
7055                   } else {
7056                     MOVA (aopGet (right, offset, FALSE, FALSE));
7057                     emitcode ("xrl", "a,%s",
7058                               aopGet (left, offset, FALSE, FALSE));
7059                   }
7060                 }
7061               emitcode ("jnz", "%05d$", tlbl->key + 100);
7062               offset++;
7063             }
7064           if (size)
7065             {
7066               CLRC;
7067               emitcode ("", "%05d$:", tlbl->key + 100);
7068               outBitC (result);
7069             }
7070           else if (ifx)
7071             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7072         }
7073       else
7074         {
7075           for (; (size--); offset++)
7076             {
7077               // normal case
7078               // result = left & right
7079               if (AOP_TYPE (right) == AOP_LIT)
7080                 {
7081                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7082                   if (bytelit == 0)
7083                     {
7084                       aopPut (result,
7085                               aopGet (left, offset, FALSE, FALSE),
7086                               offset,
7087                               isOperandVolatile (result, FALSE));
7088                       continue;
7089                     }
7090                 }
7091               // faster than result <- left, anl result,right
7092               // and better if result is SFR
7093               if (AOP_TYPE (left) == AOP_ACC)
7094                 {
7095                   if (offset)
7096                     emitcode("mov", "a,b");
7097                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7098                 }
7099               else
7100                 {
7101                   MOVA (aopGet (right, offset, FALSE, FALSE));
7102                   emitcode ("xrl", "a,%s",
7103                             aopGet (left, offset, FALSE, TRUE));
7104                 }
7105               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7106             }
7107         }
7108     }
7109
7110 release:
7111   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7112   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7113   freeAsmop (result, NULL, ic, TRUE);
7114 }
7115
7116 /*-----------------------------------------------------------------*/
7117 /* genInline - write the inline code out                           */
7118 /*-----------------------------------------------------------------*/
7119 static void
7120 genInline (iCode * ic)
7121 {
7122   char *buffer, *bp, *bp1;
7123
7124   D(emitcode (";     genInline",""));
7125
7126   _G.inLine += (!options.asmpeep);
7127
7128   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7129   strcpy (buffer, IC_INLINE (ic));
7130
7131   /* emit each line as a code */
7132   while (*bp)
7133     {
7134       if (*bp == '\n')
7135         {
7136           *bp++ = '\0';
7137           emitcode (bp1, "");
7138           bp1 = bp;
7139         }
7140       else
7141         {
7142           /* Add \n for labels, not dirs such as c:\mydir */
7143           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7144             {
7145               bp++;
7146               *bp = '\0';
7147               bp++;
7148               emitcode (bp1, "");
7149               bp1 = bp;
7150             }
7151           else
7152             bp++;
7153         }
7154     }
7155   if (bp1 != bp)
7156     emitcode (bp1, "");
7157   /*     emitcode("",buffer); */
7158   _G.inLine -= (!options.asmpeep);
7159 }
7160
7161 /*-----------------------------------------------------------------*/
7162 /* genRRC - rotate right with carry                                */
7163 /*-----------------------------------------------------------------*/
7164 static void
7165 genRRC (iCode * ic)
7166 {
7167   operand *left, *result;
7168   int size, offset = 0;
7169   char *l;
7170
7171   D(emitcode (";     genRRC",""));
7172
7173   /* rotate right with carry */
7174   left = IC_LEFT (ic);
7175   result = IC_RESULT (ic);
7176   aopOp (left, ic, FALSE);
7177   aopOp (result, ic, FALSE);
7178
7179   /* move it to the result */
7180   size = AOP_SIZE (result);
7181   offset = size - 1;
7182   if (size == 1) { /* special case for 1 byte */
7183       l = aopGet (left, offset, FALSE, FALSE);
7184       MOVA (l);
7185       emitcode ("rr", "a");
7186       goto release;
7187   }
7188   /* no need to clear carry, bit7 will be written later */
7189   while (size--)
7190     {
7191       l = aopGet (left, offset, FALSE, FALSE);
7192       MOVA (l);
7193       emitcode ("rrc", "a");
7194       if (AOP_SIZE (result) > 1)
7195         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7196     }
7197   /* now we need to put the carry into the
7198      highest order byte of the result */
7199   if (AOP_SIZE (result) > 1)
7200     {
7201       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7202       MOVA (l);
7203     }
7204   emitcode ("mov", "acc.7,c");
7205  release:
7206   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7207   freeAsmop (left, NULL, ic, TRUE);
7208   freeAsmop (result, NULL, ic, TRUE);
7209 }
7210
7211 /*-----------------------------------------------------------------*/
7212 /* genRLC - generate code for rotate left with carry               */
7213 /*-----------------------------------------------------------------*/
7214 static void
7215 genRLC (iCode * ic)
7216 {
7217   operand *left, *result;
7218   int size, offset = 0;
7219   char *l;
7220
7221   D(emitcode (";     genRLC",""));
7222
7223   /* rotate right with carry */
7224   left = IC_LEFT (ic);
7225   result = IC_RESULT (ic);
7226   aopOp (left, ic, FALSE);
7227   aopOp (result, ic, FALSE);
7228
7229   /* move it to the result */
7230   size = AOP_SIZE (result);
7231   offset = 0;
7232   if (size--)
7233     {
7234       l = aopGet (left, offset, FALSE, FALSE);
7235       MOVA (l);
7236       if (size == 0) { /* special case for 1 byte */
7237               emitcode("rl","a");
7238               goto release;
7239       }
7240       emitcode("rlc","a"); /* bit0 will be written later */
7241       if (AOP_SIZE (result) > 1)
7242         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7243       while (size--)
7244         {
7245           l = aopGet (left, offset, FALSE, FALSE);
7246           MOVA (l);
7247           emitcode ("rlc", "a");
7248           if (AOP_SIZE (result) > 1)
7249             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7250         }
7251     }
7252   /* now we need to put the carry into the
7253      highest order byte of the result */
7254   if (AOP_SIZE (result) > 1)
7255     {
7256       l = aopGet (result, 0, FALSE, FALSE);
7257       MOVA (l);
7258     }
7259   emitcode ("mov", "acc.0,c");
7260  release:
7261   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7262   freeAsmop (left, NULL, ic, TRUE);
7263   freeAsmop (result, NULL, ic, TRUE);
7264 }
7265
7266 /*-----------------------------------------------------------------*/
7267 /* genGetHbit - generates code get highest order bit               */
7268 /*-----------------------------------------------------------------*/
7269 static void
7270 genGetHbit (iCode * ic)
7271 {
7272   operand *left, *result;
7273
7274   D(emitcode (";     genGetHbit",""));
7275
7276   left = IC_LEFT (ic);
7277   result = IC_RESULT (ic);
7278   aopOp (left, ic, FALSE);
7279   aopOp (result, ic, FALSE);
7280
7281   /* get the highest order byte into a */
7282   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7283   if (AOP_TYPE (result) == AOP_CRY)
7284     {
7285       emitcode ("rlc", "a");
7286       outBitC (result);
7287     }
7288   else
7289     {
7290       emitcode ("rl", "a");
7291       emitcode ("anl", "a,#0x01");
7292       outAcc (result);
7293     }
7294
7295
7296   freeAsmop (left, NULL, ic, TRUE);
7297   freeAsmop (result, NULL, ic, TRUE);
7298 }
7299
7300 /*-----------------------------------------------------------------*/
7301 /* genSwap - generates code to swap nibbles or bytes               */
7302 /*-----------------------------------------------------------------*/
7303 static void
7304 genSwap (iCode * ic)
7305 {
7306   operand *left, *result;
7307
7308   D(emitcode (";     genSwap",""));
7309
7310   left = IC_LEFT (ic);
7311   result = IC_RESULT (ic);
7312   aopOp (left, ic, FALSE);
7313   aopOp (result, ic, FALSE);
7314
7315   switch (AOP_SIZE (left))
7316     {
7317     case 1: /* swap nibbles in byte */
7318       MOVA (aopGet (left, 0, FALSE, FALSE));
7319       emitcode ("swap", "a");
7320       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7321       break;
7322     case 2: /* swap bytes in word */
7323       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7324         {
7325           MOVA (aopGet (left, 0, FALSE, FALSE));
7326           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7327                   0, isOperandVolatile (result, FALSE));
7328           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7329         }
7330       else if (operandsEqu (left, result))
7331         {
7332           char * reg = "a";
7333           bool pushedB = FALSE, leftInB = FALSE;
7334
7335           MOVA (aopGet (left, 0, FALSE, FALSE));
7336           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7337             {
7338               pushedB = pushB ();
7339               emitcode ("mov", "b,a");
7340               reg = "b";
7341               leftInB = TRUE;
7342             }
7343           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7344                   0, isOperandVolatile (result, FALSE));
7345           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7346
7347           if (leftInB)
7348             popB (pushedB);
7349         }
7350       else
7351         {
7352           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7353                   0, isOperandVolatile (result, FALSE));
7354           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7355                   1, isOperandVolatile (result, FALSE));
7356         }
7357       break;
7358     default:
7359       wassertl(FALSE, "unsupported SWAP operand size");
7360     }
7361
7362   freeAsmop (left, NULL, ic, TRUE);
7363   freeAsmop (result, NULL, ic, TRUE);
7364 }
7365
7366
7367 /*-----------------------------------------------------------------*/
7368 /* AccRol - rotate left accumulator by known count                 */
7369 /*-----------------------------------------------------------------*/
7370 static void
7371 AccRol (int shCount)
7372 {
7373   shCount &= 0x0007;            // shCount : 0..7
7374
7375   switch (shCount)
7376     {
7377     case 0:
7378       break;
7379     case 1:
7380       emitcode ("rl", "a");
7381       break;
7382     case 2:
7383       emitcode ("rl", "a");
7384       emitcode ("rl", "a");
7385       break;
7386     case 3:
7387       emitcode ("swap", "a");
7388       emitcode ("rr", "a");
7389       break;
7390     case 4:
7391       emitcode ("swap", "a");
7392       break;
7393     case 5:
7394       emitcode ("swap", "a");
7395       emitcode ("rl", "a");
7396       break;
7397     case 6:
7398       emitcode ("rr", "a");
7399       emitcode ("rr", "a");
7400       break;
7401     case 7:
7402       emitcode ("rr", "a");
7403       break;
7404     }
7405 }
7406
7407 /*-----------------------------------------------------------------*/
7408 /* AccLsh - left shift accumulator by known count                  */
7409 /*-----------------------------------------------------------------*/
7410 static void
7411 AccLsh (int shCount)
7412 {
7413   if (shCount != 0)
7414     {
7415       if (shCount == 1)
7416         emitcode ("add", "a,acc");
7417       else if (shCount == 2)
7418         {
7419           emitcode ("add", "a,acc");
7420           emitcode ("add", "a,acc");
7421         }
7422       else
7423         {
7424           /* rotate left accumulator */
7425           AccRol (shCount);
7426           /* and kill the lower order bits */
7427           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7428         }
7429     }
7430 }
7431
7432 /*-----------------------------------------------------------------*/
7433 /* AccRsh - right shift accumulator by known count                 */
7434 /*-----------------------------------------------------------------*/
7435 static void
7436 AccRsh (int shCount)
7437 {
7438   if (shCount != 0)
7439     {
7440       if (shCount == 1)
7441         {
7442           CLRC;
7443           emitcode ("rrc", "a");
7444         }
7445       else
7446         {
7447           /* rotate right accumulator */
7448           AccRol (8 - shCount);
7449           /* and kill the higher order bits */
7450           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7451         }
7452     }
7453 }
7454
7455 /*-----------------------------------------------------------------*/
7456 /* AccSRsh - signed right shift accumulator by known count                 */
7457 /*-----------------------------------------------------------------*/
7458 static void
7459 AccSRsh (int shCount)
7460 {
7461   symbol *tlbl;
7462   if (shCount != 0)
7463     {
7464       if (shCount == 1)
7465         {
7466           emitcode ("mov", "c,acc.7");
7467           emitcode ("rrc", "a");
7468         }
7469       else if (shCount == 2)
7470         {
7471           emitcode ("mov", "c,acc.7");
7472           emitcode ("rrc", "a");
7473           emitcode ("mov", "c,acc.7");
7474           emitcode ("rrc", "a");
7475         }
7476       else
7477         {
7478           tlbl = newiTempLabel (NULL);
7479           /* rotate right accumulator */
7480           AccRol (8 - shCount);
7481           /* and kill the higher order bits */
7482           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7483           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7484           emitcode ("orl", "a,#0x%02x",
7485                     (unsigned char) ~SRMask[shCount]);
7486           emitcode ("", "%05d$:", tlbl->key + 100);
7487         }
7488     }
7489 }
7490
7491 /*-----------------------------------------------------------------*/
7492 /* shiftR1Left2Result - shift right one byte from left to result   */
7493 /*-----------------------------------------------------------------*/
7494 static void
7495 shiftR1Left2Result (operand * left, int offl,
7496                     operand * result, int offr,
7497                     int shCount, int sign)
7498 {
7499   MOVA (aopGet (left, offl, FALSE, FALSE));
7500   /* shift right accumulator */
7501   if (sign)
7502     AccSRsh (shCount);
7503   else
7504     AccRsh (shCount);
7505   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7506 }
7507
7508 /*-----------------------------------------------------------------*/
7509 /* shiftL1Left2Result - shift left one byte from left to result    */
7510 /*-----------------------------------------------------------------*/
7511 static void
7512 shiftL1Left2Result (operand * left, int offl,
7513                     operand * result, int offr, int shCount)
7514 {
7515   char *l;
7516   l = aopGet (left, offl, FALSE, FALSE);
7517   MOVA (l);
7518   /* shift left accumulator */
7519   AccLsh (shCount);
7520   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7521 }
7522
7523 /*-----------------------------------------------------------------*/
7524 /* movLeft2Result - move byte from left to result                  */
7525 /*-----------------------------------------------------------------*/
7526 static void
7527 movLeft2Result (operand * left, int offl,
7528                 operand * result, int offr, int sign)
7529 {
7530   char *l;
7531   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7532     {
7533       l = aopGet (left, offl, FALSE, FALSE);
7534
7535       if (*l == '@' && (IS_AOP_PREG (result)))
7536         {
7537           emitcode ("mov", "a,%s", l);
7538           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7539         }
7540       else
7541         {
7542           if (!sign)
7543             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7544           else
7545             {
7546               /* MSB sign in acc.7 ! */
7547               if (getDataSize (left) == offl + 1)
7548                 {
7549                   emitcode ("mov", "a,%s", l);
7550                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7551                 }
7552             }
7553         }
7554     }
7555 }
7556
7557 /*-----------------------------------------------------------------*/
7558 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7559 /*-----------------------------------------------------------------*/
7560 static void
7561 AccAXRrl1 (char *x)
7562 {
7563   emitcode ("rrc", "a");
7564   emitcode ("xch", "a,%s", x);
7565   emitcode ("rrc", "a");
7566   emitcode ("xch", "a,%s", x);
7567 }
7568
7569 /*-----------------------------------------------------------------*/
7570 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7571 /*-----------------------------------------------------------------*/
7572 static void
7573 AccAXLrl1 (char *x)
7574 {
7575   emitcode ("xch", "a,%s", x);
7576   emitcode ("rlc", "a");
7577   emitcode ("xch", "a,%s", x);
7578   emitcode ("rlc", "a");
7579 }
7580
7581 /*-----------------------------------------------------------------*/
7582 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7583 /*-----------------------------------------------------------------*/
7584 static void
7585 AccAXLsh1 (char *x)
7586 {
7587   emitcode ("xch", "a,%s", x);
7588   emitcode ("add", "a,acc");
7589   emitcode ("xch", "a,%s", x);
7590   emitcode ("rlc", "a");
7591 }
7592
7593 /*-----------------------------------------------------------------*/
7594 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7595 /*-----------------------------------------------------------------*/
7596 static void
7597 AccAXLsh (char *x, int shCount)
7598 {
7599   switch (shCount)
7600     {
7601     case 0:
7602       break;
7603     case 1:
7604       AccAXLsh1 (x);
7605       break;
7606     case 2:
7607       AccAXLsh1 (x);
7608       AccAXLsh1 (x);
7609       break;
7610     case 3:
7611     case 4:
7612     case 5:                     // AAAAABBB:CCCCCDDD
7613
7614       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7615
7616       emitcode ("anl", "a,#0x%02x",
7617                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7618
7619       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7620
7621       AccRol (shCount);         // DDDCCCCC:BBB00000
7622
7623       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7624
7625       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7626
7627       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7628
7629       emitcode ("anl", "a,#0x%02x",
7630                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7631
7632       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7633
7634       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7635
7636       break;
7637     case 6:                     // AAAAAABB:CCCCCCDD
7638       emitcode ("anl", "a,#0x%02x",
7639                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7640       emitcode ("mov", "c,acc.0");      // c = B
7641       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7642 #if 0 // REMOVE ME
7643       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7644       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7645 #else
7646       emitcode("rrc","a");
7647       emitcode("xch","a,%s", x);
7648       emitcode("rrc","a");
7649       emitcode("mov","c,acc.0"); //<< get correct bit
7650       emitcode("xch","a,%s", x);
7651
7652       emitcode("rrc","a");
7653       emitcode("xch","a,%s", x);
7654       emitcode("rrc","a");
7655       emitcode("xch","a,%s", x);
7656 #endif
7657       break;
7658     case 7:                     // a:x <<= 7
7659
7660       emitcode ("anl", "a,#0x%02x",
7661                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7662
7663       emitcode ("mov", "c,acc.0");      // c = B
7664
7665       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7666
7667       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7668
7669       break;
7670     default:
7671       break;
7672     }
7673 }
7674
7675 /*-----------------------------------------------------------------*/
7676 /* AccAXRsh - right shift a:x known count (0..7)                   */
7677 /*-----------------------------------------------------------------*/
7678 static void
7679 AccAXRsh (char *x, int shCount)
7680 {
7681   switch (shCount)
7682     {
7683     case 0:
7684       break;
7685     case 1:
7686       CLRC;
7687       AccAXRrl1 (x);            // 0->a:x
7688
7689       break;
7690     case 2:
7691       CLRC;
7692       AccAXRrl1 (x);            // 0->a:x
7693
7694       CLRC;
7695       AccAXRrl1 (x);            // 0->a:x
7696
7697       break;
7698     case 3:
7699     case 4:
7700     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7701
7702       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7703
7704       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7705
7706       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7707
7708       emitcode ("anl", "a,#0x%02x",
7709                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7710
7711       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7712
7713       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7714
7715       emitcode ("anl", "a,#0x%02x",
7716                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7717
7718       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7719
7720       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7721
7722       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7723
7724       break;
7725     case 6:                     // AABBBBBB:CCDDDDDD
7726
7727       emitcode ("mov", "c,acc.7");
7728       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7729
7730       emitcode ("mov", "c,acc.7");
7731       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7732
7733       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7734
7735       emitcode ("anl", "a,#0x%02x",
7736                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7737
7738       break;
7739     case 7:                     // ABBBBBBB:CDDDDDDD
7740
7741       emitcode ("mov", "c,acc.7");      // c = A
7742
7743       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7744
7745       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7746
7747       emitcode ("anl", "a,#0x%02x",
7748                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7749
7750       break;
7751     default:
7752       break;
7753     }
7754 }
7755
7756 /*-----------------------------------------------------------------*/
7757 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7758 /*-----------------------------------------------------------------*/
7759 static void
7760 AccAXRshS (char *x, int shCount)
7761 {
7762   symbol *tlbl;
7763   switch (shCount)
7764     {
7765     case 0:
7766       break;
7767     case 1:
7768       emitcode ("mov", "c,acc.7");
7769       AccAXRrl1 (x);            // s->a:x
7770
7771       break;
7772     case 2:
7773       emitcode ("mov", "c,acc.7");
7774       AccAXRrl1 (x);            // s->a:x
7775
7776       emitcode ("mov", "c,acc.7");
7777       AccAXRrl1 (x);            // s->a:x
7778
7779       break;
7780     case 3:
7781     case 4:
7782     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7783
7784       tlbl = newiTempLabel (NULL);
7785       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7786
7787       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7788
7789       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7790
7791       emitcode ("anl", "a,#0x%02x",
7792                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7793
7794       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7795
7796       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7797
7798       emitcode ("anl", "a,#0x%02x",
7799                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7800
7801       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7802
7803       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7804
7805       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7806
7807       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7808       emitcode ("orl", "a,#0x%02x",
7809                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7810
7811       emitcode ("", "%05d$:", tlbl->key + 100);
7812       break;                    // SSSSAAAA:BBBCCCCC
7813
7814     case 6:                     // AABBBBBB:CCDDDDDD
7815
7816       tlbl = newiTempLabel (NULL);
7817       emitcode ("mov", "c,acc.7");
7818       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7819
7820       emitcode ("mov", "c,acc.7");
7821       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7822
7823       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7824
7825       emitcode ("anl", "a,#0x%02x",
7826                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7827
7828       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7829       emitcode ("orl", "a,#0x%02x",
7830                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7831
7832       emitcode ("", "%05d$:", tlbl->key + 100);
7833       break;
7834     case 7:                     // ABBBBBBB:CDDDDDDD
7835
7836       tlbl = newiTempLabel (NULL);
7837       emitcode ("mov", "c,acc.7");      // c = A
7838
7839       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7840
7841       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7842
7843       emitcode ("anl", "a,#0x%02x",
7844                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7845
7846       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7847       emitcode ("orl", "a,#0x%02x",
7848                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7849
7850       emitcode ("", "%05d$:", tlbl->key + 100);
7851       break;
7852     default:
7853       break;
7854     }
7855 }
7856
7857 /*-----------------------------------------------------------------*/
7858 /* shiftL2Left2Result - shift left two bytes from left to result   */
7859 /*-----------------------------------------------------------------*/
7860 static void
7861 shiftL2Left2Result (operand * left, int offl,
7862                     operand * result, int offr, int shCount)
7863 {
7864   if (sameRegs (AOP (result), AOP (left)) &&
7865       ((offl + MSB16) == offr))
7866     {
7867       /* don't crash result[offr] */
7868       MOVA (aopGet (left, offl, FALSE, FALSE));
7869       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7870     }
7871   else
7872     {
7873       movLeft2Result (left, offl, result, offr, 0);
7874       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7875     }
7876   /* ax << shCount (x = lsb(result)) */
7877   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
7878   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7879 }
7880
7881
7882 /*-----------------------------------------------------------------*/
7883 /* shiftR2Left2Result - shift right two bytes from left to result  */
7884 /*-----------------------------------------------------------------*/
7885 static void
7886 shiftR2Left2Result (operand * left, int offl,
7887                     operand * result, int offr,
7888                     int shCount, int sign)
7889 {
7890   if (sameRegs (AOP (result), AOP (left)) &&
7891       ((offl + MSB16) == offr))
7892     {
7893       /* don't crash result[offr] */
7894       MOVA (aopGet (left, offl, FALSE, FALSE));
7895       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
7896     }
7897   else
7898     {
7899       movLeft2Result (left, offl, result, offr, 0);
7900       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
7901     }
7902   /* a:x >> shCount (x = lsb(result)) */
7903   if (sign)
7904     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
7905   else
7906     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
7907   if (getDataSize (result) > 1)
7908     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
7909 }
7910
7911 /*-----------------------------------------------------------------*/
7912 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7913 /*-----------------------------------------------------------------*/
7914 static void
7915 shiftLLeftOrResult (operand * left, int offl,
7916                     operand * result, int offr, int shCount)
7917 {
7918   MOVA (aopGet (left, offl, FALSE, FALSE));
7919   /* shift left accumulator */
7920   AccLsh (shCount);
7921   /* or with result */
7922   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7923   /* back to result */
7924   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7925 }
7926
7927 /*-----------------------------------------------------------------*/
7928 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7929 /*-----------------------------------------------------------------*/
7930 static void
7931 shiftRLeftOrResult (operand * left, int offl,
7932                     operand * result, int offr, int shCount)
7933 {
7934   MOVA (aopGet (left, offl, FALSE, FALSE));
7935   /* shift right accumulator */
7936   AccRsh (shCount);
7937   /* or with result */
7938   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
7939   /* back to result */
7940   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7941 }
7942
7943 /*-----------------------------------------------------------------*/
7944 /* genlshOne - left shift a one byte quantity by known count       */
7945 /*-----------------------------------------------------------------*/
7946 static void
7947 genlshOne (operand * result, operand * left, int shCount)
7948 {
7949   D(emitcode (";     genlshOne",""));
7950
7951   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7952 }
7953
7954 /*-----------------------------------------------------------------*/
7955 /* genlshTwo - left shift two bytes by known amount != 0           */
7956 /*-----------------------------------------------------------------*/
7957 static void
7958 genlshTwo (operand * result, operand * left, int shCount)
7959 {
7960   int size;
7961
7962   D(emitcode (";     genlshTwo",""));
7963
7964   size = getDataSize (result);
7965
7966   /* if shCount >= 8 */
7967   if (shCount >= 8)
7968     {
7969       shCount -= 8;
7970
7971       if (size > 1)
7972         {
7973           if (shCount)
7974             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7975           else
7976             movLeft2Result (left, LSB, result, MSB16, 0);
7977         }
7978       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
7979     }
7980
7981   /*  1 <= shCount <= 7 */
7982   else
7983     {
7984       if (size == 1)
7985         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7986       else
7987         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7988     }
7989 }
7990
7991 /*-----------------------------------------------------------------*/
7992 /* shiftLLong - shift left one long from left to result            */
7993 /* offl = LSB or MSB16                                             */
7994 /*-----------------------------------------------------------------*/
7995 static void
7996 shiftLLong (operand * left, operand * result, int offr)
7997 {
7998   char *l;
7999   int size = AOP_SIZE (result);
8000
8001   if (size >= LSB + offr)
8002     {
8003       l = aopGet (left, LSB, FALSE, FALSE);
8004       MOVA (l);
8005       emitcode ("add", "a,acc");
8006       if (sameRegs (AOP (left), AOP (result)) &&
8007           size >= MSB16 + offr && offr != LSB)
8008         emitcode ("xch", "a,%s",
8009                   aopGet (left, LSB + offr, FALSE, FALSE));
8010       else
8011         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8012     }
8013
8014   if (size >= MSB16 + offr)
8015     {
8016       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8017         {
8018           l = aopGet (left, MSB16, FALSE, FALSE);
8019           MOVA (l);
8020         }
8021       emitcode ("rlc", "a");
8022       if (sameRegs (AOP (left), AOP (result)) &&
8023           size >= MSB24 + offr && offr != LSB)
8024         emitcode ("xch", "a,%s",
8025                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8026       else
8027         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8028     }
8029
8030   if (size >= MSB24 + offr)
8031     {
8032       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8033         {
8034           l = aopGet (left, MSB24, FALSE, FALSE);
8035           MOVA (l);
8036         }
8037       emitcode ("rlc", "a");
8038       if (sameRegs (AOP (left), AOP (result)) &&
8039           size >= MSB32 + offr && offr != LSB)
8040         emitcode ("xch", "a,%s",
8041                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8042       else
8043         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8044     }
8045
8046   if (size > MSB32 + offr)
8047     {
8048       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8049         {
8050           l = aopGet (left, MSB32, FALSE, FALSE);
8051           MOVA (l);
8052         }
8053       emitcode ("rlc", "a");
8054       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8055     }
8056   if (offr != LSB)
8057     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8058 }
8059
8060 /*-----------------------------------------------------------------*/
8061 /* genlshFour - shift four byte by a known amount != 0             */
8062 /*-----------------------------------------------------------------*/
8063 static void
8064 genlshFour (operand * result, operand * left, int shCount)
8065 {
8066   int size;
8067
8068   D(emitcode (";     genlshFour",""));
8069
8070   size = AOP_SIZE (result);
8071
8072   /* if shifting more that 3 bytes */
8073   if (shCount >= 24)
8074     {
8075       shCount -= 24;
8076       if (shCount)
8077         /* lowest order of left goes to the highest
8078            order of the destination */
8079         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8080       else
8081         movLeft2Result (left, LSB, result, MSB32, 0);
8082       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8083       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8084       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8085       return;
8086     }
8087
8088   /* more than two bytes */
8089   else if (shCount >= 16)
8090     {
8091       /* lower order two bytes goes to higher order two bytes */
8092       shCount -= 16;
8093       /* if some more remaining */
8094       if (shCount)
8095         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8096       else
8097         {
8098           movLeft2Result (left, MSB16, result, MSB32, 0);
8099           movLeft2Result (left, LSB, result, MSB24, 0);
8100         }
8101       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8102       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8103       return;
8104     }
8105
8106   /* if more than 1 byte */
8107   else if (shCount >= 8)
8108     {
8109       /* lower order three bytes goes to higher order  three bytes */
8110       shCount -= 8;
8111       if (size == 2)
8112         {
8113           if (shCount)
8114             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8115           else
8116             movLeft2Result (left, LSB, result, MSB16, 0);
8117         }
8118       else
8119         {                       /* size = 4 */
8120           if (shCount == 0)
8121             {
8122               movLeft2Result (left, MSB24, result, MSB32, 0);
8123               movLeft2Result (left, MSB16, result, MSB24, 0);
8124               movLeft2Result (left, LSB, result, MSB16, 0);
8125               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8126             }
8127           else if (shCount == 1)
8128             shiftLLong (left, result, MSB16);
8129           else
8130             {
8131               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8132               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8133               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8134               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8135             }
8136         }
8137     }
8138
8139   /* 1 <= shCount <= 7 */
8140   else if (shCount <= 2)
8141     {
8142       shiftLLong (left, result, LSB);
8143       if (shCount == 2)
8144         shiftLLong (result, result, LSB);
8145     }
8146   /* 3 <= shCount <= 7, optimize */
8147   else
8148     {
8149       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8150       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8151       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8152     }
8153 }
8154
8155 /*-----------------------------------------------------------------*/
8156 /* genLeftShiftLiteral - left shifting by known count              */
8157 /*-----------------------------------------------------------------*/
8158 static void
8159 genLeftShiftLiteral (operand * left,
8160                      operand * right,
8161                      operand * result,
8162                      iCode * ic)
8163 {
8164   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8165   int size;
8166
8167   D(emitcode (";     genLeftShiftLiteral",""));
8168
8169   freeAsmop (right, NULL, ic, TRUE);
8170
8171   aopOp (left, ic, FALSE);
8172   aopOp (result, ic, FALSE);
8173
8174   size = getSize (operandType (result));
8175
8176 #if VIEW_SIZE
8177   emitcode ("; shift left ", "result %d, left %d", size,
8178             AOP_SIZE (left));
8179 #endif
8180
8181   /* I suppose that the left size >= result size */
8182   if (shCount == 0)
8183     {
8184       while (size--)
8185         {
8186           movLeft2Result (left, size, result, size, 0);
8187         }
8188     }
8189
8190   else if (shCount >= (size * 8))
8191     while (size--)
8192       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8193   else
8194     {
8195       switch (size)
8196         {
8197         case 1:
8198           genlshOne (result, left, shCount);
8199           break;
8200
8201         case 2:
8202           genlshTwo (result, left, shCount);
8203           break;
8204
8205         case 4:
8206           genlshFour (result, left, shCount);
8207           break;
8208         default:
8209           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8210                   "*** ack! mystery literal shift!\n");
8211           break;
8212         }
8213     }
8214   freeAsmop (left, NULL, ic, TRUE);
8215   freeAsmop (result, NULL, ic, TRUE);
8216 }
8217
8218 /*-----------------------------------------------------------------*/
8219 /* genLeftShift - generates code for left shifting                 */
8220 /*-----------------------------------------------------------------*/
8221 static void
8222 genLeftShift (iCode * ic)
8223 {
8224   operand *left, *right, *result;
8225   int size, offset;
8226   char *l;
8227   symbol *tlbl, *tlbl1;
8228   bool pushedB;
8229
8230   D(emitcode (";     genLeftShift",""));
8231
8232   right = IC_RIGHT (ic);
8233   left = IC_LEFT (ic);
8234   result = IC_RESULT (ic);
8235
8236   aopOp (right, ic, FALSE);
8237
8238   /* if the shift count is known then do it
8239      as efficiently as possible */
8240   if (AOP_TYPE (right) == AOP_LIT)
8241     {
8242       genLeftShiftLiteral (left, right, result, ic);
8243       return;
8244     }
8245
8246   /* shift count is unknown then we have to form
8247      a loop get the loop count in B : Note: we take
8248      only the lower order byte since shifting
8249      more that 32 bits make no sense anyway, ( the
8250      largest size of an object can be only 32 bits ) */
8251
8252   pushedB = pushB ();
8253   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8254   emitcode ("inc", "b");
8255   freeAsmop (right, NULL, ic, TRUE);
8256   aopOp (left, ic, FALSE);
8257   aopOp (result, ic, FALSE);
8258
8259   /* now move the left to the result if they are not the same */
8260   if (!sameRegs (AOP (left), AOP (result)) &&
8261       AOP_SIZE (result) > 1)
8262     {
8263
8264       size = AOP_SIZE (result);
8265       offset = 0;
8266       while (size--)
8267         {
8268           l = aopGet (left, offset, FALSE, TRUE);
8269           if (*l == '@' && (IS_AOP_PREG (result)))
8270             {
8271
8272               emitcode ("mov", "a,%s", l);
8273               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8274             }
8275           else
8276             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8277           offset++;
8278         }
8279     }
8280
8281   tlbl = newiTempLabel (NULL);
8282   size = AOP_SIZE (result);
8283   offset = 0;
8284   tlbl1 = newiTempLabel (NULL);
8285
8286   /* if it is only one byte then */
8287   if (size == 1)
8288     {
8289       symbol *tlbl1 = newiTempLabel (NULL);
8290
8291       l = aopGet (left, 0, FALSE, FALSE);
8292       MOVA (l);
8293       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8294       emitcode ("", "%05d$:", tlbl->key + 100);
8295       emitcode ("add", "a,acc");
8296       emitcode ("", "%05d$:", tlbl1->key + 100);
8297       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8298       popB (pushedB);
8299       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8300       goto release;
8301     }
8302
8303   reAdjustPreg (AOP (result));
8304
8305   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8306   emitcode ("", "%05d$:", tlbl->key + 100);
8307   l = aopGet (result, offset, FALSE, FALSE);
8308   MOVA (l);
8309   emitcode ("add", "a,acc");
8310   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8311   while (--size)
8312     {
8313       l = aopGet (result, offset, FALSE, FALSE);
8314       MOVA (l);
8315       emitcode ("rlc", "a");
8316       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8317     }
8318   reAdjustPreg (AOP (result));
8319
8320   emitcode ("", "%05d$:", tlbl1->key + 100);
8321   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8322   popB (pushedB);
8323 release:
8324   freeAsmop (left, NULL, ic, TRUE);
8325   freeAsmop (result, NULL, ic, TRUE);
8326 }
8327
8328 /*-----------------------------------------------------------------*/
8329 /* genrshOne - right shift a one byte quantity by known count      */
8330 /*-----------------------------------------------------------------*/
8331 static void
8332 genrshOne (operand * result, operand * left,
8333            int shCount, int sign)
8334 {
8335   D(emitcode (";     genrshOne",""));
8336
8337   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8338 }
8339
8340 /*-----------------------------------------------------------------*/
8341 /* genrshTwo - right shift two bytes by known amount != 0          */
8342 /*-----------------------------------------------------------------*/
8343 static void
8344 genrshTwo (operand * result, operand * left,
8345            int shCount, int sign)
8346 {
8347   D(emitcode (";     genrshTwo",""));
8348
8349   /* if shCount >= 8 */
8350   if (shCount >= 8)
8351     {
8352       shCount -= 8;
8353       if (shCount)
8354         shiftR1Left2Result (left, MSB16, result, LSB,
8355                             shCount, sign);
8356       else
8357         movLeft2Result (left, MSB16, result, LSB, sign);
8358       addSign (result, MSB16, sign);
8359     }
8360
8361   /*  1 <= shCount <= 7 */
8362   else
8363     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8364 }
8365
8366 /*-----------------------------------------------------------------*/
8367 /* shiftRLong - shift right one long from left to result           */
8368 /* offl = LSB or MSB16                                             */
8369 /*-----------------------------------------------------------------*/
8370 static void
8371 shiftRLong (operand * left, int offl,
8372             operand * result, int sign)
8373 {
8374   int isSameRegs=sameRegs(AOP(left),AOP(result));
8375
8376   if (isSameRegs && offl>1) {
8377     // we are in big trouble, but this shouldn't happen
8378     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8379   }
8380
8381   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8382
8383   if (offl==MSB16) {
8384     // shift is > 8
8385     if (sign) {
8386       emitcode ("rlc", "a");
8387       emitcode ("subb", "a,acc");
8388       if (isSameRegs)
8389         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8390       else {
8391         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8392         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8393       }
8394     } else {
8395       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8396     }
8397   }
8398
8399   if (!sign) {
8400     emitcode ("clr", "c");
8401   } else {
8402     emitcode ("mov", "c,acc.7");
8403   }
8404
8405   emitcode ("rrc", "a");
8406
8407   if (isSameRegs && offl==MSB16) {
8408     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8409   } else {
8410     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8411     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8412   }
8413
8414   emitcode ("rrc", "a");
8415   if (isSameRegs && offl==1) {
8416     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8417   } else {
8418     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8419     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8420   }
8421   emitcode ("rrc", "a");
8422   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8423
8424   if (offl == LSB)
8425     {
8426       MOVA (aopGet (left, LSB, FALSE, FALSE));
8427       emitcode ("rrc", "a");
8428       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8429     }
8430 }
8431
8432 /*-----------------------------------------------------------------*/
8433 /* genrshFour - shift four byte by a known amount != 0             */
8434 /*-----------------------------------------------------------------*/
8435 static void
8436 genrshFour (operand * result, operand * left,
8437             int shCount, int sign)
8438 {
8439   D(emitcode (";     genrshFour",""));
8440
8441   /* if shifting more that 3 bytes */
8442   if (shCount >= 24)
8443     {
8444       shCount -= 24;
8445       if (shCount)
8446         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8447       else
8448         movLeft2Result (left, MSB32, result, LSB, sign);
8449       addSign (result, MSB16, sign);
8450     }
8451   else if (shCount >= 16)
8452     {
8453       shCount -= 16;
8454       if (shCount)
8455         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8456       else
8457         {
8458           movLeft2Result (left, MSB24, result, LSB, 0);
8459           movLeft2Result (left, MSB32, result, MSB16, sign);
8460         }
8461       addSign (result, MSB24, sign);
8462     }
8463   else if (shCount >= 8)
8464     {
8465       shCount -= 8;
8466       if (shCount == 1)
8467         shiftRLong (left, MSB16, result, sign);
8468       else if (shCount == 0)
8469         {
8470           movLeft2Result (left, MSB16, result, LSB, 0);
8471           movLeft2Result (left, MSB24, result, MSB16, 0);
8472           movLeft2Result (left, MSB32, result, MSB24, sign);
8473           addSign (result, MSB32, sign);
8474         }
8475       else
8476         {
8477           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8478           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8479           /* the last shift is signed */
8480           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8481           addSign (result, MSB32, sign);
8482         }
8483     }
8484   else
8485     {                           /* 1 <= shCount <= 7 */
8486       if (shCount <= 2)
8487         {
8488           shiftRLong (left, LSB, result, sign);
8489           if (shCount == 2)
8490             shiftRLong (result, LSB, result, sign);
8491         }
8492       else
8493         {
8494           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8495           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8496           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8497         }
8498     }
8499 }
8500
8501 /*-----------------------------------------------------------------*/
8502 /* genRightShiftLiteral - right shifting by known count            */
8503 /*-----------------------------------------------------------------*/
8504 static void
8505 genRightShiftLiteral (operand * left,
8506                       operand * right,
8507                       operand * result,
8508                       iCode * ic,
8509                       int sign)
8510 {
8511   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8512   int size;
8513
8514   D(emitcode (";     genRightShiftLiteral",""));
8515
8516   freeAsmop (right, NULL, ic, TRUE);
8517
8518   aopOp (left, ic, FALSE);
8519   aopOp (result, ic, FALSE);
8520
8521 #if VIEW_SIZE
8522   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8523             AOP_SIZE (left));
8524 #endif
8525
8526   size = getDataSize (left);
8527   /* test the LEFT size !!! */
8528
8529   /* I suppose that the left size >= result size */
8530   if (shCount == 0)
8531     {
8532       size = getDataSize (result);
8533       while (size--)
8534         movLeft2Result (left, size, result, size, 0);
8535     }
8536
8537   else if (shCount >= (size * 8))
8538     {
8539       if (sign) {
8540         /* get sign in acc.7 */
8541         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8542       }
8543       addSign (result, LSB, sign);
8544     }
8545   else
8546     {
8547       switch (size)
8548         {
8549         case 1:
8550           genrshOne (result, left, shCount, sign);
8551           break;
8552
8553         case 2:
8554           genrshTwo (result, left, shCount, sign);
8555           break;
8556
8557         case 4:
8558           genrshFour (result, left, shCount, sign);
8559           break;
8560         default:
8561           break;
8562         }
8563     }
8564   freeAsmop (left, NULL, ic, TRUE);
8565   freeAsmop (result, NULL, ic, TRUE);
8566 }
8567
8568 /*-----------------------------------------------------------------*/
8569 /* genSignedRightShift - right shift of signed number              */
8570 /*-----------------------------------------------------------------*/
8571 static void
8572 genSignedRightShift (iCode * ic)
8573 {
8574   operand *right, *left, *result;
8575   int size, offset;
8576   char *l;
8577   symbol *tlbl, *tlbl1;
8578   bool pushedB;
8579
8580   D(emitcode (";     genSignedRightShift",""));
8581
8582   /* we do it the hard way put the shift count in b
8583      and loop thru preserving the sign */
8584
8585   right = IC_RIGHT (ic);
8586   left = IC_LEFT (ic);
8587   result = IC_RESULT (ic);
8588
8589   aopOp (right, ic, FALSE);
8590
8591
8592   if (AOP_TYPE (right) == AOP_LIT)
8593     {
8594       genRightShiftLiteral (left, right, result, ic, 1);
8595       return;
8596     }
8597   /* shift count is unknown then we have to form
8598      a loop get the loop count in B : Note: we take
8599      only the lower order byte since shifting
8600      more that 32 bits make no sense anyway, ( the
8601      largest size of an object can be only 32 bits ) */
8602
8603   pushedB = pushB ();
8604   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8605   emitcode ("inc", "b");
8606   freeAsmop (right, NULL, ic, TRUE);
8607   aopOp (left, ic, FALSE);
8608   aopOp (result, ic, FALSE);
8609
8610   /* now move the left to the result if they are not the
8611      same */
8612   if (!sameRegs (AOP (left), AOP (result)) &&
8613       AOP_SIZE (result) > 1)
8614     {
8615
8616       size = AOP_SIZE (result);
8617       offset = 0;
8618       while (size--)
8619         {
8620           l = aopGet (left, offset, FALSE, TRUE);
8621           if (*l == '@' && IS_AOP_PREG (result))
8622             {
8623
8624               emitcode ("mov", "a,%s", l);
8625               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8626             }
8627           else
8628             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8629           offset++;
8630         }
8631     }
8632
8633   /* mov the highest order bit to OVR */
8634   tlbl = newiTempLabel (NULL);
8635   tlbl1 = newiTempLabel (NULL);
8636
8637   size = AOP_SIZE (result);
8638   offset = size - 1;
8639   MOVA (aopGet (left, offset, FALSE, FALSE));
8640   emitcode ("rlc", "a");
8641   emitcode ("mov", "ov,c");
8642   /* if it is only one byte then */
8643   if (size == 1)
8644     {
8645       l = aopGet (left, 0, FALSE, FALSE);
8646       MOVA (l);
8647       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8648       emitcode ("", "%05d$:", tlbl->key + 100);
8649       emitcode ("mov", "c,ov");
8650       emitcode ("rrc", "a");
8651       emitcode ("", "%05d$:", tlbl1->key + 100);
8652       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8653       popB (pushedB);
8654       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8655       goto release;
8656     }
8657
8658   reAdjustPreg (AOP (result));
8659   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8660   emitcode ("", "%05d$:", tlbl->key + 100);
8661   emitcode ("mov", "c,ov");
8662   while (size--)
8663     {
8664       l = aopGet (result, offset, FALSE, FALSE);
8665       MOVA (l);
8666       emitcode ("rrc", "a");
8667       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8668     }
8669   reAdjustPreg (AOP (result));
8670   emitcode ("", "%05d$:", tlbl1->key + 100);
8671   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8672   popB (pushedB);
8673
8674 release:
8675   freeAsmop (left, NULL, ic, TRUE);
8676   freeAsmop (result, NULL, ic, TRUE);
8677 }
8678
8679 /*-----------------------------------------------------------------*/
8680 /* genRightShift - generate code for right shifting                */
8681 /*-----------------------------------------------------------------*/
8682 static void
8683 genRightShift (iCode * ic)
8684 {
8685   operand *right, *left, *result;
8686   sym_link *letype;
8687   int size, offset;
8688   char *l;
8689   symbol *tlbl, *tlbl1;
8690   bool pushedB;
8691
8692   D(emitcode (";     genRightShift",""));
8693
8694   /* if signed then we do it the hard way preserve the
8695      sign bit moving it inwards */
8696   letype = getSpec (operandType (IC_LEFT (ic)));
8697
8698   if (!SPEC_USIGN (letype))
8699     {
8700       genSignedRightShift (ic);
8701       return;
8702     }
8703
8704   /* signed & unsigned types are treated the same : i.e. the
8705      signed is NOT propagated inwards : quoting from the
8706      ANSI - standard : "for E1 >> E2, is equivalent to division
8707      by 2**E2 if unsigned or if it has a non-negative value,
8708      otherwise the result is implementation defined ", MY definition
8709      is that the sign does not get propagated */
8710
8711   right = IC_RIGHT (ic);
8712   left = IC_LEFT (ic);
8713   result = IC_RESULT (ic);
8714
8715   aopOp (right, ic, FALSE);
8716
8717   /* if the shift count is known then do it
8718      as efficiently as possible */
8719   if (AOP_TYPE (right) == AOP_LIT)
8720     {
8721       genRightShiftLiteral (left, right, result, ic, 0);
8722       return;
8723     }
8724
8725   /* shift count is unknown then we have to form
8726      a loop get the loop count in B : Note: we take
8727      only the lower order byte since shifting
8728      more that 32 bits make no sense anyway, ( the
8729      largest size of an object can be only 32 bits ) */
8730
8731   pushedB = pushB ();
8732   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8733   emitcode ("inc", "b");
8734   freeAsmop (right, NULL, ic, TRUE);
8735   aopOp (left, ic, FALSE);
8736   aopOp (result, ic, FALSE);
8737
8738   /* now move the left to the result if they are not the
8739      same */
8740   if (!sameRegs (AOP (left), AOP (result)) &&
8741       AOP_SIZE (result) > 1)
8742     {
8743
8744       size = AOP_SIZE (result);
8745       offset = 0;
8746       while (size--)
8747         {
8748           l = aopGet (left, offset, FALSE, TRUE);
8749           if (*l == '@' && IS_AOP_PREG (result))
8750             {
8751
8752               emitcode ("mov", "a,%s", l);
8753               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8754             }
8755           else
8756             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8757           offset++;
8758         }
8759     }
8760
8761   tlbl = newiTempLabel (NULL);
8762   tlbl1 = newiTempLabel (NULL);
8763   size = AOP_SIZE (result);
8764   offset = size - 1;
8765
8766   /* if it is only one byte then */
8767   if (size == 1)
8768     {
8769       l = aopGet (left, 0, FALSE, FALSE);
8770       MOVA (l);
8771       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8772       emitcode ("", "%05d$:", tlbl->key + 100);
8773       CLRC;
8774       emitcode ("rrc", "a");
8775       emitcode ("", "%05d$:", tlbl1->key + 100);
8776       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8777       popB (pushedB);
8778       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8779       goto release;
8780     }
8781
8782   reAdjustPreg (AOP (result));
8783   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8784   emitcode ("", "%05d$:", tlbl->key + 100);
8785   CLRC;
8786   while (size--)
8787     {
8788       l = aopGet (result, offset, FALSE, FALSE);
8789       MOVA (l);
8790       emitcode ("rrc", "a");
8791       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8792     }
8793   reAdjustPreg (AOP (result));
8794
8795   emitcode ("", "%05d$:", tlbl1->key + 100);
8796   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8797   popB (pushedB);
8798
8799 release:
8800   freeAsmop (left, NULL, ic, TRUE);
8801   freeAsmop (result, NULL, ic, TRUE);
8802 }
8803
8804 /*-----------------------------------------------------------------*/
8805 /* emitPtrByteGet - emits code to get a byte into A through a      */
8806 /*                  pointer register (R0, R1, or DPTR). The        */
8807 /*                  original value of A can be preserved in B.     */
8808 /*-----------------------------------------------------------------*/
8809 static void
8810 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8811 {
8812   switch (p_type)
8813     {
8814     case IPOINTER:
8815     case POINTER:
8816       if (preserveAinB)
8817         emitcode ("mov", "b,a");
8818       emitcode ("mov", "a,@%s", rname);
8819       break;
8820
8821     case PPOINTER:
8822       if (preserveAinB)
8823         emitcode ("mov", "b,a");
8824       emitcode ("movx", "a,@%s", rname);
8825       break;
8826
8827     case FPOINTER:
8828       if (preserveAinB)
8829         emitcode ("mov", "b,a");
8830       emitcode ("movx", "a,@dptr");
8831       break;
8832
8833     case CPOINTER:
8834       if (preserveAinB)
8835         emitcode ("mov", "b,a");
8836       emitcode ("clr", "a");
8837       emitcode ("movc", "a,@a+dptr");
8838       break;
8839
8840     case GPOINTER:
8841       if (preserveAinB)
8842         {
8843           emitcode ("push", "b");
8844           emitcode ("push", "acc");
8845         }
8846       emitcode ("lcall", "__gptrget");
8847       if (preserveAinB)
8848         emitcode ("pop", "b");
8849       break;
8850     }
8851 }
8852
8853 /*-----------------------------------------------------------------*/
8854 /* emitPtrByteSet - emits code to set a byte from src through a    */
8855 /*                  pointer register (R0, R1, or DPTR).            */
8856 /*-----------------------------------------------------------------*/
8857 static void
8858 emitPtrByteSet (char *rname, int p_type, char *src)
8859 {
8860   switch (p_type)
8861     {
8862     case IPOINTER:
8863     case POINTER:
8864       if (*src=='@')
8865         {
8866           MOVA (src);
8867           emitcode ("mov", "@%s,a", rname);
8868         }
8869       else
8870         emitcode ("mov", "@%s,%s", rname, src);
8871       break;
8872
8873     case PPOINTER:
8874       MOVA (src);
8875       emitcode ("movx", "@%s,a", rname);
8876       break;
8877
8878     case FPOINTER:
8879       MOVA (src);
8880       emitcode ("movx", "@dptr,a");
8881       break;
8882
8883     case GPOINTER:
8884       MOVA (src);
8885       emitcode ("lcall", "__gptrput");
8886       break;
8887     }
8888 }
8889
8890 /*-----------------------------------------------------------------*/
8891 /* genUnpackBits - generates code for unpacking bits               */
8892 /*-----------------------------------------------------------------*/
8893 static void
8894 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8895 {
8896   int offset = 0;       /* result byte offset */
8897   int rsize;            /* result size */
8898   int rlen = 0;         /* remaining bitfield length */
8899   sym_link *etype;      /* bitfield type information */
8900   int blen;             /* bitfield length */
8901   int bstr;             /* bitfield starting bit within byte */
8902   char buffer[10];
8903
8904   D(emitcode (";     genUnpackBits",""));
8905
8906   etype = getSpec (operandType (result));
8907   rsize = getSize (operandType (result));
8908   blen = SPEC_BLEN (etype);
8909   bstr = SPEC_BSTR (etype);
8910
8911   if (ifx && blen <= 8)
8912     {
8913       emitPtrByteGet (rname, ptype, FALSE);
8914       if (blen == 1)
8915         {
8916           SNPRINTF (buffer, sizeof(buffer),
8917                     "acc.%d", bstr);
8918           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8919         }
8920       else
8921         {
8922           if (blen < 8)
8923             emitcode ("anl", "a,#0x%02x",
8924                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8925           genIfxJump (ifx, "a", NULL, NULL, NULL);
8926         }
8927       return;
8928     }
8929   wassert (!ifx);
8930
8931   /* If the bitfield length is less than a byte */
8932   if (blen < 8)
8933     {
8934       emitPtrByteGet (rname, ptype, FALSE);
8935       AccRsh (bstr);
8936       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8937       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8938       goto finish;
8939     }
8940
8941   /* Bit field did not fit in a byte. Copy all
8942      but the partial byte at the end.  */
8943   for (rlen=blen;rlen>=8;rlen-=8)
8944     {
8945       emitPtrByteGet (rname, ptype, FALSE);
8946       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8947       if (rlen>8)
8948         emitcode ("inc", "%s", rname);
8949     }
8950
8951   /* Handle the partial byte at the end */
8952   if (rlen)
8953     {
8954       emitPtrByteGet (rname, ptype, FALSE);
8955       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8956       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8957     }
8958
8959 finish:
8960   if (offset < rsize)
8961     {
8962       rsize -= offset;
8963       while (rsize--)
8964         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
8965     }
8966 }
8967
8968
8969 /*-----------------------------------------------------------------*/
8970 /* genDataPointerGet - generates code when ptr offset is known     */
8971 /*-----------------------------------------------------------------*/
8972 static void
8973 genDataPointerGet (operand * left,
8974                    operand * result,
8975                    iCode * ic)
8976 {
8977   char *l;
8978   char buffer[256];
8979   int size, offset = 0;
8980
8981   D(emitcode (";     genDataPointerGet",""));
8982
8983   aopOp (result, ic, TRUE);
8984
8985   /* get the string representation of the name */
8986   l = aopGet (left, 0, FALSE, TRUE);
8987   size = AOP_SIZE (result);
8988   while (size--)
8989     {
8990       if (offset)
8991         sprintf (buffer, "(%s + %d)", l + 1, offset);
8992       else
8993         sprintf (buffer, "%s", l + 1);
8994       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
8995     }
8996
8997   freeAsmop (left, NULL, ic, TRUE);
8998   freeAsmop (result, NULL, ic, TRUE);
8999 }
9000
9001 /*-----------------------------------------------------------------*/
9002 /* genNearPointerGet - emitcode for near pointer fetch             */
9003 /*-----------------------------------------------------------------*/
9004 static void
9005 genNearPointerGet (operand * left,
9006                    operand * result,
9007                    iCode * ic,
9008                    iCode * pi,
9009                    iCode * ifx)
9010 {
9011   asmop *aop = NULL;
9012   regs *preg = NULL;
9013   char *rname;
9014   sym_link *rtype, *retype;
9015   sym_link *ltype = operandType (left);
9016   char buffer[80];
9017
9018   D(emitcode (";     genNearPointerGet",""));
9019
9020   rtype = operandType (result);
9021   retype = getSpec (rtype);
9022
9023   aopOp (left, ic, FALSE);
9024
9025   /* if left is rematerialisable and
9026      result is not bitfield variable type and
9027      the left is pointer to data space i.e
9028      lower 128 bytes of space */
9029   if (AOP_TYPE (left) == AOP_IMMD &&
9030       !IS_BITFIELD (retype) &&
9031       DCL_TYPE (ltype) == POINTER)
9032     {
9033       genDataPointerGet (left, result, ic);
9034       return;
9035     }
9036
9037  /* if the value is already in a pointer register
9038      then don't need anything more */
9039   if (!AOP_INPREG (AOP (left)))
9040     {
9041       if (IS_AOP_PREG (left))
9042         {
9043           // Aha, it is a pointer, just in disguise.
9044           rname = aopGet (left, 0, FALSE, FALSE);
9045           if (*rname != '@')
9046             {
9047               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9048                       __FILE__, __LINE__);
9049             }
9050           else
9051             {
9052               // Expected case.
9053               emitcode ("mov", "a%s,%s", rname + 1, rname);
9054               rname++;  // skip the '@'.
9055             }
9056         }
9057       else
9058         {
9059           /* otherwise get a free pointer register */
9060           aop = newAsmop (0);
9061           preg = getFreePtr (ic, &aop, FALSE);
9062           emitcode ("mov", "%s,%s",
9063                     preg->name,
9064                     aopGet (left, 0, FALSE, TRUE));
9065           rname = preg->name;
9066         }
9067     }
9068   else
9069     rname = aopGet (left, 0, FALSE, FALSE);
9070
9071   //aopOp (result, ic, FALSE);
9072   aopOp (result, ic, result?TRUE:FALSE);
9073
9074   /* if bitfield then unpack the bits */
9075   if (IS_BITFIELD (retype))
9076     genUnpackBits (result, rname, POINTER, ifx);
9077   else
9078     {
9079       /* we have can just get the values */
9080       int size = AOP_SIZE (result);
9081       int offset = 0;
9082
9083       while (size--)
9084         {
9085           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9086             {
9087
9088               emitcode ("mov", "a,@%s", rname);
9089               if (!ifx)
9090               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9091             }
9092           else
9093             {
9094               sprintf (buffer, "@%s", rname);
9095               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9096             }
9097           offset++;
9098           if (size || pi)
9099             emitcode ("inc", "%s", rname);
9100         }
9101     }
9102
9103   /* now some housekeeping stuff */
9104   if (aop)       /* we had to allocate for this iCode */
9105     {
9106       if (pi) { /* post increment present */
9107         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9108       }
9109       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9110     }
9111   else
9112     {
9113       /* we did not allocate which means left
9114          already in a pointer register, then
9115          if size > 0 && this could be used again
9116          we have to point it back to where it
9117          belongs */
9118       if ((AOP_SIZE (result) > 1 &&
9119            !OP_SYMBOL (left)->remat &&
9120            (OP_SYMBOL (left)->liveTo > ic->seq ||
9121             ic->depth)) &&
9122           !pi)
9123         {
9124           int size = AOP_SIZE (result) - 1;
9125           while (size--)
9126             emitcode ("dec", "%s", rname);
9127         }
9128     }
9129
9130   if (ifx && !ifx->generated)
9131     {
9132       genIfxJump (ifx, "a", left, NULL, result);
9133     }
9134
9135   /* done */
9136   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9137   freeAsmop (left, NULL, ic, TRUE);
9138   if (pi) pi->generated = 1;
9139 }
9140
9141 /*-----------------------------------------------------------------*/
9142 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9143 /*-----------------------------------------------------------------*/
9144 static void
9145 genPagedPointerGet (operand * left,
9146                     operand * result,
9147                     iCode * ic,
9148                     iCode *pi,
9149                     iCode *ifx)
9150 {
9151   asmop *aop = NULL;
9152   regs *preg = NULL;
9153   char *rname;
9154   sym_link *rtype, *retype;
9155
9156   D(emitcode (";     genPagedPointerGet",""));
9157
9158   rtype = operandType (result);
9159   retype = getSpec (rtype);
9160
9161   aopOp (left, ic, FALSE);
9162
9163   /* if the value is already in a pointer register
9164      then don't need anything more */
9165   if (!AOP_INPREG (AOP (left)))
9166     {
9167       /* otherwise get a free pointer register */
9168       aop = newAsmop (0);
9169       preg = getFreePtr (ic, &aop, FALSE);
9170       emitcode ("mov", "%s,%s",
9171                 preg->name,
9172                 aopGet (left, 0, FALSE, TRUE));
9173       rname = preg->name;
9174     }
9175   else
9176     rname = aopGet (left, 0, FALSE, FALSE);
9177
9178   aopOp (result, ic, FALSE);
9179
9180   /* if bitfield then unpack the bits */
9181   if (IS_BITFIELD (retype))
9182     genUnpackBits (result, rname, PPOINTER, ifx);
9183   else
9184     {
9185       /* we have can just get the values */
9186       int size = AOP_SIZE (result);
9187       int offset = 0;
9188
9189       while (size--)
9190         {
9191
9192           emitcode ("movx", "a,@%s", rname);
9193           if (!ifx)
9194           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9195
9196           offset++;
9197
9198           if (size || pi)
9199             emitcode ("inc", "%s", rname);
9200         }
9201     }
9202
9203   /* now some housekeeping stuff */
9204   if (aop) /* we had to allocate for this iCode */
9205     {
9206       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9207       freeAsmop (NULL, aop, ic, TRUE);
9208     }
9209   else
9210     {
9211       /* we did not allocate which means left
9212          already in a pointer register, then
9213          if size > 0 && this could be used again
9214          we have to point it back to where it
9215          belongs */
9216       if ((AOP_SIZE (result) > 1 &&
9217            !OP_SYMBOL (left)->remat &&
9218            (OP_SYMBOL (left)->liveTo > ic->seq ||
9219             ic->depth)) &&
9220           !pi)
9221         {
9222           int size = AOP_SIZE (result) - 1;
9223           while (size--)
9224             emitcode ("dec", "%s", rname);
9225         }
9226     }
9227
9228   if (ifx && !ifx->generated)
9229     {
9230       genIfxJump (ifx, "a", left, NULL, result);
9231     }
9232
9233   /* done */
9234   freeAsmop (left, NULL, ic, TRUE);
9235   freeAsmop (result, NULL, ic, TRUE);
9236   if (pi) pi->generated = 1;
9237
9238 }
9239
9240 /*--------------------------------------------------------------------*/
9241 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9242 /*--------------------------------------------------------------------*/
9243 static void
9244 loadDptrFromOperand (operand *op, bool loadBToo)
9245 {
9246   if (AOP_TYPE (op) != AOP_STR)
9247     {
9248       /* if this is rematerializable */
9249       if (AOP_TYPE (op) == AOP_IMMD)
9250         {
9251           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9252           if (loadBToo)
9253             {
9254               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9255                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9256               else
9257                 {
9258                   wassertl(FALSE, "need pointerCode");
9259                   emitcode ("", "; mov b,???");
9260                   /* genPointerGet and genPointerSet originally did different
9261                   ** things for this case. Both seem wrong.
9262                   ** from genPointerGet:
9263                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9264                   ** from genPointerSet:
9265                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9266                   */
9267                 }
9268             }
9269         }
9270       else if (AOP_TYPE (op) == AOP_DPTR)
9271         {
9272           if (loadBToo)
9273             {
9274               MOVA (aopGet (op, 0, FALSE, FALSE));
9275               emitcode ("push", "acc");
9276               MOVA (aopGet (op, 1, FALSE, FALSE));
9277               emitcode ("push", "acc");
9278               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9279               emitcode ("pop", "dph");
9280               emitcode ("pop", "dpl");
9281             }
9282           else
9283             {
9284               MOVA (aopGet (op, 0, FALSE, FALSE));
9285               emitcode ("push", "acc");
9286               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9287               emitcode ("pop", "dpl");
9288             }
9289         }
9290       else
9291         {                       /* we need to get it byte by byte */
9292           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9293           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9294           if (loadBToo)
9295             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9296         }
9297     }
9298 }
9299
9300 /*-----------------------------------------------------------------*/
9301 /* genFarPointerGet - gget value from far space                    */
9302 /*-----------------------------------------------------------------*/
9303 static void
9304 genFarPointerGet (operand * left,
9305                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9306 {
9307   int size, offset;
9308   sym_link *retype = getSpec (operandType (result));
9309
9310   D(emitcode (";     genFarPointerGet",""));
9311
9312   aopOp (left, ic, FALSE);
9313   loadDptrFromOperand (left, FALSE);
9314
9315   /* so dptr now contains the address */
9316   aopOp (result, ic, FALSE);
9317
9318   /* if bit then unpack */
9319   if (IS_BITFIELD (retype))
9320     genUnpackBits (result, "dptr", FPOINTER, ifx);
9321   else
9322     {
9323       size = AOP_SIZE (result);
9324       offset = 0;
9325
9326       while (size--)
9327         {
9328           emitcode ("movx", "a,@dptr");
9329           if (!ifx)
9330             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9331           if (size || pi)
9332             emitcode ("inc", "dptr");
9333         }
9334     }
9335
9336   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9337     {
9338     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9339     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9340     pi->generated = 1;
9341   }
9342
9343   if (ifx && !ifx->generated)
9344     {
9345       genIfxJump (ifx, "a", left, NULL, result);
9346     }
9347
9348   freeAsmop (left, NULL, ic, TRUE);
9349   freeAsmop (result, NULL, ic, TRUE);
9350 }
9351
9352 /*-----------------------------------------------------------------*/
9353 /* genCodePointerGet - gget value from code space                  */
9354 /*-----------------------------------------------------------------*/
9355 static void
9356 genCodePointerGet (operand * left,
9357                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9358 {
9359   int size, offset;
9360   sym_link *retype = getSpec (operandType (result));
9361
9362   D(emitcode (";     genCodePointerGet",""));
9363
9364   aopOp (left, ic, FALSE);
9365   loadDptrFromOperand (left, FALSE);
9366
9367   /* so dptr now contains the address */
9368   aopOp (result, ic, FALSE);
9369
9370   /* if bit then unpack */
9371   if (IS_BITFIELD (retype))
9372     genUnpackBits (result, "dptr", CPOINTER, ifx);
9373   else
9374     {
9375       size = AOP_SIZE (result);
9376       offset = 0;
9377
9378       while (size--)
9379         {
9380           if (pi)
9381             {
9382               emitcode ("clr", "a");
9383               emitcode ("movc", "a,@a+dptr");
9384               if (!ifx)
9385               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9386               emitcode ("inc", "dptr");
9387             }
9388           else
9389             {
9390               emitcode ("mov", "a,#0x%02x", offset);
9391               emitcode ("movc", "a,@a+dptr");
9392               if (!ifx)
9393               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9394             }
9395         }
9396     }
9397
9398   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9399     {
9400     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9401     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9402     pi->generated = 1;
9403   }
9404
9405   if (ifx && !ifx->generated)
9406     {
9407       genIfxJump (ifx, "a", left, NULL, result);
9408     }
9409
9410   freeAsmop (left, NULL, ic, TRUE);
9411   freeAsmop (result, NULL, ic, TRUE);
9412 }
9413
9414 /*-----------------------------------------------------------------*/
9415 /* genGenPointerGet - gget value from generic pointer space        */
9416 /*-----------------------------------------------------------------*/
9417 static void
9418 genGenPointerGet (operand * left,
9419                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9420 {
9421   int size, offset;
9422   sym_link *retype = getSpec (operandType (result));
9423
9424   D(emitcode (";     genGenPointerGet",""));
9425
9426   aopOp (left, ic, FALSE);
9427   loadDptrFromOperand (left, TRUE);
9428
9429   /* so dptr know contains the address */
9430   aopOp (result, ic, FALSE);
9431
9432   /* if bit then unpack */
9433   if (IS_BITFIELD (retype))
9434     genUnpackBits (result, "dptr", GPOINTER, ifx);
9435   else
9436     {
9437       size = AOP_SIZE (result);
9438       offset = 0;
9439
9440       while (size--)
9441         {
9442           emitcode ("lcall", "__gptrget");
9443           if (!ifx)
9444           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9445           if (size || pi)
9446             emitcode ("inc", "dptr");
9447         }
9448     }
9449
9450   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9451     {
9452     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9453     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9454     pi->generated = 1;
9455   }
9456
9457   if (ifx && !ifx->generated)
9458     {
9459       genIfxJump (ifx, "a", left, NULL, result);
9460     }
9461
9462
9463   freeAsmop (left, NULL, ic, TRUE);
9464   freeAsmop (result, NULL, ic, TRUE);
9465 }
9466
9467 /*-----------------------------------------------------------------*/
9468 /* genPointerGet - generate code for pointer get                   */
9469 /*-----------------------------------------------------------------*/
9470 static void
9471 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9472 {
9473   operand *left, *result;
9474   sym_link *type, *etype;
9475   int p_type;
9476
9477   D(emitcode (";     genPointerGet",""));
9478
9479   left = IC_LEFT (ic);
9480   result = IC_RESULT (ic);
9481
9482   if (getSize (operandType (result))>1)
9483     ifx = NULL;
9484
9485   /* depending on the type of pointer we need to
9486      move it to the correct pointer register */
9487   type = operandType (left);
9488   etype = getSpec (type);
9489   /* if left is of type of pointer then it is simple */
9490   if (IS_PTR (type) && !IS_FUNC (type->next))
9491     p_type = DCL_TYPE (type);
9492   else
9493     {
9494       /* we have to go by the storage class */
9495       p_type = PTR_TYPE (SPEC_OCLS (etype));
9496     }
9497
9498   /* special case when cast remat */
9499   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9500       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9501           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9502           type = operandType (left);
9503           p_type = DCL_TYPE (type);
9504   }
9505   /* now that we have the pointer type we assign
9506      the pointer values */
9507   switch (p_type)
9508     {
9509
9510     case POINTER:
9511     case IPOINTER:
9512       genNearPointerGet (left, result, ic, pi, ifx);
9513       break;
9514
9515     case PPOINTER:
9516       genPagedPointerGet (left, result, ic, pi, ifx);
9517       break;
9518
9519     case FPOINTER:
9520       genFarPointerGet (left, result, ic, pi, ifx);
9521       break;
9522
9523     case CPOINTER:
9524       genCodePointerGet (left, result, ic, pi, ifx);
9525       break;
9526
9527     case GPOINTER:
9528       genGenPointerGet (left, result, ic, pi, ifx);
9529       break;
9530     }
9531
9532 }
9533
9534
9535
9536 /*-----------------------------------------------------------------*/
9537 /* genPackBits - generates code for packed bit storage             */
9538 /*-----------------------------------------------------------------*/
9539 static void
9540 genPackBits (sym_link * etype,
9541              operand * right,
9542              char *rname, int p_type)
9543 {
9544   int offset = 0;       /* source byte offset */
9545   int rlen = 0;         /* remaining bitfield length */
9546   int blen;             /* bitfield length */
9547   int bstr;             /* bitfield starting bit within byte */
9548   int litval;           /* source literal value (if AOP_LIT) */
9549   unsigned char mask;   /* bitmask within current byte */
9550
9551   D(emitcode (";     genPackBits",""));
9552
9553   blen = SPEC_BLEN (etype);
9554   bstr = SPEC_BSTR (etype);
9555
9556   /* If the bitfield length is less than a byte */
9557   if (blen < 8)
9558     {
9559       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9560               (unsigned char) (0xFF >> (8 - bstr)));
9561
9562       if (AOP_TYPE (right) == AOP_LIT)
9563         {
9564           /* Case with a bitfield length <8 and literal source
9565           */
9566           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9567           litval <<= bstr;
9568           litval &= (~mask) & 0xff;
9569           emitPtrByteGet (rname, p_type, FALSE);
9570           if ((mask|litval)!=0xff)
9571             emitcode ("anl","a,#0x%02x", mask);
9572           if (litval)
9573             emitcode ("orl","a,#0x%02x", litval);
9574         }
9575       else
9576         {
9577           if ((blen==1) && (p_type!=GPOINTER))
9578             {
9579               /* Case with a bitfield length == 1 and no generic pointer
9580               */
9581               if (AOP_TYPE (right) == AOP_CRY)
9582                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9583               else
9584                 {
9585                   MOVA (aopGet (right, 0, FALSE, FALSE));
9586                   emitcode ("rrc","a");
9587                 }
9588               emitPtrByteGet (rname, p_type, FALSE);
9589               emitcode ("mov","acc.%d,c",bstr);
9590             }
9591           else
9592             {
9593               bool pushedB;
9594               /* Case with a bitfield length < 8 and arbitrary source
9595               */
9596               MOVA (aopGet (right, 0, FALSE, FALSE));
9597               /* shift and mask source value */
9598               AccLsh (bstr);
9599               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9600
9601               pushedB = pushB ();
9602               /* transfer A to B and get next byte */
9603               emitPtrByteGet (rname, p_type, TRUE);
9604
9605               emitcode ("anl", "a,#0x%02x", mask);
9606               emitcode ("orl", "a,b");
9607               if (p_type == GPOINTER)
9608                 emitcode ("pop", "b");
9609
9610               popB (pushedB);
9611            }
9612         }
9613
9614       emitPtrByteSet (rname, p_type, "a");
9615       return;
9616     }
9617
9618   /* Bit length is greater than 7 bits. In this case, copy  */
9619   /* all except the partial byte at the end                 */
9620   for (rlen=blen;rlen>=8;rlen-=8)
9621     {
9622       emitPtrByteSet (rname, p_type,
9623                       aopGet (right, offset++, FALSE, TRUE) );
9624       if (rlen>8)
9625         emitcode ("inc", "%s", rname);
9626     }
9627
9628   /* If there was a partial byte at the end */
9629   if (rlen)
9630     {
9631       mask = (((unsigned char) -1 << rlen) & 0xff);
9632
9633       if (AOP_TYPE (right) == AOP_LIT)
9634         {
9635           /* Case with partial byte and literal source
9636           */
9637           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9638           litval >>= (blen-rlen);
9639           litval &= (~mask) & 0xff;
9640           emitPtrByteGet (rname, p_type, FALSE);
9641           if ((mask|litval)!=0xff)
9642             emitcode ("anl","a,#0x%02x", mask);
9643           if (litval)
9644             emitcode ("orl","a,#0x%02x", litval);
9645         }
9646       else
9647         {
9648           bool pushedB;
9649           /* Case with partial byte and arbitrary source
9650           */
9651           MOVA (aopGet (right, offset++, FALSE, FALSE));
9652           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9653
9654           pushedB = pushB ();
9655           /* transfer A to B and get next byte */
9656           emitPtrByteGet (rname, p_type, TRUE);
9657
9658           emitcode ("anl", "a,#0x%02x", mask);
9659           emitcode ("orl", "a,b");
9660           if (p_type == GPOINTER)
9661             emitcode ("pop", "b");
9662
9663           popB (pushedB);
9664         }
9665       emitPtrByteSet (rname, p_type, "a");
9666     }
9667
9668 }
9669
9670
9671 /*-----------------------------------------------------------------*/
9672 /* genDataPointerSet - remat pointer to data space                 */
9673 /*-----------------------------------------------------------------*/
9674 static void
9675 genDataPointerSet (operand * right,
9676                    operand * result,
9677                    iCode * ic)
9678 {
9679   int size, offset = 0;
9680   char *l, buffer[256];
9681
9682   D(emitcode (";     genDataPointerSet",""));
9683
9684   aopOp (right, ic, FALSE);
9685
9686   l = aopGet (result, 0, FALSE, TRUE);
9687   size = AOP_SIZE (right);
9688   while (size--)
9689     {
9690       if (offset)
9691         sprintf (buffer, "(%s + %d)", l + 1, offset);
9692       else
9693         sprintf (buffer, "%s", l + 1);
9694       emitcode ("mov", "%s,%s", buffer,
9695                 aopGet (right, offset++, FALSE, FALSE));
9696     }
9697
9698   freeAsmop (right, NULL, ic, TRUE);
9699   freeAsmop (result, NULL, ic, TRUE);
9700 }
9701
9702 /*-----------------------------------------------------------------*/
9703 /* genNearPointerSet - emitcode for near pointer put                */
9704 /*-----------------------------------------------------------------*/
9705 static void
9706 genNearPointerSet (operand * right,
9707                    operand * result,
9708                    iCode * ic,
9709                    iCode * pi)
9710 {
9711   asmop *aop = NULL;
9712   regs *preg = NULL;
9713   char *rname, *l;
9714   sym_link *retype, *letype;
9715   sym_link *ptype = operandType (result);
9716
9717   D(emitcode (";     genNearPointerSet",""));
9718
9719   retype = getSpec (operandType (right));
9720   letype = getSpec (ptype);
9721   aopOp (result, ic, FALSE);
9722
9723   /* if the result is rematerializable &
9724      in data space & not a bit variable */
9725   if (AOP_TYPE (result) == AOP_IMMD &&
9726       DCL_TYPE (ptype) == POINTER &&
9727       !IS_BITVAR (retype) &&
9728       !IS_BITVAR (letype))
9729     {
9730       genDataPointerSet (right, result, ic);
9731       return;
9732     }
9733
9734   /* if the value is already in a pointer register
9735      then don't need anything more */
9736   if (!AOP_INPREG (AOP (result)))
9737     {
9738         if (
9739             //AOP_TYPE (result) == AOP_STK
9740             IS_AOP_PREG(result)
9741             )
9742         {
9743             // Aha, it is a pointer, just in disguise.
9744             rname = aopGet (result, 0, FALSE, FALSE);
9745             if (*rname != '@')
9746             {
9747                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9748                         __FILE__, __LINE__);
9749             }
9750             else
9751             {
9752                 // Expected case.
9753                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9754                 rname++;  // skip the '@'.
9755             }
9756         }
9757         else
9758         {
9759             /* otherwise get a free pointer register */
9760             aop = newAsmop (0);
9761             preg = getFreePtr (ic, &aop, FALSE);
9762             emitcode ("mov", "%s,%s",
9763                       preg->name,
9764                       aopGet (result, 0, FALSE, TRUE));
9765             rname = preg->name;
9766         }
9767     }
9768     else
9769     {
9770         rname = aopGet (result, 0, FALSE, FALSE);
9771     }
9772
9773   aopOp (right, ic, FALSE);
9774
9775   /* if bitfield then unpack the bits */
9776   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9777     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9778   else
9779     {
9780       /* we have can just get the values */
9781       int size = AOP_SIZE (right);
9782       int offset = 0;
9783
9784       while (size--)
9785         {
9786           l = aopGet (right, offset, FALSE, TRUE);
9787           if (*l == '@')
9788             {
9789               MOVA (l);
9790               emitcode ("mov", "@%s,a", rname);
9791             }
9792           else
9793             emitcode ("mov", "@%s,%s", rname, l);
9794           if (size || pi)
9795             emitcode ("inc", "%s", rname);
9796           offset++;
9797         }
9798     }
9799
9800   /* now some housekeeping stuff */
9801   if (aop) /* we had to allocate for this iCode */
9802     {
9803       if (pi)
9804         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9805       freeAsmop (NULL, aop, ic, TRUE);
9806     }
9807   else
9808     {
9809       /* we did not allocate which means left
9810          already in a pointer register, then
9811          if size > 0 && this could be used again
9812          we have to point it back to where it
9813          belongs */
9814       if ((AOP_SIZE (right) > 1 &&
9815            !OP_SYMBOL (result)->remat &&
9816            (OP_SYMBOL (result)->liveTo > ic->seq ||
9817             ic->depth)) &&
9818           !pi)
9819         {
9820           int size = AOP_SIZE (right) - 1;
9821           while (size--)
9822             emitcode ("dec", "%s", rname);
9823         }
9824     }
9825
9826   /* done */
9827   if (pi) pi->generated = 1;
9828   freeAsmop (result, NULL, ic, TRUE);
9829   freeAsmop (right, NULL, ic, TRUE);
9830 }
9831
9832 /*-----------------------------------------------------------------*/
9833 /* genPagedPointerSet - emitcode for Paged pointer put             */
9834 /*-----------------------------------------------------------------*/
9835 static void
9836 genPagedPointerSet (operand * right,
9837                     operand * result,
9838                     iCode * ic,
9839                     iCode * pi)
9840 {
9841   asmop *aop = NULL;
9842   regs *preg = NULL;
9843   char *rname, *l;
9844   sym_link *retype, *letype;
9845
9846   D(emitcode (";     genPagedPointerSet",""));
9847
9848   retype = getSpec (operandType (right));
9849   letype = getSpec (operandType (result));
9850
9851   aopOp (result, ic, FALSE);
9852
9853   /* if the value is already in a pointer register
9854      then don't need anything more */
9855   if (!AOP_INPREG (AOP (result)))
9856     {
9857       /* otherwise get a free pointer register */
9858       aop = newAsmop (0);
9859       preg = getFreePtr (ic, &aop, FALSE);
9860       emitcode ("mov", "%s,%s",
9861                 preg->name,
9862                 aopGet (result, 0, FALSE, TRUE));
9863       rname = preg->name;
9864     }
9865   else
9866     rname = aopGet (result, 0, FALSE, FALSE);
9867
9868   aopOp (right, ic, FALSE);
9869
9870   /* if bitfield then unpack the bits */
9871   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9872     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9873   else
9874     {
9875       /* we have can just get the values */
9876       int size = AOP_SIZE (right);
9877       int offset = 0;
9878
9879       while (size--)
9880         {
9881           l = aopGet (right, offset, FALSE, TRUE);
9882
9883           MOVA (l);
9884           emitcode ("movx", "@%s,a", rname);
9885
9886           if (size || pi)
9887             emitcode ("inc", "%s", rname);
9888
9889           offset++;
9890         }
9891     }
9892
9893   /* now some housekeeping stuff */
9894   if (aop) /* we had to allocate for this iCode */
9895     {
9896       if (pi)
9897         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9898       freeAsmop (NULL, aop, ic, TRUE);
9899     }
9900   else
9901     {
9902       /* we did not allocate which means left
9903          already in a pointer register, then
9904          if size > 0 && this could be used again
9905          we have to point it back to where it
9906          belongs */
9907       if (AOP_SIZE (right) > 1 &&
9908           !OP_SYMBOL (result)->remat &&
9909           (OP_SYMBOL (result)->liveTo > ic->seq ||
9910            ic->depth))
9911         {
9912           int size = AOP_SIZE (right) - 1;
9913           while (size--)
9914             emitcode ("dec", "%s", rname);
9915         }
9916     }
9917
9918   /* done */
9919   if (pi) pi->generated = 1;
9920   freeAsmop (result, NULL, ic, TRUE);
9921   freeAsmop (right, NULL, ic, TRUE);
9922
9923
9924 }
9925
9926 /*-----------------------------------------------------------------*/
9927 /* genFarPointerSet - set value from far space                     */
9928 /*-----------------------------------------------------------------*/
9929 static void
9930 genFarPointerSet (operand * right,
9931                   operand * result, iCode * ic, iCode * pi)
9932 {
9933   int size, offset;
9934   sym_link *retype = getSpec (operandType (right));
9935   sym_link *letype = getSpec (operandType (result));
9936
9937   D(emitcode (";     genFarPointerSet",""));
9938
9939   aopOp (result, ic, FALSE);
9940   loadDptrFromOperand (result, FALSE);
9941
9942   /* so dptr know contains the address */
9943   aopOp (right, ic, FALSE);
9944
9945   /* if bit then unpack */
9946   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9947     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9948   else
9949     {
9950       size = AOP_SIZE (right);
9951       offset = 0;
9952
9953       while (size--)
9954         {
9955           char *l = aopGet (right, offset++, FALSE, FALSE);
9956           MOVA (l);
9957           emitcode ("movx", "@dptr,a");
9958           if (size || pi)
9959             emitcode ("inc", "dptr");
9960         }
9961     }
9962   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9963     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
9964     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
9965     pi->generated=1;
9966   }
9967   freeAsmop (result, NULL, ic, TRUE);
9968   freeAsmop (right, NULL, ic, TRUE);
9969 }
9970
9971 /*-----------------------------------------------------------------*/
9972 /* genGenPointerSet - set value from generic pointer space         */
9973 /*-----------------------------------------------------------------*/
9974 static void
9975 genGenPointerSet (operand * right,
9976                   operand * result, iCode * ic, iCode * pi)
9977 {
9978   int size, offset;
9979   sym_link *retype = getSpec (operandType (right));
9980   sym_link *letype = getSpec (operandType (result));
9981
9982   D(emitcode (";     genGenPointerSet",""));
9983
9984   aopOp (result, ic, FALSE);
9985   loadDptrFromOperand (result, TRUE);
9986
9987   /* so dptr know contains the address */
9988   aopOp (right, ic, FALSE);
9989
9990   /* if bit then unpack */
9991   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9992     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9993   else
9994     {
9995       size = AOP_SIZE (right);
9996       offset = 0;
9997
9998       while (size--)
9999         {
10000           char *l = aopGet (right, offset++, FALSE, FALSE);
10001           MOVA (l);
10002           emitcode ("lcall", "__gptrput");
10003           if (size || pi)
10004             emitcode ("inc", "dptr");
10005         }
10006     }
10007
10008   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10009     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10010     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10011     pi->generated=1;
10012   }
10013   freeAsmop (result, NULL, ic, TRUE);
10014   freeAsmop (right, NULL, ic, TRUE);
10015 }
10016
10017 /*-----------------------------------------------------------------*/
10018 /* genPointerSet - stores the value into a pointer location        */
10019 /*-----------------------------------------------------------------*/
10020 static void
10021 genPointerSet (iCode * ic, iCode *pi)
10022 {
10023   operand *right, *result;
10024   sym_link *type, *etype;
10025   int p_type;
10026
10027   D(emitcode (";     genPointerSet",""));
10028
10029   right = IC_RIGHT (ic);
10030   result = IC_RESULT (ic);
10031
10032   /* depending on the type of pointer we need to
10033      move it to the correct pointer register */
10034   type = operandType (result);
10035   etype = getSpec (type);
10036   /* if left is of type of pointer then it is simple */
10037   if (IS_PTR (type) && !IS_FUNC (type->next))
10038     {
10039       p_type = DCL_TYPE (type);
10040     }
10041   else
10042     {
10043       /* we have to go by the storage class */
10044       p_type = PTR_TYPE (SPEC_OCLS (etype));
10045     }
10046
10047   /* special case when cast remat */
10048   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10049       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10050           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10051           type = operandType (result);
10052           p_type = DCL_TYPE (type);
10053   }
10054   /* now that we have the pointer type we assign
10055      the pointer values */
10056   switch (p_type)
10057     {
10058
10059     case POINTER:
10060     case IPOINTER:
10061       genNearPointerSet (right, result, ic, pi);
10062       break;
10063
10064     case PPOINTER:
10065       genPagedPointerSet (right, result, ic, pi);
10066       break;
10067
10068     case FPOINTER:
10069       genFarPointerSet (right, result, ic, pi);
10070       break;
10071
10072     case GPOINTER:
10073       genGenPointerSet (right, result, ic, pi);
10074       break;
10075
10076     default:
10077       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10078               "genPointerSet: illegal pointer type");
10079     }
10080
10081 }
10082
10083 /*-----------------------------------------------------------------*/
10084 /* genIfx - generate code for Ifx statement                        */
10085 /*-----------------------------------------------------------------*/
10086 static void
10087 genIfx (iCode * ic, iCode * popIc)
10088 {
10089   operand *cond = IC_COND (ic);
10090   int isbit = 0;
10091   char *dup = NULL;
10092
10093   D(emitcode (";     genIfx",""));
10094
10095   aopOp (cond, ic, FALSE);
10096
10097   /* get the value into acc */
10098   if (AOP_TYPE (cond) != AOP_CRY)
10099     toBoolean (cond);
10100   else
10101     {
10102       isbit = 1;
10103       if (AOP(cond)->aopu.aop_dir)
10104         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10105     }
10106   /* the result is now in the accumulator or a directly addressable bit */
10107   freeAsmop (cond, NULL, ic, TRUE);
10108
10109   /* if there was something to be popped then do it */
10110   if (popIc)
10111     genIpop (popIc);
10112
10113   /* if the condition is a bit variable */
10114   if (isbit && dup)
10115     genIfxJump(ic, dup, NULL, NULL, NULL);
10116   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10117     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10118   else if (isbit && !IS_ITEMP (cond))
10119     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10120   else
10121     genIfxJump (ic, "a", NULL, NULL, NULL);
10122
10123   ic->generated = 1;
10124 }
10125
10126 /*-----------------------------------------------------------------*/
10127 /* genAddrOf - generates code for address of                       */
10128 /*-----------------------------------------------------------------*/
10129 static void
10130 genAddrOf (iCode * ic)
10131 {
10132   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10133   int size, offset;
10134
10135   D(emitcode (";     genAddrOf",""));
10136
10137   aopOp (IC_RESULT (ic), ic, FALSE);
10138
10139   /* if the operand is on the stack then we
10140      need to get the stack offset of this
10141      variable */
10142   if (sym->onStack)
10143     {
10144       /* if it has an offset then we need to compute
10145          it */
10146       if (sym->stack)
10147         {
10148           emitcode ("mov", "a,%s", SYM_BP (sym));
10149           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10150                                          ((char) (sym->stack - _G.nRegsSaved)) :
10151                                          ((char) sym->stack)) & 0xff);
10152           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10153         }
10154       else
10155         {
10156           /* we can just move _bp */
10157           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10158         }
10159       /* fill the result with zero */
10160       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10161
10162       offset = 1;
10163       while (size--)
10164         {
10165           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10166         }
10167
10168       goto release;
10169     }
10170
10171   /* object not on stack then we need the name */
10172   size = AOP_SIZE (IC_RESULT (ic));
10173   offset = 0;
10174
10175   while (size--)
10176     {
10177       char s[SDCC_NAME_MAX];
10178       if (offset)
10179         sprintf (s, "#(%s >> %d)",
10180                  sym->rname,
10181                  offset * 8);
10182       else
10183         sprintf (s, "#%s", sym->rname);
10184       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10185     }
10186
10187 release:
10188   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10189
10190 }
10191
10192 /*-----------------------------------------------------------------*/
10193 /* genFarFarAssign - assignment when both are in far space         */
10194 /*-----------------------------------------------------------------*/
10195 static void
10196 genFarFarAssign (operand * result, operand * right, iCode * ic)
10197 {
10198   int size = AOP_SIZE (right);
10199   int offset = 0;
10200   char *l;
10201
10202   D(emitcode (";     genFarFarAssign",""));
10203
10204   /* first push the right side on to the stack */
10205   while (size--)
10206     {
10207       l = aopGet (right, offset++, FALSE, FALSE);
10208       MOVA (l);
10209       emitcode ("push", "acc");
10210     }
10211
10212   freeAsmop (right, NULL, ic, FALSE);
10213   /* now assign DPTR to result */
10214   aopOp (result, ic, FALSE);
10215   size = AOP_SIZE (result);
10216   while (size--)
10217     {
10218       emitcode ("pop", "acc");
10219       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10220     }
10221   freeAsmop (result, NULL, ic, FALSE);
10222
10223 }
10224
10225 /*-----------------------------------------------------------------*/
10226 /* genAssign - generate code for assignment                        */
10227 /*-----------------------------------------------------------------*/
10228 static void
10229 genAssign (iCode * ic)
10230 {
10231   operand *result, *right;
10232   int size, offset;
10233   unsigned long lit = 0L;
10234
10235   D(emitcode(";     genAssign",""));
10236
10237   result = IC_RESULT (ic);
10238   right = IC_RIGHT (ic);
10239
10240   /* if they are the same */
10241   if (operandsEqu (result, right) &&
10242       !isOperandVolatile (result, FALSE) &&
10243       !isOperandVolatile (right, FALSE))
10244     return;
10245
10246   aopOp (right, ic, FALSE);
10247
10248   /* special case both in far space */
10249   if (AOP_TYPE (right) == AOP_DPTR &&
10250       IS_TRUE_SYMOP (result) &&
10251       isOperandInFarSpace (result))
10252     {
10253
10254       genFarFarAssign (result, right, ic);
10255       return;
10256     }
10257
10258   aopOp (result, ic, TRUE);
10259
10260   /* if they are the same registers */
10261   if (sameRegs (AOP (right), AOP (result)) &&
10262       !isOperandVolatile (result, FALSE) &&
10263       !isOperandVolatile (right, FALSE))
10264     goto release;
10265
10266   /* if the result is a bit */
10267   if (AOP_TYPE (result) == AOP_CRY)
10268     {
10269
10270       /* if the right size is a literal then
10271          we know what the value is */
10272       if (AOP_TYPE (right) == AOP_LIT)
10273         {
10274           if (((int) operandLitValue (right)))
10275             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10276           else
10277             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10278           goto release;
10279         }
10280
10281       /* the right is also a bit variable */
10282       if (AOP_TYPE (right) == AOP_CRY)
10283         {
10284           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10285           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10286           goto release;
10287         }
10288
10289       /* we need to or */
10290       toBoolean (right);
10291       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10292       goto release;
10293     }
10294
10295   /* bit variables done */
10296   /* general case */
10297   size = AOP_SIZE (result);
10298   offset = 0;
10299   if (AOP_TYPE (right) == AOP_LIT)
10300     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10301   if ((size > 1) &&
10302       (AOP_TYPE (result) != AOP_REG) &&
10303       (AOP_TYPE (right) == AOP_LIT) &&
10304       !IS_FLOAT (operandType (right)) &&
10305       (lit < 256L))
10306     {
10307       while ((size) && (lit))
10308         {
10309           aopPut (result,
10310                   aopGet (right, offset, FALSE, FALSE),
10311                   offset,
10312                   isOperandVolatile (result, FALSE));
10313           lit >>= 8;
10314           offset++;
10315           size--;
10316         }
10317       emitcode ("clr", "a");
10318       while (size--)
10319         {
10320           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10321           offset++;
10322         }
10323     }
10324   else
10325     {
10326       while (size--)
10327         {
10328           aopPut (result,
10329                   aopGet (right, offset, FALSE, FALSE),
10330                   offset,
10331                   isOperandVolatile (result, FALSE));
10332           offset++;
10333         }
10334     }
10335
10336 release:
10337   freeAsmop (right, NULL, ic, TRUE);
10338   freeAsmop (result, NULL, ic, TRUE);
10339 }
10340
10341 /*-----------------------------------------------------------------*/
10342 /* genJumpTab - generates code for jump table                      */
10343 /*-----------------------------------------------------------------*/
10344 static void
10345 genJumpTab (iCode * ic)
10346 {
10347   symbol *jtab,*jtablo,*jtabhi;
10348   char *l;
10349   unsigned int count;
10350
10351   D(emitcode (";     genJumpTab",""));
10352
10353   count = elementsInSet( IC_JTLABELS (ic) );
10354
10355   if( count <= 16 )
10356     {
10357       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10358          if the switch argument is in a register.
10359          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10360       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10361          How will multiply by three be updated ???*/
10362       aopOp (IC_JTCOND (ic), ic, FALSE);
10363       /* get the condition into accumulator */
10364       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10365       MOVA (l);
10366       /* multiply by three */
10367       emitcode ("add", "a,acc");
10368       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10369       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10370
10371       jtab = newiTempLabel (NULL);
10372       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10373       emitcode ("jmp", "@a+dptr");
10374       emitcode ("", "%05d$:", jtab->key + 100);
10375       /* now generate the jump labels */
10376       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10377            jtab = setNextItem (IC_JTLABELS (ic)))
10378         emitcode ("ljmp", "%05d$", jtab->key + 100);
10379     }
10380   else
10381     {
10382       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10383          if the switch argument is in a register.
10384          For n>6 this algorithm may be more compact */
10385       jtablo = newiTempLabel (NULL);
10386       jtabhi = newiTempLabel (NULL);
10387
10388       /* get the condition into accumulator.
10389          Using b as temporary storage, if register push/pop is needed */
10390       aopOp (IC_JTCOND (ic), ic, FALSE);
10391       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10392       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10393           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10394         {
10395           // (MB) what if B is in use???
10396           wassertl(!BINUSE, "B was in use");
10397           emitcode ("mov", "b,%s", l);
10398           l = "b";
10399         }
10400       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10401       MOVA (l);
10402       if( count <= 112 )
10403         {
10404           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10405           emitcode ("movc", "a,@a+pc");
10406           emitcode ("push", "acc");
10407
10408           MOVA (l);
10409           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10410           emitcode ("movc", "a,@a+pc");
10411           emitcode ("push", "acc");
10412         }
10413       else
10414         {
10415           /* this scales up to n<=255, but needs two more bytes
10416              and changes dptr */
10417           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10418           emitcode ("movc", "a,@a+dptr");
10419           emitcode ("push", "acc");
10420
10421           MOVA (l);
10422           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10423           emitcode ("movc", "a,@a+dptr");
10424           emitcode ("push", "acc");
10425         }
10426
10427       emitcode ("ret", "");
10428
10429       /* now generate jump table, LSB */
10430       emitcode ("", "%05d$:", jtablo->key + 100);
10431       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10432            jtab = setNextItem (IC_JTLABELS (ic)))
10433         emitcode (".db", "%05d$", jtab->key + 100);
10434
10435       /* now generate jump table, MSB */
10436       emitcode ("", "%05d$:", jtabhi->key + 100);
10437       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10438            jtab = setNextItem (IC_JTLABELS (ic)))
10439          emitcode (".db", "%05d$>>8", jtab->key + 100);
10440     }
10441 }
10442
10443 /*-----------------------------------------------------------------*/
10444 /* genCast - gen code for casting                                  */
10445 /*-----------------------------------------------------------------*/
10446 static void
10447 genCast (iCode * ic)
10448 {
10449   operand *result = IC_RESULT (ic);
10450   sym_link *ctype = operandType (IC_LEFT (ic));
10451   sym_link *rtype = operandType (IC_RIGHT (ic));
10452   operand *right = IC_RIGHT (ic);
10453   int size, offset;
10454
10455   D(emitcode(";     genCast",""));
10456
10457   /* if they are equivalent then do nothing */
10458   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10459     return;
10460
10461   aopOp (right, ic, FALSE);
10462   aopOp (result, ic, FALSE);
10463
10464   /* if the result is a bit (and not a bitfield) */
10465   // if (AOP_TYPE (result) == AOP_CRY)
10466   if (IS_BITVAR (OP_SYMBOL (result)->type)
10467       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10468     {
10469       /* if the right size is a literal then
10470          we know what the value is */
10471       if (AOP_TYPE (right) == AOP_LIT)
10472         {
10473           if (((int) operandLitValue (right)))
10474             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10475           else
10476             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10477
10478           goto release;
10479         }
10480
10481       /* the right is also a bit variable */
10482       if (AOP_TYPE (right) == AOP_CRY)
10483         {
10484           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10485           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10486           goto release;
10487         }
10488
10489       /* we need to or */
10490       toBoolean (right);
10491       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10492       goto release;
10493     }
10494
10495
10496   /* if they are the same size : or less */
10497   if (AOP_SIZE (result) <= AOP_SIZE (right))
10498     {
10499
10500       /* if they are in the same place */
10501       if (sameRegs (AOP (right), AOP (result)))
10502         goto release;
10503
10504       /* if they in different places then copy */
10505       size = AOP_SIZE (result);
10506       offset = 0;
10507       while (size--)
10508         {
10509           aopPut (result,
10510                   aopGet (right, offset, FALSE, FALSE),
10511                   offset,
10512                   isOperandVolatile (result, FALSE));
10513           offset++;
10514         }
10515       goto release;
10516     }
10517
10518
10519   /* if the result is of type pointer */
10520   if (IS_PTR (ctype))
10521     {
10522
10523       int p_type;
10524       sym_link *type = operandType (right);
10525       sym_link *etype = getSpec (type);
10526
10527       /* pointer to generic pointer */
10528       if (IS_GENPTR (ctype))
10529         {
10530           if (IS_PTR (type))
10531             p_type = DCL_TYPE (type);
10532           else
10533             {
10534               if (SPEC_SCLS(etype)==S_REGISTER) {
10535                 // let's assume it is a generic pointer
10536                 p_type=GPOINTER;
10537               } else {
10538                 /* we have to go by the storage class */
10539                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10540               }
10541             }
10542
10543           /* the first two bytes are known */
10544           size = GPTRSIZE - 1;
10545           offset = 0;
10546           while (size--)
10547             {
10548               aopPut (result,
10549                       aopGet (right, offset, FALSE, FALSE),
10550                       offset,
10551                       isOperandVolatile (result, FALSE));
10552               offset++;
10553             }
10554           /* the last byte depending on type */
10555             {
10556                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10557                 char gpValStr[10];
10558
10559                 if (gpVal == -1)
10560                 {
10561                     // pointerTypeToGPByte will have bitched.
10562                     exit(1);
10563                 }
10564
10565                 sprintf(gpValStr, "#0x%x", gpVal);
10566                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10567             }
10568           goto release;
10569         }
10570
10571       /* just copy the pointers */
10572       size = AOP_SIZE (result);
10573       offset = 0;
10574       while (size--)
10575         {
10576           aopPut (result,
10577                   aopGet (right, offset, FALSE, FALSE),
10578                   offset,
10579                   isOperandVolatile (result, FALSE));
10580           offset++;
10581         }
10582       goto release;
10583     }
10584
10585   /* so we now know that the size of destination is greater
10586      than the size of the source */
10587   /* we move to result for the size of source */
10588   size = AOP_SIZE (right);
10589   offset = 0;
10590   while (size--)
10591     {
10592       aopPut (result,
10593               aopGet (right, offset, FALSE, FALSE),
10594               offset,
10595               isOperandVolatile (result, FALSE));
10596       offset++;
10597     }
10598
10599   /* now depending on the sign of the source && destination */
10600   size = AOP_SIZE (result) - AOP_SIZE (right);
10601   /* if unsigned or not an integral type */
10602   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10603     {
10604       while (size--)
10605         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10606     }
10607   else
10608     {
10609       /* we need to extend the sign :{ */
10610       char *l = aopGet (right, AOP_SIZE (right) - 1,
10611                         FALSE, FALSE);
10612       MOVA (l);
10613       emitcode ("rlc", "a");
10614       emitcode ("subb", "a,acc");
10615       while (size--)
10616         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10617     }
10618
10619   /* we are done hurray !!!! */
10620
10621 release:
10622   freeAsmop (right, NULL, ic, TRUE);
10623   freeAsmop (result, NULL, ic, TRUE);
10624
10625 }
10626
10627 /*-----------------------------------------------------------------*/
10628 /* genDjnz - generate decrement & jump if not zero instrucion      */
10629 /*-----------------------------------------------------------------*/
10630 static int
10631 genDjnz (iCode * ic, iCode * ifx)
10632 {
10633   symbol *lbl, *lbl1;
10634   if (!ifx)
10635     return 0;
10636
10637   D(emitcode (";     genDjnz",""));
10638
10639   /* if the if condition has a false label
10640      then we cannot save */
10641   if (IC_FALSE (ifx))
10642     return 0;
10643
10644   /* if the minus is not of the form
10645      a = a - 1 */
10646   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10647       !IS_OP_LITERAL (IC_RIGHT (ic)))
10648     return 0;
10649
10650   if (operandLitValue (IC_RIGHT (ic)) != 1)
10651     return 0;
10652
10653   /* if the size of this greater than one then no
10654      saving */
10655   if (getSize (operandType (IC_RESULT (ic))) > 1)
10656     return 0;
10657
10658   /* otherwise we can save BIG */
10659   lbl = newiTempLabel (NULL);
10660   lbl1 = newiTempLabel (NULL);
10661
10662   aopOp (IC_RESULT (ic), ic, FALSE);
10663
10664   if (AOP_NEEDSACC(IC_RESULT(ic)))
10665   {
10666       /* If the result is accessed indirectly via
10667        * the accumulator, we must explicitly write
10668        * it back after the decrement.
10669        */
10670       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10671
10672       if (strcmp(rByte, "a"))
10673       {
10674            /* Something is hopelessly wrong */
10675            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10676                    __FILE__, __LINE__);
10677            /* We can just give up; the generated code will be inefficient,
10678             * but what the hey.
10679             */
10680            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10681            return 0;
10682       }
10683       emitcode ("dec", "%s", rByte);
10684       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10685       emitcode ("jnz", "%05d$", lbl->key + 100);
10686   }
10687   else if (IS_AOP_PREG (IC_RESULT (ic)))
10688     {
10689       emitcode ("dec", "%s",
10690                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10691       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10692       emitcode ("jnz", "%05d$", lbl->key + 100);
10693     }
10694   else
10695     {
10696       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10697                 lbl->key + 100);
10698     }
10699   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10700   emitcode ("", "%05d$:", lbl->key + 100);
10701   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10702   emitcode ("", "%05d$:", lbl1->key + 100);
10703
10704   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10705   ifx->generated = 1;
10706   return 1;
10707 }
10708
10709 /*-----------------------------------------------------------------*/
10710 /* genReceive - generate code for a receive iCode                  */
10711 /*-----------------------------------------------------------------*/
10712 static void
10713 genReceive (iCode * ic)
10714 {
10715   int size = getSize (operandType (IC_RESULT (ic)));
10716   int offset = 0;
10717
10718   D(emitcode (";     genReceive",""));
10719
10720   if (ic->argreg == 1)
10721     { /* first parameter */
10722       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10723           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10724            IS_TRUE_SYMOP (IC_RESULT (ic))))
10725         {
10726           regs *tempRegs[4];
10727           int receivingA = 0;
10728           int roffset = 0;
10729
10730           for (offset = 0; offset<size; offset++)
10731             if (!strcmp (fReturn[offset], "a"))
10732               receivingA = 1;
10733
10734           if (!receivingA)
10735             {
10736               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10737                 {
10738                   for (offset = size-1; offset>0; offset--)
10739                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10740                   emitcode("mov","a,%s", fReturn[0]);
10741                   _G.accInUse++;
10742                   aopOp (IC_RESULT (ic), ic, FALSE);
10743                   _G.accInUse--;
10744                   aopPut (IC_RESULT (ic), "a", offset,
10745                           isOperandVolatile (IC_RESULT (ic), FALSE));
10746                   for (offset = 1; offset<size; offset++)
10747                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10748                             isOperandVolatile (IC_RESULT (ic), FALSE));
10749                   goto release;
10750                 }
10751             }
10752           else
10753             {
10754               if (getTempRegs(tempRegs, size, ic))
10755                 {
10756                   for (offset = 0; offset<size; offset++)
10757                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10758                   aopOp (IC_RESULT (ic), ic, FALSE);
10759                   for (offset = 0; offset<size; offset++)
10760                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10761                             isOperandVolatile (IC_RESULT (ic), FALSE));
10762                   goto release;
10763                 }
10764             }
10765
10766           offset = fReturnSizeMCS51 - size;
10767           while (size--)
10768             {
10769               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10770                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10771               offset++;
10772             }
10773           aopOp (IC_RESULT (ic), ic, FALSE);
10774           size = AOP_SIZE (IC_RESULT (ic));
10775           offset = 0;
10776           while (size--)
10777             {
10778               emitcode ("pop", "acc");
10779               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10780             }
10781         }
10782       else
10783         {
10784           _G.accInUse++;
10785           aopOp (IC_RESULT (ic), ic, FALSE);
10786           _G.accInUse--;
10787           assignResultValue (IC_RESULT (ic), NULL);
10788         }
10789     }
10790   else if (ic->argreg > 12)
10791     { /* bit parameters */
10792       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
10793         {
10794           aopOp (IC_RESULT (ic), ic, FALSE);
10795           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
10796           outBitC(IC_RESULT (ic));
10797         }
10798     }
10799   else
10800     { /* other parameters */
10801       int rb1off ;
10802       aopOp (IC_RESULT (ic), ic, FALSE);
10803       rb1off = ic->argreg;
10804       while (size--)
10805         {
10806           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10807         }
10808     }
10809
10810 release:
10811   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10812 }
10813
10814 /*-----------------------------------------------------------------*/
10815 /* genDummyRead - generate code for dummy read of volatiles        */
10816 /*-----------------------------------------------------------------*/
10817 static void
10818 genDummyRead (iCode * ic)
10819 {
10820   operand *op;
10821   int size, offset;
10822
10823   D(emitcode(";     genDummyRead",""));
10824
10825   op = IC_RIGHT (ic);
10826   if (op && IS_SYMOP (op))
10827     {
10828       aopOp (op, ic, FALSE);
10829
10830       /* if the result is a bit */
10831       if (AOP_TYPE (op) == AOP_CRY)
10832         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10833       else
10834         {
10835           /* bit variables done */
10836           /* general case */
10837           size = AOP_SIZE (op);
10838           offset = 0;
10839           while (size--)
10840           {
10841             MOVA (aopGet (op, offset, FALSE, FALSE));
10842             offset++;
10843           }
10844         }
10845
10846       freeAsmop (op, NULL, ic, TRUE);
10847     }
10848
10849   op = IC_LEFT (ic);
10850   if (op && IS_SYMOP (op))
10851     {
10852       aopOp (op, ic, FALSE);
10853
10854       /* if the result is a bit */
10855       if (AOP_TYPE (op) == AOP_CRY)
10856         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10857       else
10858         {
10859           /* bit variables done */
10860           /* general case */
10861           size = AOP_SIZE (op);
10862           offset = 0;
10863           while (size--)
10864           {
10865             MOVA (aopGet (op, offset, FALSE, FALSE));
10866             offset++;
10867           }
10868         }
10869
10870       freeAsmop (op, NULL, ic, TRUE);
10871     }
10872 }
10873
10874 /*-----------------------------------------------------------------*/
10875 /* genCritical - generate code for start of a critical sequence    */
10876 /*-----------------------------------------------------------------*/
10877 static void
10878 genCritical (iCode *ic)
10879 {
10880   symbol *tlbl = newiTempLabel (NULL);
10881
10882   D(emitcode(";     genCritical",""));
10883
10884   if (IC_RESULT (ic))
10885     {
10886       aopOp (IC_RESULT (ic), ic, TRUE);
10887       aopPut (IC_RESULT (ic), one, 0, 0);
10888       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10889       aopPut (IC_RESULT (ic), zero, 0, 0);
10890       emitcode ("", "%05d$:", (tlbl->key + 100));
10891       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10892     }
10893   else
10894     {
10895       emitcode ("setb", "c");
10896       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10897       emitcode ("clr", "c");
10898       emitcode ("", "%05d$:", (tlbl->key + 100));
10899       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10900     }
10901 }
10902
10903 /*-----------------------------------------------------------------*/
10904 /* genEndCritical - generate code for end of a critical sequence   */
10905 /*-----------------------------------------------------------------*/
10906 static void
10907 genEndCritical (iCode *ic)
10908 {
10909   D(emitcode(";     genEndCritical",""));
10910
10911   if (IC_RIGHT (ic))
10912     {
10913       aopOp (IC_RIGHT (ic), ic, FALSE);
10914       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10915         {
10916           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10917           emitcode ("mov", "ea,c");
10918         }
10919       else
10920         {
10921           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10922             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
10923           emitcode ("rrc", "a");
10924           emitcode ("mov", "ea,c");
10925         }
10926       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10927     }
10928   else
10929     {
10930       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10931       emitcode ("mov", "ea,c");
10932     }
10933 }
10934
10935 /*-----------------------------------------------------------------*/
10936 /* gen51Code - generate code for 8051 based controllers            */
10937 /*-----------------------------------------------------------------*/
10938 void
10939 gen51Code (iCode * lic)
10940 {
10941   iCode *ic;
10942   int cln = 0;
10943   /* int cseq = 0; */
10944
10945   _G.currentFunc = NULL;
10946   lineHead = lineCurr = NULL;
10947
10948   /* print the allocation information */
10949   if (allocInfo && currFunc)
10950     printAllocInfo (currFunc, codeOutFile);
10951   /* if debug information required */
10952   if (options.debug && currFunc)
10953     {
10954       debugFile->writeFunction (currFunc, lic);
10955     }
10956   /* stack pointer name */
10957   if (options.useXstack)
10958     spname = "_spx";
10959   else
10960     spname = "sp";
10961
10962
10963   for (ic = lic; ic; ic = ic->next)
10964     {
10965       _G.current_iCode = ic;
10966
10967       if (ic->lineno && cln != ic->lineno)
10968         {
10969           if (options.debug)
10970             {
10971               debugFile->writeCLine (ic);
10972             }
10973           if (!options.noCcodeInAsm) {
10974             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10975                       printCLine(ic->filename, ic->lineno));
10976           }
10977           cln = ic->lineno;
10978         }
10979       #if 0
10980       if (ic->seqPoint && ic->seqPoint != cseq)
10981         {
10982           emitcode ("", "; sequence point %d", ic->seqPoint);
10983           cseq = ic->seqPoint;
10984         }
10985       #endif
10986       if (options.iCodeInAsm) {
10987         char regsInUse[80];
10988         int i;
10989
10990         for (i=0; i<8; i++) {
10991           sprintf (&regsInUse[i],
10992                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10993         }
10994         regsInUse[i]=0;
10995         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10996       }
10997       /* if the result is marked as
10998          spilt and rematerializable or code for
10999          this has already been generated then
11000          do nothing */
11001       if (resultRemat (ic) || ic->generated)
11002         continue;
11003
11004       /* depending on the operation */
11005       switch (ic->op)
11006         {
11007         case '!':
11008           genNot (ic);
11009           break;
11010
11011         case '~':
11012           genCpl (ic);
11013           break;
11014
11015         case UNARYMINUS:
11016           genUminus (ic);
11017           break;
11018
11019         case IPUSH:
11020           genIpush (ic);
11021           break;
11022
11023         case IPOP:
11024           /* IPOP happens only when trying to restore a
11025              spilt live range, if there is an ifx statement
11026              following this pop then the if statement might
11027              be using some of the registers being popped which
11028              would destory the contents of the register so
11029              we need to check for this condition and handle it */
11030           if (ic->next &&
11031               ic->next->op == IFX &&
11032               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11033             genIfx (ic->next, ic);
11034           else
11035             genIpop (ic);
11036           break;
11037
11038         case CALL:
11039           genCall (ic);
11040           break;
11041
11042         case PCALL:
11043           genPcall (ic);
11044           break;
11045
11046         case FUNCTION:
11047           genFunction (ic);
11048           break;
11049
11050         case ENDFUNCTION:
11051           genEndFunction (ic);
11052           break;
11053
11054         case RETURN:
11055           genRet (ic);
11056           break;
11057
11058         case LABEL:
11059           genLabel (ic);
11060           break;
11061
11062         case GOTO:
11063           genGoto (ic);
11064           break;
11065
11066         case '+':
11067           genPlus (ic);
11068           break;
11069
11070         case '-':
11071           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11072             genMinus (ic);
11073           break;
11074
11075         case '*':
11076           genMult (ic);
11077           break;
11078
11079         case '/':
11080           genDiv (ic);
11081           break;
11082
11083         case '%':
11084           genMod (ic);
11085           break;
11086
11087         case '>':
11088           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11089           break;
11090
11091         case '<':
11092           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11093           break;
11094
11095         case LE_OP:
11096         case GE_OP:
11097         case NE_OP:
11098
11099           /* note these two are xlated by algebraic equivalence
11100              during parsing SDCC.y */
11101           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11102                   "got '>=' or '<=' shouldn't have come here");
11103           break;
11104
11105         case EQ_OP:
11106           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11107           break;
11108
11109         case AND_OP:
11110           genAndOp (ic);
11111           break;
11112
11113         case OR_OP:
11114           genOrOp (ic);
11115           break;
11116
11117         case '^':
11118           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11119           break;
11120
11121         case '|':
11122           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11123           break;
11124
11125         case BITWISEAND:
11126           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11127           break;
11128
11129         case INLINEASM:
11130           genInline (ic);
11131           break;
11132
11133         case RRC:
11134           genRRC (ic);
11135           break;
11136
11137         case RLC:
11138           genRLC (ic);
11139           break;
11140
11141         case GETHBIT:
11142           genGetHbit (ic);
11143           break;
11144
11145         case LEFT_OP:
11146           genLeftShift (ic);
11147           break;
11148
11149         case RIGHT_OP:
11150           genRightShift (ic);
11151           break;
11152
11153         case GET_VALUE_AT_ADDRESS:
11154           genPointerGet (ic,
11155                          hasInc (IC_LEFT (ic), ic,
11156                                  getSize (operandType (IC_RESULT (ic)))),
11157                          ifxForOp (IC_RESULT (ic), ic) );
11158           break;
11159
11160         case '=':
11161           if (POINTER_SET (ic))
11162             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11163           else
11164             genAssign (ic);
11165           break;
11166
11167         case IFX:
11168           genIfx (ic, NULL);
11169           break;
11170
11171         case ADDRESS_OF:
11172           genAddrOf (ic);
11173           break;
11174
11175         case JUMPTABLE:
11176           genJumpTab (ic);
11177           break;
11178
11179         case CAST:
11180           genCast (ic);
11181           break;
11182
11183         case RECEIVE:
11184           genReceive (ic);
11185           break;
11186
11187         case SEND:
11188           addSet (&_G.sendSet, ic);
11189           break;
11190
11191         case DUMMY_READ_VOLATILE:
11192           genDummyRead (ic);
11193           break;
11194
11195         case CRITICAL:
11196           genCritical (ic);
11197           break;
11198
11199         case ENDCRITICAL:
11200           genEndCritical (ic);
11201           break;
11202
11203         case SWAP:
11204           genSwap (ic);
11205           break;
11206
11207         default:
11208           ic = ic;
11209         }
11210     }
11211
11212   _G.current_iCode = NULL;
11213
11214   /* now we are ready to call the
11215      peep hole optimizer */
11216   if (!options.nopeep)
11217     peepHole (&lineHead);
11218
11219   /* now do the actual printing */
11220   printLine (lineHead, codeOutFile);
11221   return;
11222 }