* doc/sdccman.lyx: inserted footnotes about inline assembler labels,
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.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) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
70
71 #define REG_WITH_INDEX   mcs51_regWithIdx
72
73 #define AOP(op) op->aop
74 #define AOP_TYPE(op) AOP(op)->type
75 #define AOP_SIZE(op) AOP(op)->size
76 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
77                         AOP_TYPE(x) == AOP_R0))
78
79 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
80                          AOP_TYPE(x) == AOP_DPTR || \
81                          AOP(x)->paged))
82
83 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
84                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
85                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
86
87 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
88
89 #define R0INB   _G.bu.bs.r0InB
90 #define R1INB   _G.bu.bs.r1InB
91 #define OPINB   _G.bu.bs.OpInB
92 #define BINUSE  _G.bu.BInUse
93
94 static struct
95   {
96     short r0Pushed;
97     short r1Pushed;
98     union
99       {
100         struct
101           {
102             short r0InB : 2;//2 so we can see it overflow
103             short r1InB : 2;//2 so we can see it overflow
104             short OpInB : 2;//2 so we can see it overflow
105           } bs;
106         short BInUse;
107       } bu;
108     short accInUse;
109     short inLine;
110     short debugLine;
111     short nRegsSaved;
112     set *sendSet;
113     iCode *current_iCode;
114     symbol *currentFunc;
115   }
116 _G;
117
118 static char *rb1regs[] = {
119     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
120     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
121 };
122
123 extern struct dbuf_s *codeOutBuf;
124
125 #define RESULTONSTACK(x) \
126                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
127                          IC_RESULT(x)->aop->type == AOP_STK )
128
129 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
130 #define MOVB(x)  movb(x)
131
132 #define CLRC     emitcode("clr","c")
133 #define SETC     emitcode("setb","c")
134
135 static lineNode *lineHead = NULL;
136 static lineNode *lineCurr = NULL;
137
138 static unsigned char SLMask[] =
139 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
140  0xE0, 0xC0, 0x80, 0x00};
141 static unsigned char SRMask[] =
142 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
143  0x07, 0x03, 0x01, 0x00};
144
145 #define LSB     0
146 #define MSB16   1
147 #define MSB24   2
148 #define MSB32   3
149
150 /*-----------------------------------------------------------------*/
151 /* emitcode - writes the code into a file : for now it is simple    */
152 /*-----------------------------------------------------------------*/
153 void
154 emitcode (const char *inst, const char *fmt,...)
155 {
156   va_list ap;
157   struct dbuf_s dbuf;
158   const char *lbp, *lb;
159
160   dbuf_init (&dbuf, INITIAL_INLINEASM);
161
162   va_start (ap, fmt);
163
164   if (inst && *inst)
165     {
166       dbuf_append_str (&dbuf, inst);
167
168       if (fmt && *fmt)
169         {
170           dbuf_append_char (&dbuf, '\t');
171           dbuf_tvprintf (&dbuf, fmt, ap);
172         }
173     }
174   else
175     {
176       dbuf_tvprintf (&dbuf, fmt, ap);
177     }
178
179   lbp = lb = dbuf_c_str(&dbuf);
180
181   while (isspace ((unsigned char)*lbp))
182     {
183       lbp++;
184     }
185
186   if (lbp)
187     {
188       rtrackUpdate (lbp);
189
190       lineCurr = (lineCurr ?
191                   connectLine (lineCurr, newLineNode (lb)) :
192                   (lineHead = newLineNode (lb)));
193
194       lineCurr->isInline = _G.inLine;
195       lineCurr->isDebug = _G.debugLine;
196       lineCurr->ic = _G.current_iCode;
197       lineCurr->isComment = (*lbp==';');
198     }
199
200   va_end (ap);
201
202   dbuf_destroy(&dbuf);
203 }
204
205 static void
206 emitLabel (symbol *tlbl)
207 {
208   emitcode ("", "%05d$:", tlbl->key + 100);
209   lineCurr->isLabel = 1;
210 }
211
212 /*-----------------------------------------------------------------*/
213 /* mcs51_emitDebuggerSymbol - associate the current code location  */
214 /*   with a debugger symbol                                        */
215 /*-----------------------------------------------------------------*/
216 void
217 mcs51_emitDebuggerSymbol (char * debugSym)
218 {
219   _G.debugLine = 1;
220   emitcode ("", "%s ==.", debugSym);
221   _G.debugLine = 0;
222 }
223
224 /*-----------------------------------------------------------------*/
225 /* mova - moves specified value into accumulator                   */
226 /*-----------------------------------------------------------------*/
227 static void
228 mova (const char *x)
229 {
230   /* do some early peephole optimization */
231   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
232     return;
233
234   /* if it is a literal mov try to get it cheaper */
235   if (*x == '#' &&
236       rtrackMoveALit(x))
237     return;
238
239   emitcode("mov", "a,%s", x);
240 }
241
242 /*-----------------------------------------------------------------*/
243 /* movb - moves specified value into register b                    */
244 /*-----------------------------------------------------------------*/
245 static void
246 movb (const char *x)
247 {
248   /* do some early peephole optimization */
249   if (!strncmp(x, "b", 2))
250     return;
251
252   /* if it is a literal mov try to get it cheaper */
253   if (*x == '#')
254     {
255       emitcode("mov","b,%s", rtrackGetLit(x));
256       return;
257     }
258
259   emitcode("mov","b,%s", x);
260 }
261
262 /*-----------------------------------------------------------------*/
263 /* pushB - saves register B if necessary                           */
264 /*-----------------------------------------------------------------*/
265 static bool
266 pushB (void)
267 {
268   bool pushedB = FALSE;
269
270   if (BINUSE)
271     {
272       emitcode ("push", "b");
273 //    printf("B was in use !\n");
274       pushedB = TRUE;
275     }
276   else
277     {
278       OPINB++;
279     }
280   return pushedB;
281 }
282
283 /*-----------------------------------------------------------------*/
284 /* popB - restores value of register B if necessary                */
285 /*-----------------------------------------------------------------*/
286 static void
287 popB (bool pushedB)
288 {
289   if (pushedB)
290     {
291       emitcode ("pop", "b");
292     }
293   else
294     {
295       OPINB--;
296     }
297 }
298
299 /*-----------------------------------------------------------------*/
300 /* pushReg - saves register                                        */
301 /*-----------------------------------------------------------------*/
302 static bool
303 pushReg (int index, bool bits_pushed)
304 {
305   regs * reg = REG_WITH_INDEX (index);
306   if (reg->type == REG_BIT)
307     {
308       if (!bits_pushed)
309         emitcode ("push", "%s", reg->base);
310       return TRUE;
311     }
312   else
313     emitcode ("push", "%s", reg->dname);
314   return bits_pushed;
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* popReg - restores register                                      */
319 /*-----------------------------------------------------------------*/
320 static bool
321 popReg (int index, bool bits_popped)
322 {
323   regs * reg = REG_WITH_INDEX (index);
324   if (reg->type == REG_BIT)
325     {
326       if (!bits_popped)
327         emitcode ("pop", "%s", reg->base);
328       return TRUE;
329     }
330   else
331     emitcode ("pop", "%s", reg->dname);
332   return bits_popped;
333 }
334
335 /*-----------------------------------------------------------------*/
336 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
337 /*-----------------------------------------------------------------*/
338 static regs *
339 getFreePtr (iCode * ic, asmop ** aopp, bool result)
340 {
341   bool r0iu, r1iu;
342   bool r0ou, r1ou;
343
344   /* the logic: if r0 & r1 used in the instruction
345      then we are in trouble otherwise */
346
347   /* first check if r0 & r1 are used by this
348      instruction, in which case we are in trouble */
349   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
350   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
351   if (r0iu && r1iu) {
352       goto endOfWorld;
353     }
354
355   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
356   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
357
358   /* if no usage of r0 then return it */
359   if (!r0iu && !r0ou)
360     {
361       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
362       (*aopp)->type = AOP_R0;
363
364       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
365     }
366
367   /* if no usage of r1 then return it */
368   if (!r1iu && !r1ou)
369     {
370       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
371       (*aopp)->type = AOP_R1;
372
373       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
374     }
375
376   /* now we know they both have usage */
377   /* if r0 not used in this instruction */
378   if (!r0iu)
379     {
380       /* push it if not already pushed */
381       if (ic->op == IPUSH)
382         {
383           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
384           R0INB++;
385         }
386       else if (!_G.r0Pushed)
387         {
388           emitcode ("push", "%s",
389                     REG_WITH_INDEX (R0_IDX)->dname);
390           _G.r0Pushed++;
391         }
392
393       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
394       (*aopp)->type = AOP_R0;
395
396       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
397     }
398
399   /* if r1 not used then */
400
401   if (!r1iu)
402     {
403       /* push it if not already pushed */
404       if (ic->op == IPUSH)
405         {
406           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
407           R1INB++;
408         }
409       else if (!_G.r1Pushed)
410         {
411           emitcode ("push", "%s",
412                     REG_WITH_INDEX (R1_IDX)->dname);
413           _G.r1Pushed++;
414         }
415
416       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
417       (*aopp)->type = AOP_R1;
418       return REG_WITH_INDEX (R1_IDX);
419     }
420
421 endOfWorld:
422   /* I said end of world, but not quite end of world yet */
423   /* if this is a result then we can push it on the stack */
424   if (result)
425     {
426       (*aopp)->type = AOP_STK;
427       return NULL;
428     }
429   /* in the case that result AND left AND right needs a pointer reg
430      we can safely use the result's */
431   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
432     {
433       (*aopp)->type = AOP_R0;
434       return REG_WITH_INDEX (R0_IDX);
435     }
436   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
437     {
438       (*aopp)->type = AOP_R1;
439       return REG_WITH_INDEX (R1_IDX);
440     }
441
442   /* now this is REALLY the end of the world */
443   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
444           "getFreePtr should never reach here");
445   exit (1);
446 }
447
448
449 /*-----------------------------------------------------------------*/
450 /* getTempRegs - initialize an array of pointers to GPR registers */
451 /*               that are not in use. Returns 1 if the requested   */
452 /*               number of registers were available, 0 otherwise.  */
453 /*-----------------------------------------------------------------*/
454 int
455 getTempRegs(regs **tempRegs, int size, iCode *ic)
456 {
457   bitVect * freeRegs;
458   int i;
459   int offset;
460
461   if (!ic)
462     ic = _G.current_iCode;
463   if (!ic)
464     return 0;
465   if (!_G.currentFunc)
466     return 0;
467
468   freeRegs = newBitVect(8);
469   bitVectSetBit (freeRegs, R2_IDX);
470   bitVectSetBit (freeRegs, R3_IDX);
471   bitVectSetBit (freeRegs, R4_IDX);
472   bitVectSetBit (freeRegs, R5_IDX);
473   bitVectSetBit (freeRegs, R6_IDX);
474   bitVectSetBit (freeRegs, R7_IDX);
475
476   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
477     {
478       bitVect * newfreeRegs;
479       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
480       freeBitVect(freeRegs);
481       freeRegs = newfreeRegs;
482     }
483   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
484
485   offset = 0;
486   for (i=0; i<freeRegs->size; i++)
487     {
488       if (bitVectBitValue(freeRegs,i))
489         tempRegs[offset++] = REG_WITH_INDEX(i);
490       if (offset>=size)
491         {
492           freeBitVect(freeRegs);
493           return 1;
494         }
495     }
496
497   freeBitVect(freeRegs);
498   return 0;
499 }
500
501
502 /*-----------------------------------------------------------------*/
503 /* newAsmop - creates a new asmOp                                  */
504 /*-----------------------------------------------------------------*/
505 static asmop *
506 newAsmop (short type)
507 {
508   asmop *aop;
509
510   aop = Safe_calloc (1, sizeof (asmop));
511   aop->type = type;
512   aop->allocated = 1;
513   return aop;
514 }
515
516 /*-----------------------------------------------------------------*/
517 /* pointerCode - returns the code for a pointer type               */
518 /*-----------------------------------------------------------------*/
519 static int
520 pointerCode (sym_link * etype)
521 {
522
523   return PTR_TYPE (SPEC_OCLS (etype));
524
525 }
526
527 /*-----------------------------------------------------------------*/
528 /* leftRightUseAcc - returns size of accumulator use by operands   */
529 /*-----------------------------------------------------------------*/
530 static int
531 leftRightUseAcc(iCode *ic)
532 {
533   operand *op;
534   int size;
535   int accuseSize = 0;
536   int accuse = 0;
537
538   if (!ic)
539     {
540       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
541               "null iCode pointer");
542       return 0;
543     }
544
545   if (ic->op == IFX)
546     {
547       op = IC_COND (ic);
548       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
549         {
550           accuse = 1;
551           size = getSize (OP_SYMBOL (op)->type);
552           if (size>accuseSize)
553             accuseSize = size;
554         }
555     }
556   else if (ic->op == JUMPTABLE)
557     {
558       op = IC_JTCOND (ic);
559       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
560         {
561           accuse = 1;
562           size = getSize (OP_SYMBOL (op)->type);
563           if (size>accuseSize)
564             accuseSize = size;
565         }
566     }
567   else
568     {
569       op = IC_LEFT (ic);
570       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
571         {
572           accuse = 1;
573           size = getSize (OP_SYMBOL (op)->type);
574           if (size>accuseSize)
575             accuseSize = size;
576         }
577       op = IC_RIGHT (ic);
578       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
579         {
580           accuse = 1;
581           size = getSize (OP_SYMBOL (op)->type);
582           if (size>accuseSize)
583             accuseSize = size;
584         }
585     }
586
587   if (accuseSize)
588     return accuseSize;
589   else
590     return accuse;
591 }
592
593 /*-----------------------------------------------------------------*/
594 /* aopForSym - for a true symbol                                   */
595 /*-----------------------------------------------------------------*/
596 static asmop *
597 aopForSym (iCode * ic, symbol * sym, bool result)
598 {
599   asmop *aop;
600   memmap *space;
601   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
602
603   wassertl (ic != NULL, "Got a null iCode");
604   wassertl (sym != NULL, "Got a null symbol");
605
606   space = SPEC_OCLS (sym->etype);
607
608   /* if already has one */
609   if (sym->aop)
610     {
611       sym->aop->allocated++;
612       return sym->aop;
613     }
614
615   /* assign depending on the storage class */
616   /* if it is on the stack or indirectly addressable */
617   /* space we need to assign either r0 or r1 to it   */
618   if (sym->onStack || sym->iaccess)
619     {
620       sym->aop = aop = newAsmop (0);
621       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
622       aop->size = getSize (sym->type);
623
624       /* now assign the address of the variable to
625          the pointer register */
626       if (aop->type != AOP_STK)
627         {
628           if (sym->onStack)
629             {
630               signed char offset = ((sym->stack < 0) ?
631                          ((signed char) (sym->stack - _G.nRegsSaved)) :
632                          ((signed char) sym->stack)) & 0xff;
633
634               if ((abs(offset) <= 3) ||
635                   (accuse && (abs(offset) <= 7)))
636                 {
637                   emitcode ("mov", "%s,%s",
638                             aop->aopu.aop_ptr->name, SYM_BP (sym));
639                   while (offset < 0)
640                     {
641                       emitcode ("dec", aop->aopu.aop_ptr->name);
642                       offset++;
643                     }
644                   while (offset > 0)
645                     {
646                       emitcode ("inc", aop->aopu.aop_ptr->name);
647                       offset--;
648                     }
649                 }
650               else
651                 {
652                   if (accuse)
653                     emitcode ("push", "acc");
654                   emitcode ("mov", "a,%s", SYM_BP (sym));
655                   emitcode ("add", "a,#0x%02x", offset & 0xff);
656                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
657                   if (accuse)
658                     emitcode ("pop", "acc");
659                 }
660             }
661           else
662             {
663               emitcode ("mov", "%s,#%s",
664                         aop->aopu.aop_ptr->name,
665                         sym->rname);
666             }
667           aop->paged = space->paged;
668         }
669       else
670         aop->aopu.aop_stk = sym->stack;
671       return aop;
672     }
673
674   /* if in bit space */
675   if (IN_BITSPACE (space))
676     {
677       sym->aop = aop = newAsmop (AOP_CRY);
678       aop->aopu.aop_dir = sym->rname;
679       aop->size = getSize (sym->type);
680       return aop;
681     }
682   /* if it is in direct space */
683   if (IN_DIRSPACE (space))
684     {
685       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
686       //printTypeChainRaw(sym->type, NULL);
687       //printf("space = %s\n", space ? space->sname : "NULL");
688       sym->aop = aop = newAsmop (AOP_DIR);
689       aop->aopu.aop_dir = sym->rname;
690       aop->size = getSize (sym->type);
691       return aop;
692     }
693
694   /* special case for a function */
695   if (IS_FUNC (sym->type))
696     {
697       sym->aop = aop = newAsmop (AOP_IMMD);
698       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
699       aop->size = getSize (sym->type);
700       return aop;
701     }
702
703   /* only remaining is far space */
704   /* in which case DPTR gets the address */
705   sym->aop = aop = newAsmop (AOP_DPTR);
706   emitcode ("mov", "dptr,#%s", sym->rname);
707   aop->size = getSize (sym->type);
708
709   /* if it is in code space */
710   if (IN_CODESPACE (space))
711     aop->code = 1;
712
713   return aop;
714 }
715
716 /*-----------------------------------------------------------------*/
717 /* aopForRemat - rematerialzes an object                           */
718 /*-----------------------------------------------------------------*/
719 static asmop *
720 aopForRemat (symbol * sym)
721 {
722   iCode *ic = sym->rematiCode;
723   asmop *aop = newAsmop (AOP_IMMD);
724   int ptr_type = 0;
725   int val = 0;
726
727   for (;;)
728     {
729       if (ic->op == '+')
730         val += (int) operandLitValue (IC_RIGHT (ic));
731       else if (ic->op == '-')
732         val -= (int) operandLitValue (IC_RIGHT (ic));
733       else if (IS_CAST_ICODE(ic)) {
734               sym_link *from_type = operandType(IC_RIGHT(ic));
735               aop->aopu.aop_immd.from_cast_remat = 1;
736               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
737               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
738               continue;
739       } else break;
740
741       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
742     }
743
744   if (val)
745     {
746       SNPRINTF (buffer, sizeof(buffer),
747                 "(%s %c 0x%04x)",
748                 OP_SYMBOL (IC_LEFT (ic))->rname,
749                 val >= 0 ? '+' : '-',
750                 abs (val) & 0xffff);
751     }
752   else
753     {
754       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
755     }
756
757   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
758   /* set immd2 field if required */
759   if (aop->aopu.aop_immd.from_cast_remat)
760     {
761       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
762       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
763     }
764
765   return aop;
766 }
767
768 /*-----------------------------------------------------------------*/
769 /* regsInCommon - two operands have some registers in common       */
770 /*-----------------------------------------------------------------*/
771 static bool
772 regsInCommon (operand * op1, operand * op2)
773 {
774   symbol *sym1, *sym2;
775   int i;
776
777   /* if they have registers in common */
778   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
779     return FALSE;
780
781   sym1 = OP_SYMBOL (op1);
782   sym2 = OP_SYMBOL (op2);
783
784   if (sym1->nRegs == 0 || sym2->nRegs == 0)
785     return FALSE;
786
787   for (i = 0; i < sym1->nRegs; i++)
788     {
789       int j;
790       if (!sym1->regs[i])
791         continue;
792
793       for (j = 0; j < sym2->nRegs; j++)
794         {
795           if (!sym2->regs[j])
796             continue;
797
798           if (sym2->regs[j] == sym1->regs[i])
799             return TRUE;
800         }
801     }
802
803   return FALSE;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* operandsEqu - equivalent                                        */
808 /*-----------------------------------------------------------------*/
809 static bool
810 operandsEqu (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813
814   /* if they're not symbols */
815   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
816     return FALSE;
817
818   sym1 = OP_SYMBOL (op1);
819   sym2 = OP_SYMBOL (op2);
820
821   /* if both are itemps & one is spilt
822      and the other is not then false */
823   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
824       sym1->isspilt != sym2->isspilt)
825     return FALSE;
826
827   /* if they are the same */
828   if (sym1 == sym2)
829     return TRUE;
830
831   /* if they have the same rname */
832   if (sym1->rname[0] && sym2->rname[0] &&
833       strcmp (sym1->rname, sym2->rname) == 0 &&
834       !(IS_PARM (op2) && IS_ITEMP (op1)))
835     return TRUE;
836
837   /* if left is a tmp & right is not */
838   if (IS_ITEMP (op1) &&
839       !IS_ITEMP (op2) &&
840       sym1->isspilt &&
841       (sym1->usl.spillLoc == sym2))
842     return TRUE;
843
844   if (IS_ITEMP (op2) &&
845       !IS_ITEMP (op1) &&
846       sym2->isspilt &&
847       sym1->level > 0 &&
848       (sym2->usl.spillLoc == sym1))
849     return TRUE;
850
851   return FALSE;
852 }
853
854 /*-----------------------------------------------------------------*/
855 /* sameByte - two asmops have the same address at given offsets    */
856 /*-----------------------------------------------------------------*/
857 static bool
858 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
859 {
860   if (aop1 == aop2 && off1 == off2)
861     return TRUE;
862
863   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
864     return FALSE;
865
866   if (aop1->type != aop2->type)
867     return FALSE;
868
869   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
870     return FALSE;
871
872   return TRUE;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* sameRegs - two asmops have the same registers                   */
877 /*-----------------------------------------------------------------*/
878 static bool
879 sameRegs (asmop * aop1, asmop * aop2)
880 {
881   int i;
882
883   if (aop1 == aop2)
884     return TRUE;
885
886   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
887     return FALSE;
888
889   if (aop1->type != aop2->type)
890     return FALSE;
891
892   if (aop1->size != aop2->size)
893     return FALSE;
894
895   for (i = 0; i < aop1->size; i++)
896     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
897       return FALSE;
898
899   return TRUE;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* aopOp - allocates an asmop for an operand  :                    */
904 /*-----------------------------------------------------------------*/
905 static void
906 aopOp (operand * op, iCode * ic, bool result)
907 {
908   asmop *aop;
909   symbol *sym;
910   int i;
911
912   if (!op)
913     return;
914
915   /* if this a literal */
916   if (IS_OP_LITERAL (op))
917     {
918       op->aop = aop = newAsmop (AOP_LIT);
919       aop->aopu.aop_lit = op->operand.valOperand;
920       aop->size = getSize (operandType (op));
921       return;
922     }
923
924   /* if already has a asmop then continue */
925   if (op->aop)
926     {
927       op->aop->allocated++;
928       return;
929     }
930
931   /* if the underlying symbol has a aop */
932   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
933     {
934       op->aop = OP_SYMBOL (op)->aop;
935       op->aop->allocated++;
936       return;
937     }
938
939   /* if this is a true symbol */
940   if (IS_TRUE_SYMOP (op))
941     {
942       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
943       return;
944     }
945
946   /* this is a temporary : this has
947      only five choices :
948      a) register
949      b) spillocation
950      c) rematerialize
951      d) conditional
952      e) can be a return use only */
953
954   sym = OP_SYMBOL (op);
955
956   /* if the type is a conditional */
957   if (sym->regType == REG_CND)
958     {
959       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
960       aop->size = sym->ruonly ? 1 : 0;
961       return;
962     }
963
964   /* if it is spilt then two situations
965      a) is rematerialize
966      b) has a spill location */
967   if (sym->isspilt || sym->nRegs == 0)
968     {
969
970       /* rematerialize it NOW */
971       if (sym->remat)
972         {
973           sym->aop = op->aop = aop = aopForRemat (sym);
974           aop->size = getSize (sym->type);
975           return;
976         }
977
978       if (sym->accuse)
979         {
980           int i;
981           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
982           aop->size = getSize (sym->type);
983           for (i = 0; i < 2; i++)
984             aop->aopu.aop_str[i] = accUse[i];
985           return;
986         }
987
988       if (sym->ruonly)
989         {
990           unsigned i;
991
992           sym->aop = op->aop = aop = newAsmop (AOP_STR);
993           aop->size = getSize (sym->type);
994           for (i = 0; i < fReturnSizeMCS51; i++)
995             aop->aopu.aop_str[i] = fReturn[i];
996           return;
997         }
998
999       if (sym->usl.spillLoc)
1000         {
1001           asmop *oldAsmOp = NULL;
1002
1003           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1004             {
1005               /* force a new aop if sizes differ */
1006               oldAsmOp = sym->usl.spillLoc->aop;
1007               sym->usl.spillLoc->aop = NULL;
1008             }
1009           sym->aop = op->aop = aop =
1010                      aopForSym (ic, sym->usl.spillLoc, result);
1011           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1012             {
1013               /* Don't reuse the new aop, go with the last one */
1014               sym->usl.spillLoc->aop = oldAsmOp;
1015             }
1016           aop->size = getSize (sym->type);
1017           return;
1018         }
1019
1020       /* else must be a dummy iTemp */
1021       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1022       aop->size = getSize (sym->type);
1023       return;
1024     }
1025
1026   /* if the type is a bit register */
1027   if (sym->regType == REG_BIT)
1028     {
1029       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1030       aop->size = sym->nRegs;//1???
1031       aop->aopu.aop_reg[0] = sym->regs[0];
1032       aop->aopu.aop_dir = sym->regs[0]->name;
1033       return;
1034     }
1035
1036   /* must be in a register */
1037   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1038   aop->size = sym->nRegs;
1039   for (i = 0; i < sym->nRegs; i++)
1040     aop->aopu.aop_reg[i] = sym->regs[i];
1041 }
1042
1043 /*-----------------------------------------------------------------*/
1044 /* freeAsmop - free up the asmop given to an operand               */
1045 /*----------------------------------------------------------------*/
1046 static void
1047 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1048 {
1049   asmop *aop;
1050
1051   if (!op)
1052     aop = aaop;
1053   else
1054     aop = op->aop;
1055
1056   if (!aop)
1057     return;
1058
1059   aop->allocated--;
1060
1061   if (aop->allocated)
1062     goto dealloc;
1063
1064   /* depending on the asmop type only three cases need work
1065      AOP_R0, AOP_R1 & AOP_STK */
1066   switch (aop->type)
1067     {
1068     case AOP_R0:
1069       if (R0INB)
1070         {
1071           emitcode ("mov", "r0,b");
1072           R0INB--;
1073         }
1074       else if (_G.r0Pushed)
1075         {
1076           if (pop)
1077             {
1078               emitcode ("pop", "ar0");
1079               _G.r0Pushed--;
1080             }
1081         }
1082       bitVectUnSetBit (ic->rUsed, R0_IDX);
1083       break;
1084
1085     case AOP_R1:
1086       if (R1INB)
1087         {
1088           emitcode ("mov", "r1,b");
1089           R1INB--;
1090         }
1091       else if (_G.r1Pushed)
1092         {
1093           if (pop)
1094             {
1095               emitcode ("pop", "ar1");
1096               _G.r1Pushed--;
1097             }
1098         }
1099       bitVectUnSetBit (ic->rUsed, R1_IDX);
1100       break;
1101
1102     case AOP_STK:
1103       {
1104         int sz = aop->size;
1105         int stk = aop->aopu.aop_stk + aop->size - 1;
1106         bitVectUnSetBit (ic->rUsed, R0_IDX);
1107         bitVectUnSetBit (ic->rUsed, R1_IDX);
1108
1109         getFreePtr (ic, &aop, FALSE);
1110
1111         if (stk)
1112           {
1113             emitcode ("mov", "a,_bp");
1114             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1115             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1116           }
1117         else
1118           {
1119             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1120           }
1121
1122         while (sz--)
1123           {
1124             emitcode ("pop", "acc");
1125             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1126             if (!sz)
1127               break;
1128             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1129           }
1130         op->aop = aop;
1131         freeAsmop (op, NULL, ic, TRUE);
1132         if (_G.r1Pushed)
1133           {
1134             emitcode ("pop", "ar1");
1135             _G.r1Pushed--;
1136           }
1137         if (_G.r0Pushed)
1138           {
1139             emitcode ("pop", "ar0");
1140             _G.r0Pushed--;
1141           }
1142       }
1143       break;
1144     }
1145
1146 dealloc:
1147   /* all other cases just dealloc */
1148   if (op)
1149     {
1150       op->aop = NULL;
1151       if (IS_SYMOP (op))
1152         {
1153           OP_SYMBOL (op)->aop = NULL;
1154           /* if the symbol has a spill */
1155           if (SPIL_LOC (op))
1156             SPIL_LOC (op)->aop = NULL;
1157         }
1158     }
1159 }
1160
1161 /*------------------------------------------------------------------*/
1162 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1163 /*                      pop r0 or r1 off stack if pushed            */
1164 /*------------------------------------------------------------------*/
1165 static void
1166 freeForBranchAsmop (operand * op)
1167 {
1168   asmop *aop;
1169
1170   if (!op)
1171     return;
1172
1173   aop = op->aop;
1174
1175   if (!aop)
1176     return;
1177
1178   if (!aop->allocated)
1179     return;
1180
1181   switch (aop->type)
1182     {
1183     case AOP_R0:
1184       if (R0INB)
1185         {
1186           emitcode ("mov", "r0,b");
1187         }
1188       else if (_G.r0Pushed)
1189         {
1190           emitcode ("pop", "ar0");
1191         }
1192       break;
1193
1194     case AOP_R1:
1195       if (R1INB)
1196         {
1197           emitcode ("mov", "r1,b");
1198         }
1199       else if (_G.r1Pushed)
1200         {
1201           emitcode ("pop", "ar1");
1202         }
1203       break;
1204
1205     case AOP_STK:
1206       {
1207         int sz = aop->size;
1208         int stk = aop->aopu.aop_stk + aop->size - 1;
1209
1210         emitcode ("mov", "b,r0");
1211         if (stk)
1212           {
1213             emitcode ("mov", "a,_bp");
1214             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1215             emitcode ("mov", "r0,a");
1216           }
1217         else
1218           {
1219             emitcode ("mov", "r0,_bp");
1220           }
1221
1222         while (sz--)
1223           {
1224             emitcode ("pop", "acc");
1225             emitcode ("mov", "@r0,a");
1226             if (!sz)
1227               break;
1228             emitcode ("dec", "r0");
1229           }
1230         emitcode ("mov", "r0,b");
1231       }
1232     }
1233
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1238 /*                 clobber the accumulator                         */
1239 /*-----------------------------------------------------------------*/
1240 static bool
1241 aopGetUsesAcc (operand * oper, int offset)
1242 {
1243   asmop * aop = AOP (oper);
1244
1245   if (offset > (aop->size - 1))
1246     return FALSE;
1247
1248   switch (aop->type)
1249     {
1250
1251     case AOP_R0:
1252     case AOP_R1:
1253       if (aop->paged)
1254         return TRUE;
1255       return FALSE;
1256     case AOP_DPTR:
1257       return TRUE;
1258     case AOP_IMMD:
1259       return FALSE;
1260     case AOP_DIR:
1261       return FALSE;
1262     case AOP_REG:
1263       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1264       return FALSE;
1265     case AOP_CRY:
1266       return TRUE;
1267     case AOP_ACC:
1268       if (offset)
1269         return FALSE;
1270       return TRUE;
1271     case AOP_LIT:
1272       return FALSE;
1273     case AOP_STR:
1274       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1275         return TRUE;
1276       return FALSE;
1277     case AOP_DUMMY:
1278       return FALSE;
1279     default:
1280       /* Error case --- will have been caught already */
1281       wassert(0);
1282       return FALSE;
1283     }
1284 }
1285
1286 /*-------------------------------------------------------------------*/
1287 /* aopGet - for fetching value of the aop                            */
1288 /*-------------------------------------------------------------------*/
1289 static char *
1290 aopGet (operand * oper, int offset, bool bit16, bool dname)
1291 {
1292   asmop * aop = AOP (oper);
1293
1294   /* offset is greater than
1295      size then zero */
1296   if (offset > (aop->size - 1) &&
1297       aop->type != AOP_LIT)
1298     return zero;
1299
1300   /* depending on type */
1301   switch (aop->type)
1302     {
1303     case AOP_DUMMY:
1304       return zero;
1305
1306     case AOP_R0:
1307     case AOP_R1:
1308       /* if we need to increment it */
1309       while (offset > aop->coff)
1310         {
1311           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1312           aop->coff++;
1313         }
1314
1315       while (offset < aop->coff)
1316         {
1317           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1318           aop->coff--;
1319         }
1320
1321       aop->coff = offset;
1322       if (aop->paged)
1323         {
1324           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1325           return (dname ? "acc" : "a");
1326         }
1327       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1328       return Safe_strdup(buffer);
1329
1330     case AOP_DPTR:
1331       if (aop->code && aop->coff==0 && offset>=1) {
1332         emitcode ("mov", "a,#0x%02x", offset);
1333         emitcode ("movc", "a,@a+dptr");
1334         return (dname ? "acc" : "a");
1335       }
1336
1337       while (offset > aop->coff)
1338         {
1339           emitcode ("inc", "dptr");
1340           aop->coff++;
1341         }
1342
1343       while (offset < aop->coff)
1344         {
1345           emitcode ("lcall", "__decdptr");
1346           aop->coff--;
1347         }
1348
1349       aop->coff = offset;
1350       if (aop->code)
1351         {
1352           emitcode ("clr", "a");
1353           emitcode ("movc", "a,@a+dptr");
1354         }
1355       else
1356         {
1357           emitcode ("movx", "a,@dptr");
1358         }
1359       return (dname ? "acc" : "a");
1360
1361     case AOP_IMMD:
1362       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1363         {
1364           SNPRINTF(buffer, sizeof(buffer),
1365                    "%s",aop->aopu.aop_immd.aop_immd2);
1366         }
1367       else if (bit16)
1368         {
1369           SNPRINTF(buffer, sizeof(buffer),
1370                    "#%s", aop->aopu.aop_immd.aop_immd1);
1371         }
1372       else if (offset)
1373         {
1374           SNPRINTF (buffer, sizeof(buffer),
1375                     "#(%s >> %d)",
1376                     aop->aopu.aop_immd.aop_immd1,
1377                     offset * 8);
1378         }
1379       else
1380         {
1381           SNPRINTF (buffer, sizeof(buffer),
1382                     "#%s",
1383                     aop->aopu.aop_immd.aop_immd1);
1384         }
1385       return Safe_strdup(buffer);
1386
1387     case AOP_DIR:
1388       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1389         {
1390           SNPRINTF (buffer, sizeof(buffer),
1391                     "(%s >> %d)",
1392                     aop->aopu.aop_dir, offset * 8);
1393         }
1394       else if (offset)
1395         {
1396           SNPRINTF (buffer, sizeof(buffer),
1397                     "(%s + %d)",
1398                     aop->aopu.aop_dir,
1399                     offset);
1400         }
1401       else
1402         {
1403           SNPRINTF (buffer, sizeof(buffer),
1404                     "%s",
1405                     aop->aopu.aop_dir);
1406         }
1407
1408       return Safe_strdup(buffer);
1409
1410     case AOP_REG:
1411       if (dname)
1412         return aop->aopu.aop_reg[offset]->dname;
1413       else
1414         return aop->aopu.aop_reg[offset]->name;
1415
1416     case AOP_CRY:
1417       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1418       emitcode ("clr", "a");
1419       emitcode ("rlc", "a");
1420       return (dname ? "acc" : "a");
1421
1422     case AOP_ACC:
1423       if (!offset && dname)
1424         return "acc";
1425       return aop->aopu.aop_str[offset];
1426
1427     case AOP_LIT:
1428       return aopLiteral (aop->aopu.aop_lit, offset);
1429
1430     case AOP_STR:
1431       aop->coff = offset;
1432       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1433           dname)
1434         return "acc";
1435
1436       return aop->aopu.aop_str[offset];
1437
1438     }
1439
1440   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1441           "aopget got unsupported aop->type");
1442   exit (1);
1443 }
1444
1445 /*-----------------------------------------------------------------*/
1446 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1447 /*                 clobber the accumulator                         */
1448 /*-----------------------------------------------------------------*/
1449 static bool
1450 aopPutUsesAcc (operand * oper, const char *s, int offset)
1451 {
1452   asmop * aop = AOP (oper);
1453
1454   if (offset > (aop->size - 1))
1455     return FALSE;
1456
1457   switch (aop->type)
1458     {
1459     case AOP_DUMMY:
1460       return TRUE;
1461     case AOP_DIR:
1462       return FALSE;
1463     case AOP_REG:
1464       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1465       return FALSE;
1466     case AOP_DPTR:
1467       return TRUE;
1468     case AOP_R0:
1469     case AOP_R1:
1470       return ((aop->paged) || (*s == '@'));
1471     case AOP_STK:
1472       return (*s == '@');
1473     case AOP_CRY:
1474       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1475     case AOP_STR:
1476       return FALSE;
1477     case AOP_IMMD:
1478       return FALSE;
1479     case AOP_ACC:
1480       return FALSE;
1481     default:
1482       /* Error case --- will have been caught already */
1483       wassert(0);
1484       return FALSE;
1485     }
1486 }
1487
1488 /*-----------------------------------------------------------------*/
1489 /* aopPut - puts a string for a aop and indicates if acc is in use */
1490 /*-----------------------------------------------------------------*/
1491 static bool
1492 aopPut (operand * result, const char *s, int offset)
1493 {
1494   bool bvolatile = isOperandVolatile (result, FALSE);
1495   bool accuse = FALSE;
1496   asmop * aop = AOP (result);
1497   const char *d = NULL;
1498
1499   if (aop->size && offset > (aop->size - 1))
1500     {
1501       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1502               "aopPut got offset > aop->size");
1503       exit (1);
1504     }
1505
1506   /* will assign value to value */
1507   /* depending on where it is ofcourse */
1508   switch (aop->type)
1509     {
1510     case AOP_DUMMY:
1511       MOVA (s);         /* read s in case it was volatile */
1512       accuse = TRUE;
1513       break;
1514
1515     case AOP_DIR:
1516       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1517         {
1518           SNPRINTF (buffer, sizeof(buffer),
1519                     "(%s >> %d)",
1520                     aop->aopu.aop_dir, offset * 8);
1521         }
1522       else if (offset)
1523         {
1524           SNPRINTF (buffer, sizeof(buffer),
1525                     "(%s + %d)",
1526                     aop->aopu.aop_dir, offset);
1527         }
1528       else
1529         {
1530           SNPRINTF (buffer, sizeof(buffer),
1531                     "%s",
1532                     aop->aopu.aop_dir);
1533         }
1534
1535       if (strcmp (buffer, s) || bvolatile)
1536         {
1537           emitcode ("mov", "%s,%s", buffer, s);
1538         }
1539       if (!strcmp (buffer, "acc"))
1540         {
1541           accuse = TRUE;
1542         }
1543       break;
1544
1545     case AOP_REG:
1546       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1547           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1548         {
1549           if (*s == '@' ||
1550               strcmp (s, "r0") == 0 ||
1551               strcmp (s, "r1") == 0 ||
1552               strcmp (s, "r2") == 0 ||
1553               strcmp (s, "r3") == 0 ||
1554               strcmp (s, "r4") == 0 ||
1555               strcmp (s, "r5") == 0 ||
1556               strcmp (s, "r6") == 0 ||
1557               strcmp (s, "r7") == 0)
1558             {
1559               emitcode ("mov", "%s,%s",
1560                         aop->aopu.aop_reg[offset]->dname, s);
1561             }
1562           else
1563             {
1564               emitcode ("mov", "%s,%s",
1565                         aop->aopu.aop_reg[offset]->name, s);
1566             }
1567         }
1568       break;
1569
1570     case AOP_DPTR:
1571       if (aop->code)
1572         {
1573           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1574                   "aopPut writing to code space");
1575           exit (1);
1576         }
1577
1578       while (offset > aop->coff)
1579         {
1580           aop->coff++;
1581           emitcode ("inc", "dptr");
1582         }
1583
1584       while (offset < aop->coff)
1585         {
1586           aop->coff--;
1587           emitcode ("lcall", "__decdptr");
1588         }
1589
1590       aop->coff = offset;
1591
1592       /* if not in accumulator */
1593       MOVA (s);
1594
1595       emitcode ("movx", "@dptr,a");
1596       break;
1597
1598     case AOP_R0:
1599     case AOP_R1:
1600       while (offset > aop->coff)
1601         {
1602           aop->coff++;
1603           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1604         }
1605       while (offset < aop->coff)
1606         {
1607           aop->coff--;
1608           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1609         }
1610       aop->coff = offset;
1611
1612       if (aop->paged)
1613         {
1614           MOVA (s);
1615           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1616         }
1617       else if (*s == '@')
1618         {
1619           MOVA (s);
1620           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1621         }
1622       else if (strcmp (s, "r0") == 0 ||
1623                strcmp (s, "r1") == 0 ||
1624                strcmp (s, "r2") == 0 ||
1625                strcmp (s, "r3") == 0 ||
1626                strcmp (s, "r4") == 0 ||
1627                strcmp (s, "r5") == 0 ||
1628                strcmp (s, "r6") == 0 ||
1629                strcmp (s, "r7") == 0)
1630         {
1631           char buffer[10];
1632           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1633           emitcode ("mov", "@%s,%s",
1634                     aop->aopu.aop_ptr->name, buffer);
1635         }
1636       else
1637         {
1638           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1639         }
1640       break;
1641
1642     case AOP_STK:
1643       if (strcmp (s, "a") == 0)
1644         {
1645           emitcode ("push", "acc");
1646         }
1647       else if (*s=='@')
1648         {
1649           MOVA(s);
1650           emitcode ("push", "acc");
1651         }
1652       else if (strcmp (s, "r0") == 0 ||
1653                strcmp (s, "r1") == 0 ||
1654                strcmp (s, "r2") == 0 ||
1655                strcmp (s, "r3") == 0 ||
1656                strcmp (s, "r4") == 0 ||
1657                strcmp (s, "r5") == 0 ||
1658                strcmp (s, "r6") == 0 ||
1659                strcmp (s, "r7") == 0)
1660         {
1661           char buffer[10];
1662           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1663           emitcode ("push", buffer);
1664         }
1665       else
1666         {
1667           emitcode ("push", s);
1668         }
1669
1670       break;
1671
1672     case AOP_CRY:
1673       // destination is carry for return-use-only
1674       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1675       // source is no literal and not in carry
1676       if ((s != zero) && (s != one) && strcmp (s, "c"))
1677         {
1678           MOVA (s);
1679           /* set C, if a >= 1 */
1680           emitcode ("add", "a,#0xff");
1681           s = "c";
1682         }
1683       // now source is zero, one or carry
1684
1685       /* if result no bit variable */
1686       if (!d)
1687         {
1688           if (!strcmp (s, "c"))
1689             {
1690               /* inefficient: move carry into A and use jz/jnz */
1691               emitcode ("clr", "a");
1692               emitcode ("rlc", "a");
1693               accuse = TRUE;
1694             }
1695           else
1696             {
1697               MOVA (s);
1698               accuse = TRUE;
1699             }
1700         }
1701       else if (s == zero)
1702           emitcode ("clr", "%s", d);
1703       else if (s == one)
1704           emitcode ("setb", "%s", d);
1705       else if (strcmp (s, d))
1706           emitcode ("mov", "%s,c", d);
1707       break;
1708
1709     case AOP_STR:
1710       aop->coff = offset;
1711       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1712         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1713       break;
1714
1715     case AOP_ACC:
1716       accuse = TRUE;
1717       aop->coff = offset;
1718       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1719         break;
1720
1721       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1722         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1723       break;
1724
1725     default:
1726       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1727               "aopPut got unsupported aop->type");
1728       exit (1);
1729     }
1730
1731     return accuse;
1732 }
1733
1734
1735 #if 0
1736 /*-----------------------------------------------------------------*/
1737 /* pointToEnd :- points to the last byte of the operand            */
1738 /*-----------------------------------------------------------------*/
1739 static void
1740 pointToEnd (asmop * aop)
1741 {
1742   int count;
1743   if (!aop)
1744     return;
1745
1746   aop->coff = count = (aop->size - 1);
1747   switch (aop->type)
1748     {
1749     case AOP_R0:
1750     case AOP_R1:
1751       while (count--)
1752         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1753       break;
1754     case AOP_DPTR:
1755       while (count--)
1756         emitcode ("inc", "dptr");
1757       break;
1758     }
1759
1760 }
1761 #endif
1762
1763 /*-----------------------------------------------------------------*/
1764 /* reAdjustPreg - points a register back to where it should        */
1765 /*-----------------------------------------------------------------*/
1766 static void
1767 reAdjustPreg (asmop * aop)
1768 {
1769   if ((aop->coff==0) || (aop->size <= 1))
1770     return;
1771
1772   switch (aop->type)
1773     {
1774     case AOP_R0:
1775     case AOP_R1:
1776       while (aop->coff--)
1777         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1778       break;
1779     case AOP_DPTR:
1780       while (aop->coff--)
1781         {
1782           emitcode ("lcall", "__decdptr");
1783         }
1784       break;
1785     }
1786   aop->coff = 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* opIsGptr: returns non-zero if the passed operand is       */
1791 /* a generic pointer type.             */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 opIsGptr (operand * op)
1795 {
1796   sym_link *type = operandType (op);
1797
1798   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1799     {
1800       return 1;
1801     }
1802   return 0;
1803 }
1804
1805 /*-----------------------------------------------------------------*/
1806 /* getDataSize - get the operand data size                         */
1807 /*-----------------------------------------------------------------*/
1808 static int
1809 getDataSize (operand * op)
1810 {
1811   int size;
1812   size = AOP_SIZE (op);
1813   if (size == GPTRSIZE)
1814     {
1815       sym_link *type = operandType (op);
1816       if (IS_GENPTR (type))
1817         {
1818           /* generic pointer; arithmetic operations
1819            * should ignore the high byte (pointer type).
1820            */
1821           size--;
1822         }
1823     }
1824   return size;
1825 }
1826
1827 /*-----------------------------------------------------------------*/
1828 /* outAcc - output Acc                                             */
1829 /*-----------------------------------------------------------------*/
1830 static void
1831 outAcc (operand * result)
1832 {
1833   int size, offset;
1834   size = getDataSize (result);
1835   if (size)
1836     {
1837       aopPut (result, "a", 0);
1838       size--;
1839       offset = 1;
1840       /* unsigned or positive */
1841       while (size--)
1842         {
1843           aopPut (result, zero, offset++);
1844         }
1845     }
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* outBitC - output a bit C                                        */
1850 /*-----------------------------------------------------------------*/
1851 static void
1852 outBitC (operand * result)
1853 {
1854   /* if the result is bit */
1855   if (AOP_TYPE (result) == AOP_CRY)
1856     {
1857       if (!OP_SYMBOL (result)->ruonly)
1858         aopPut (result, "c", 0);
1859     }
1860   else
1861     {
1862       emitcode ("clr", "a");
1863       emitcode ("rlc", "a");
1864       outAcc (result);
1865     }
1866 }
1867
1868 /*-----------------------------------------------------------------*/
1869 /* toBoolean - emit code for orl a,operator(sizeop)                */
1870 /*-----------------------------------------------------------------*/
1871 static void
1872 toBoolean (operand * oper)
1873 {
1874   int size = AOP_SIZE (oper) - 1;
1875   int offset = 1;
1876   bool AccUsed = FALSE;
1877   bool pushedB;
1878
1879   while (!AccUsed && size--)
1880     {
1881       AccUsed |= aopGetUsesAcc(oper, offset++);
1882     }
1883
1884   size = AOP_SIZE (oper) - 1;
1885   offset = 1;
1886   MOVA (aopGet (oper, 0, FALSE, FALSE));
1887   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1888     {
1889       pushedB = pushB ();
1890       emitcode("mov", "b,a");
1891       while (--size)
1892         {
1893           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1894           emitcode ("orl", "b,a");
1895         }
1896       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1897       emitcode ("orl", "a,b");
1898       popB (pushedB);
1899     }
1900   else
1901     {
1902       while (size--)
1903         {
1904           emitcode ("orl", "a,%s",
1905                     aopGet (oper, offset++, FALSE, FALSE));
1906         }
1907     }
1908 }
1909
1910 /*-----------------------------------------------------------------*/
1911 /* toCarry - make boolean and move into carry                      */
1912 /*-----------------------------------------------------------------*/
1913 static void
1914 toCarry (operand * oper)
1915 {
1916   /* if the operand is a literal then
1917      we know what the value is */
1918   if (AOP_TYPE (oper) == AOP_LIT)
1919     {
1920       if ((int) operandLitValue (oper))
1921         SETC;
1922       else
1923         CLRC;
1924     }
1925   else if (AOP_TYPE (oper) == AOP_CRY)
1926     {
1927       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1928     }
1929   else
1930     {
1931       /* or the operand into a */
1932       toBoolean (oper);
1933       /* set C, if a >= 1 */
1934       emitcode ("add", "a,#0xff");
1935     }
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* assignBit - assign operand to bit operand                       */
1940 /*-----------------------------------------------------------------*/
1941 static void
1942 assignBit (operand * result, operand * right)
1943 {
1944   /* if the right side is a literal then
1945      we know what the value is */
1946   if (AOP_TYPE (right) == AOP_LIT)
1947     {
1948       if ((int) operandLitValue (right))
1949         aopPut (result, one, 0);
1950       else
1951         aopPut (result, zero, 0);
1952     }
1953   else
1954     {
1955       toCarry (right);
1956       aopPut (result, "c", 0);
1957     }
1958 }
1959
1960
1961 /*-------------------------------------------------------------------*/
1962 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1963 /*-------------------------------------------------------------------*/
1964 static char *
1965 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1966 {
1967   char * l;
1968
1969   if (aopGetUsesAcc (oper, offset))
1970     {
1971       emitcode("mov", "b,a");
1972       MOVA (aopGet (oper, offset, bit16, dname));
1973       emitcode("xch", "a,b");
1974       aopPut (oper, "a", offset);
1975       emitcode("xch", "a,b");
1976       l = "b";
1977     }
1978   else
1979     {
1980       l = aopGet (oper, offset, bit16, dname);
1981       emitcode("xch", "a,%s", l);
1982     }
1983   return l;
1984 }
1985
1986
1987 /*-----------------------------------------------------------------*/
1988 /* genNot - generate code for ! operation                          */
1989 /*-----------------------------------------------------------------*/
1990 static void
1991 genNot (iCode * ic)
1992 {
1993   symbol *tlbl;
1994
1995   D (emitcode (";", "genNot"));
1996
1997   /* assign asmOps to operand & result */
1998   aopOp (IC_LEFT (ic), ic, FALSE);
1999   aopOp (IC_RESULT (ic), ic, TRUE);
2000
2001   /* if in bit space then a special case */
2002   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2003     {
2004       /* if left==result then cpl bit */
2005       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2006         {
2007           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2008         }
2009       else
2010         {
2011           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2012           emitcode ("cpl", "c");
2013           outBitC (IC_RESULT (ic));
2014         }
2015       goto release;
2016     }
2017
2018   toBoolean (IC_LEFT (ic));
2019
2020   /* set C, if a == 0 */
2021   tlbl = newiTempLabel (NULL);
2022   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2023   emitLabel (tlbl);
2024   outBitC (IC_RESULT (ic));
2025
2026 release:
2027   /* release the aops */
2028   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2029   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2030 }
2031
2032
2033 /*-----------------------------------------------------------------*/
2034 /* genCpl - generate code for complement                           */
2035 /*-----------------------------------------------------------------*/
2036 static void
2037 genCpl (iCode * ic)
2038 {
2039   int offset = 0;
2040   int size;
2041   symbol *tlbl;
2042   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2043
2044   D(emitcode (";", "genCpl"));
2045
2046   /* assign asmOps to operand & result */
2047   aopOp (IC_LEFT (ic), ic, FALSE);
2048   aopOp (IC_RESULT (ic), ic, TRUE);
2049
2050   /* special case if in bit space */
2051   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2052     {
2053       char *l;
2054
2055       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2056           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2057         {
2058           /* promotion rules are responsible for this strange result:
2059              bit -> int -> ~int -> bit
2060              uchar -> int -> ~int -> bit
2061           */
2062           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2063           goto release;
2064         }
2065
2066       tlbl=newiTempLabel(NULL);
2067       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2068       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2069           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2070           IS_AOP_PREG (IC_LEFT (ic)))
2071         {
2072           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2073         }
2074       else
2075         {
2076           MOVA (l);
2077           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2078         }
2079       emitLabel (tlbl);
2080       outBitC (IC_RESULT(ic));
2081       goto release;
2082     }
2083
2084   size = AOP_SIZE (IC_RESULT (ic));
2085   while (size--)
2086     {
2087       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2088       MOVA (l);
2089       emitcode ("cpl", "a");
2090       aopPut (IC_RESULT (ic), "a", offset++);
2091     }
2092
2093
2094 release:
2095   /* release the aops */
2096   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2097   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* genUminusFloat - unary minus for floating points                */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 genUminusFloat (operand * op, operand * result)
2105 {
2106   int size, offset = 0;
2107   char *l;
2108
2109   D (emitcode (";", "genUminusFloat"));
2110
2111   /* for this we just copy and then flip the bit */
2112
2113   size = AOP_SIZE (op) - 1;
2114
2115   while (size--)
2116     {
2117       aopPut (result,
2118               aopGet (op, offset, FALSE, FALSE),
2119               offset);
2120       offset++;
2121     }
2122
2123   l = aopGet (op, offset, FALSE, FALSE);
2124   MOVA (l);
2125
2126   emitcode ("cpl", "acc.7");
2127   aopPut (result, "a", offset);
2128 }
2129
2130 /*-----------------------------------------------------------------*/
2131 /* genUminus - unary minus code generation                         */
2132 /*-----------------------------------------------------------------*/
2133 static void
2134 genUminus (iCode * ic)
2135 {
2136   int offset, size;
2137   sym_link *optype;
2138
2139   D (emitcode (";", "genUminus"));
2140
2141   /* assign asmops */
2142   aopOp (IC_LEFT (ic), ic, FALSE);
2143   aopOp (IC_RESULT (ic), ic, TRUE);
2144
2145   /* if both in bit space then special
2146      case */
2147   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2148       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2149     {
2150
2151       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2152       emitcode ("cpl", "c");
2153       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2154       goto release;
2155     }
2156
2157   optype = operandType (IC_LEFT (ic));
2158
2159   /* if float then do float stuff */
2160   if (IS_FLOAT (optype))
2161     {
2162       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2163       goto release;
2164     }
2165
2166   /* otherwise subtract from zero */
2167   size = AOP_SIZE (IC_LEFT (ic));
2168   offset = 0;
2169   while (size--)
2170     {
2171       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2172       if (!strcmp (l, "a"))
2173         {
2174           if (offset == 0)
2175             SETC;
2176           emitcode ("cpl", "a");
2177           emitcode ("addc", "a,#0");
2178         }
2179       else
2180         {
2181           if (offset == 0)
2182             CLRC;
2183           emitcode ("clr", "a");
2184           emitcode ("subb", "a,%s", l);
2185         }
2186       aopPut (IC_RESULT (ic), "a", offset++);
2187     }
2188
2189   /* if any remaining bytes in the result */
2190   /* we just need to propagate the sign   */
2191   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2192     {
2193       emitcode ("rlc", "a");
2194       emitcode ("subb", "a,acc");
2195       while (size--)
2196         aopPut (IC_RESULT (ic), "a", offset++);
2197     }
2198
2199 release:
2200   /* release the aops */
2201   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2202   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2203 }
2204
2205 /*-----------------------------------------------------------------*/
2206 /* saveRegisters - will look for a call and save the registers     */
2207 /*-----------------------------------------------------------------*/
2208 static void
2209 saveRegisters (iCode * lic)
2210 {
2211   int i;
2212   iCode *ic;
2213   bitVect *rsave;
2214
2215   /* look for call */
2216   for (ic = lic; ic; ic = ic->next)
2217     if (ic->op == CALL || ic->op == PCALL)
2218       break;
2219
2220   if (!ic)
2221     {
2222       fprintf (stderr, "found parameter push with no function call\n");
2223       return;
2224     }
2225
2226   /* if the registers have been saved already or don't need to be then
2227      do nothing */
2228   if (ic->regsSaved)
2229     return;
2230   if (IS_SYMOP(IC_LEFT(ic)) &&
2231       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2232        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2233     return;
2234
2235   /* save the registers in use at this time but skip the
2236      ones for the result */
2237   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2238                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2239
2240   ic->regsSaved = 1;
2241   if (options.useXstack)
2242     {
2243       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2244       int nBits = bitVectnBitsOn (rsavebits);
2245       int count = bitVectnBitsOn (rsave);
2246
2247       if (nBits != 0)
2248         {
2249           count = count - nBits + 1;
2250           /* remove all but the first bits as they are pushed all at once */
2251           rsave = bitVectCplAnd (rsave, rsavebits);
2252           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2253         }
2254       freeBitVect (rsavebits);
2255
2256       if (count == 1)
2257         {
2258           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2259           if (reg->type == REG_BIT)
2260             {
2261               emitcode ("mov", "a,%s", reg->base);
2262             }
2263           else
2264             {
2265               emitcode ("mov", "a,%s", reg->name);
2266             }
2267           emitcode ("mov", "r0,%s", spname);
2268           emitcode ("inc", "%s", spname);// allocate before use
2269           emitcode ("movx", "@r0,a");
2270           if (bitVectBitValue (rsave, R0_IDX))
2271             emitcode ("mov", "r0,a");
2272         }
2273       else if (count != 0)
2274         {
2275           if (bitVectBitValue (rsave, R0_IDX))
2276             {
2277               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2278             }
2279           emitcode ("mov", "r0,%s", spname);
2280           MOVA ("r0");
2281           emitcode ("add", "a,#%d", count);
2282           emitcode ("mov", "%s,a", spname);
2283           for (i = 0; i < mcs51_nRegs; i++)
2284             {
2285               if (bitVectBitValue (rsave, i))
2286                 {
2287                   regs * reg = REG_WITH_INDEX (i);
2288                   if (i == R0_IDX)
2289                     {
2290                       emitcode ("pop", "acc");
2291                       emitcode ("push", "acc");
2292                     }
2293                   else if (reg->type == REG_BIT)
2294                     {
2295                       emitcode ("mov", "a,%s", reg->base);
2296                     }
2297                   else
2298                     {
2299                       emitcode ("mov", "a,%s", reg->name);
2300                     }
2301                   emitcode ("movx", "@r0,a");
2302                   if (--count)
2303                     {
2304                       emitcode ("inc", "r0");
2305                     }
2306                 }
2307             }
2308           if (bitVectBitValue (rsave, R0_IDX))
2309             {
2310               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2311             }
2312         }
2313     }
2314   else
2315     {
2316       bool bits_pushed = FALSE;
2317       for (i = 0; i < mcs51_nRegs; i++)
2318         {
2319           if (bitVectBitValue (rsave, i))
2320             {
2321               bits_pushed = pushReg (i, bits_pushed);
2322             }
2323         }
2324     }
2325   freeBitVect (rsave);
2326 }
2327
2328 /*-----------------------------------------------------------------*/
2329 /* unsaveRegisters - pop the pushed registers                      */
2330 /*-----------------------------------------------------------------*/
2331 static void
2332 unsaveRegisters (iCode * ic)
2333 {
2334   int i;
2335   bitVect *rsave;
2336
2337   /* restore the registers in use at this time but skip the
2338      ones for the result */
2339   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2340                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2341
2342   if (options.useXstack)
2343     {
2344       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2345       int nBits = bitVectnBitsOn (rsavebits);
2346       int count = bitVectnBitsOn (rsave);
2347
2348       if (nBits != 0)
2349         {
2350           count = count - nBits + 1;
2351           /* remove all but the first bits as they are popped all at once */
2352           rsave = bitVectCplAnd (rsave, rsavebits);
2353           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2354         }
2355       freeBitVect (rsavebits);
2356
2357       if (count == 1)
2358         {
2359           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2360           emitcode ("mov", "r0,%s", spname);
2361           emitcode ("dec", "r0");
2362           emitcode ("movx", "a,@r0");
2363           if (reg->type == REG_BIT)
2364             {
2365               emitcode ("mov", "%s,a", reg->base);
2366             }
2367           else
2368             {
2369               emitcode ("mov", "%s,a", reg->name);
2370             }
2371           emitcode ("dec", "%s", spname);
2372         }
2373       else if (count != 0)
2374         {
2375           emitcode ("mov", "r0,%s", spname);
2376           for (i = mcs51_nRegs; i >= 0; i--)
2377             {
2378               if (bitVectBitValue (rsave, i))
2379                 {
2380                   regs * reg = REG_WITH_INDEX (i);
2381                   emitcode ("dec", "r0");
2382                   emitcode ("movx", "a,@r0");
2383                   if (i == R0_IDX)
2384                     {
2385                       emitcode ("push", "acc");
2386                     }
2387                   else if (reg->type == REG_BIT)
2388                     {
2389                       emitcode ("mov", "%s,a", reg->base);
2390                     }
2391                   else
2392                     {
2393                       emitcode ("mov", "%s,a", reg->name);
2394                     }
2395                 }
2396             }
2397           emitcode ("mov", "%s,r0", spname);
2398           if (bitVectBitValue (rsave, R0_IDX))
2399             {
2400               emitcode ("pop", "ar0");
2401             }
2402         }
2403     }
2404   else
2405     {
2406       bool bits_popped = FALSE;
2407       for (i = mcs51_nRegs; i >= 0; i--)
2408         {
2409           if (bitVectBitValue (rsave, i))
2410             {
2411               bits_popped = popReg (i, bits_popped);
2412             }
2413         }
2414     }
2415   freeBitVect (rsave);
2416 }
2417
2418
2419 /*-----------------------------------------------------------------*/
2420 /* pushSide -                                                      */
2421 /*-----------------------------------------------------------------*/
2422 static void
2423 pushSide (operand * oper, int size)
2424 {
2425   int offset = 0;
2426   while (size--)
2427     {
2428       char *l = aopGet (oper, offset++, FALSE, TRUE);
2429       if (AOP_TYPE (oper) != AOP_REG &&
2430           AOP_TYPE (oper) != AOP_DIR &&
2431           strcmp (l, "a"))
2432         {
2433           MOVA (l);
2434           emitcode ("push", "acc");
2435         }
2436       else
2437         {
2438           emitcode ("push", "%s", l);
2439         }
2440     }
2441 }
2442
2443 /*-----------------------------------------------------------------*/
2444 /* assignResultValue - also indicates if acc is in use afterwards  */
2445 /*-----------------------------------------------------------------*/
2446 static bool
2447 assignResultValue (operand * oper, operand * func)
2448 {
2449   int offset = 0;
2450   int size = AOP_SIZE (oper);
2451   bool accuse = FALSE;
2452   bool pushedA = FALSE;
2453
2454   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2455     {
2456       outBitC (oper);
2457       return FALSE;
2458     }
2459
2460   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2461     {
2462       emitcode ("push", "acc");
2463       pushedA = TRUE;
2464     }
2465   while (size--)
2466     {
2467       if ((offset == 3) && pushedA)
2468         emitcode ("pop", "acc");
2469       accuse |= aopPut (oper, fReturn[offset], offset);
2470       offset++;
2471     }
2472   return accuse;
2473 }
2474
2475
2476 /*-----------------------------------------------------------------*/
2477 /* genXpush - pushes onto the external stack                       */
2478 /*-----------------------------------------------------------------*/
2479 static void
2480 genXpush (iCode * ic)
2481 {
2482   asmop *aop = newAsmop (0);
2483   regs *r;
2484   int size, offset = 0;
2485
2486   D (emitcode (";", "genXpush"));
2487
2488   aopOp (IC_LEFT (ic), ic, FALSE);
2489   r = getFreePtr (ic, &aop, FALSE);
2490
2491   size = AOP_SIZE (IC_LEFT (ic));
2492
2493   if (size == 1)
2494     {
2495       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2496       emitcode ("mov", "%s,%s", r->name, spname);
2497       emitcode ("inc", "%s", spname); // allocate space first
2498       emitcode ("movx", "@%s,a", r->name);
2499     }
2500   else
2501     {
2502       // allocate space first
2503       emitcode ("mov", "%s,%s", r->name, spname);
2504       MOVA (r->name);
2505       emitcode ("add", "a,#%d", size);
2506       emitcode ("mov", "%s,a", spname);
2507
2508       while (size--)
2509         {
2510           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2511           emitcode ("movx", "@%s,a", r->name);
2512           emitcode ("inc", "%s", r->name);
2513         }
2514     }
2515
2516   freeAsmop (NULL, aop, ic, TRUE);
2517   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2518 }
2519
2520 /*-----------------------------------------------------------------*/
2521 /* genIpush - generate code for pushing this gets a little complex */
2522 /*-----------------------------------------------------------------*/
2523 static void
2524 genIpush (iCode * ic)
2525 {
2526   int size, offset = 0;
2527   char *l;
2528   char *prev = "";
2529
2530   D (emitcode (";", "genIpush"));
2531
2532   /* if this is not a parm push : ie. it is spill push
2533      and spill push is always done on the local stack */
2534   if (!ic->parmPush)
2535     {
2536
2537       /* and the item is spilt then do nothing */
2538       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2539         return;
2540
2541       aopOp (IC_LEFT (ic), ic, FALSE);
2542       size = AOP_SIZE (IC_LEFT (ic));
2543       /* push it on the stack */
2544       while (size--)
2545         {
2546           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2547           if (*l == '#')
2548             {
2549               MOVA (l);
2550               l = "acc";
2551             }
2552           emitcode ("push", "%s", l);
2553         }
2554       return;
2555     }
2556
2557   /* this is a parameter push: in this case we call
2558      the routine to find the call and save those
2559      registers that need to be saved */
2560   saveRegisters (ic);
2561
2562   /* if use external stack then call the external
2563      stack pushing routine */
2564   if (options.useXstack)
2565     {
2566       genXpush (ic);
2567       return;
2568     }
2569
2570   /* then do the push */
2571   aopOp (IC_LEFT (ic), ic, FALSE);
2572
2573   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2574   size = AOP_SIZE (IC_LEFT (ic));
2575
2576   while (size--)
2577     {
2578       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2579       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2580           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2581         {
2582           if (strcmp (l, prev) || *l == '@')
2583             MOVA (l);
2584           emitcode ("push", "acc");
2585         }
2586       else
2587         {
2588           emitcode ("push", "%s", l);
2589         }
2590       prev = l;
2591     }
2592
2593   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2594 }
2595
2596 /*-----------------------------------------------------------------*/
2597 /* genIpop - recover the registers: can happen only for spilling   */
2598 /*-----------------------------------------------------------------*/
2599 static void
2600 genIpop (iCode * ic)
2601 {
2602   int size, offset;
2603
2604   D (emitcode (";", "genIpop"));
2605
2606   /* if the temp was not pushed then */
2607   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2608     return;
2609
2610   aopOp (IC_LEFT (ic), ic, FALSE);
2611   size = AOP_SIZE (IC_LEFT (ic));
2612   offset = (size - 1);
2613   while (size--)
2614     {
2615       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2616                                      FALSE, TRUE));
2617     }
2618
2619   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2620 }
2621
2622 /*-----------------------------------------------------------------*/
2623 /* saveRBank - saves an entire register bank on the stack          */
2624 /*-----------------------------------------------------------------*/
2625 static void
2626 saveRBank (int bank, iCode * ic, bool pushPsw)
2627 {
2628   int i;
2629   int count = 8 + (pushPsw ? 1 : 0);
2630   asmop *aop = NULL;
2631   regs *r = NULL;
2632
2633   if (options.useXstack)
2634     {
2635       if (!ic)
2636         {
2637           /* Assume r0 is available for use. */
2638           r = REG_WITH_INDEX (R0_IDX);
2639         }
2640       else
2641         {
2642           aop = newAsmop (0);
2643           r = getFreePtr (ic, &aop, FALSE);
2644         }
2645       // allocate space first
2646       emitcode ("mov", "%s,%s", r->name, spname);
2647       MOVA (r->name);
2648       emitcode ("add", "a,#%d", count);
2649       emitcode ("mov", "%s,a", spname);
2650     }
2651
2652   for (i = 0; i < 8; i++)
2653     {
2654       if (options.useXstack)
2655         {
2656           emitcode ("mov", "a,(%s+%d)",
2657                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2658           emitcode ("movx", "@%s,a", r->name);
2659           if (--count)
2660             emitcode ("inc", "%s", r->name);
2661         }
2662       else
2663         emitcode ("push", "(%s+%d)",
2664                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2665     }
2666
2667   if (pushPsw)
2668     {
2669       if (options.useXstack)
2670         {
2671           emitcode ("mov", "a,psw");
2672           emitcode ("movx", "@%s,a", r->name);
2673         }
2674       else
2675         {
2676           emitcode ("push", "psw");
2677         }
2678
2679       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2680     }
2681
2682   if (aop)
2683     {
2684       freeAsmop (NULL, aop, ic, TRUE);
2685     }
2686
2687   if (ic)
2688     {
2689       ic->bankSaved = 1;
2690     }
2691 }
2692
2693 /*-----------------------------------------------------------------*/
2694 /* unsaveRBank - restores the register bank from stack             */
2695 /*-----------------------------------------------------------------*/
2696 static void
2697 unsaveRBank (int bank, iCode * ic, bool popPsw)
2698 {
2699   int i;
2700   asmop *aop = NULL;
2701   regs *r = NULL;
2702
2703   if (options.useXstack)
2704     {
2705       if (!ic)
2706         {
2707           /* Assume r0 is available for use. */
2708           r = REG_WITH_INDEX (R0_IDX);;
2709         }
2710       else
2711         {
2712           aop = newAsmop (0);
2713           r = getFreePtr (ic, &aop, FALSE);
2714         }
2715       emitcode ("mov", "%s,%s", r->name, spname);
2716     }
2717
2718   if (popPsw)
2719     {
2720       if (options.useXstack)
2721         {
2722           emitcode ("dec", "%s", r->name);
2723           emitcode ("movx", "a,@%s", r->name);
2724           emitcode ("mov", "psw,a");
2725         }
2726       else
2727         {
2728           emitcode ("pop", "psw");
2729         }
2730     }
2731
2732   for (i = 7; i >= 0; i--)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("dec", "%s", r->name);
2737           emitcode ("movx", "a,@%s", r->name);
2738           emitcode ("mov", "(%s+%d),a",
2739                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2740         }
2741       else
2742         {
2743           emitcode ("pop", "(%s+%d)",
2744                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2745         }
2746     }
2747
2748   if (options.useXstack)
2749     {
2750       emitcode ("mov", "%s,%s", spname, r->name);
2751     }
2752
2753   if (aop)
2754     {
2755       freeAsmop (NULL, aop, ic, TRUE);
2756     }
2757 }
2758
2759 /*-----------------------------------------------------------------*/
2760 /* genSend - gen code for SEND                                     */
2761 /*-----------------------------------------------------------------*/
2762 static void genSend(set *sendSet)
2763 {
2764   iCode *sic;
2765   int bit_count = 0;
2766
2767   /* first we do all bit parameters */
2768   for (sic = setFirstItem (sendSet); sic;
2769        sic = setNextItem (sendSet))
2770     {
2771       if (sic->argreg > 12)
2772         {
2773           int bit = sic->argreg-13;
2774
2775           aopOp (IC_LEFT (sic), sic, FALSE);
2776
2777           /* if left is a literal then
2778              we know what the value is */
2779           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2780             {
2781               if (((int) operandLitValue (IC_LEFT (sic))))
2782                   emitcode ("setb", "b[%d]", bit);
2783               else
2784                   emitcode ("clr", "b[%d]", bit);
2785             }
2786           else
2787             {
2788               /* we need to or */
2789               toCarry (IC_LEFT (sic));
2790               emitcode ("mov", "b[%d],c", bit);
2791             }
2792           bit_count++;
2793           BitBankUsed = 1;
2794
2795           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2796         }
2797     }
2798
2799   if (bit_count)
2800     {
2801       saveRegisters (setFirstItem (sendSet));
2802       emitcode ("mov", "bits,b");
2803     }
2804
2805   /* then we do all other parameters */
2806   for (sic = setFirstItem (sendSet); sic;
2807        sic = setNextItem (sendSet))
2808     {
2809       if (sic->argreg <= 12)
2810         {
2811           int size, offset = 0;
2812           aopOp (IC_LEFT (sic), sic, FALSE);
2813           size = AOP_SIZE (IC_LEFT (sic));
2814
2815           if (sic->argreg == 1)
2816             {
2817               while (size--)
2818                 {
2819                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2820                   if (strcmp (l, fReturn[offset]))
2821                     {
2822                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2823                     }
2824                   offset++;
2825                 }
2826             }
2827           else
2828             {
2829               while (size--)
2830                 {
2831                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2832                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2833                   offset++;
2834                 }
2835             }
2836           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2837         }
2838     }
2839 }
2840
2841 /*-----------------------------------------------------------------*/
2842 /* selectRegBank - emit code to select the register bank           */
2843 /*-----------------------------------------------------------------*/
2844 static void
2845 selectRegBank (short bank, bool keepFlags)
2846 {
2847   /* if f.e. result is in carry */
2848   if (keepFlags)
2849     {
2850       emitcode ("anl", "psw,#0xE7");
2851       if (bank)
2852         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2853     }
2854   else
2855     {
2856       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2857     }
2858 }
2859
2860 /*-----------------------------------------------------------------*/
2861 /* genCall - generates a call statement                            */
2862 /*-----------------------------------------------------------------*/
2863 static void
2864 genCall (iCode * ic)
2865 {
2866   sym_link *dtype;
2867   sym_link *etype;
2868 //  bool restoreBank = FALSE;
2869   bool swapBanks = FALSE;
2870   bool accuse = FALSE;
2871   bool accPushed = FALSE;
2872   bool resultInF0 = FALSE;
2873   bool assignResultGenerated = FALSE;
2874
2875   D (emitcode (";", "genCall"));
2876
2877   dtype = operandType (IC_LEFT (ic));
2878   etype = getSpec(dtype);
2879   /* if send set is not empty then assign */
2880   if (_G.sendSet)
2881     {
2882         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2883             genSend(reverseSet(_G.sendSet));
2884         } else {
2885             genSend(_G.sendSet);
2886         }
2887       _G.sendSet = NULL;
2888     }
2889
2890   /* if we are calling a not _naked function that is not using
2891      the same register bank then we need to save the
2892      destination registers on the stack */
2893   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2894       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2895        !IFFUNC_ISISR (dtype))
2896     {
2897       swapBanks = TRUE;
2898     }
2899
2900   /* if caller saves & we have not saved then */
2901   if (!ic->regsSaved)
2902       saveRegisters (ic);
2903
2904   if (swapBanks)
2905     {
2906         emitcode ("mov", "psw,#0x%02x",
2907            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2908     }
2909
2910   /* make the call */
2911   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2912     {
2913       if (IFFUNC_CALLEESAVES(dtype))
2914         {
2915           werror (E_BANKED_WITH_CALLEESAVES);
2916         }
2917       else
2918         {
2919           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2920                      OP_SYMBOL (IC_LEFT (ic))->rname :
2921                      OP_SYMBOL (IC_LEFT (ic))->name);
2922
2923           emitcode ("mov", "r0,#%s", l);
2924           emitcode ("mov", "r1,#(%s >> 8)", l);
2925           emitcode ("mov", "r2,#(%s >> 16)", l);
2926           emitcode ("lcall", "__sdcc_banked_call");
2927         }
2928     }
2929   else
2930     {
2931       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2932                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2933                                 OP_SYMBOL (IC_LEFT (ic))->name));
2934     }
2935
2936   if (swapBanks)
2937     {
2938       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2939     }
2940
2941   /* if we need assign a result value */
2942   if ((IS_ITEMP (IC_RESULT (ic)) &&
2943        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2944        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2945         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2946         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2947       IS_TRUE_SYMOP (IC_RESULT (ic)))
2948     {
2949
2950       _G.accInUse++;
2951       aopOp (IC_RESULT (ic), ic, FALSE);
2952       _G.accInUse--;
2953
2954       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2955       assignResultGenerated = TRUE;
2956
2957       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2958     }
2959
2960   /* adjust the stack for parameters if required */
2961   if (ic->parmBytes)
2962     {
2963       int i;
2964       if (ic->parmBytes > 3)
2965         {
2966           if (accuse)
2967             {
2968               emitcode ("push", "acc");
2969               accPushed = TRUE;
2970             }
2971           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2972               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2973               !assignResultGenerated)
2974             {
2975               emitcode ("mov", "F0,c");
2976               resultInF0 = TRUE;
2977             }
2978
2979           emitcode ("mov", "a,%s", spname);
2980           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2981           emitcode ("mov", "%s,a", spname);
2982
2983           /* unsaveRegisters from xstack needs acc, but */
2984           /* unsaveRegisters from stack needs this popped */
2985           if (accPushed && !options.useXstack)
2986             {
2987               emitcode ("pop", "acc");
2988               accPushed = FALSE;
2989             }
2990         }
2991       else
2992         for (i = 0; i < ic->parmBytes; i++)
2993           emitcode ("dec", "%s", spname);
2994     }
2995
2996   /* if we had saved some registers then unsave them */
2997   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2998     {
2999       if (accuse && !accPushed && options.useXstack)
3000         {
3001           /* xstack needs acc, but doesn't touch normal stack */
3002           emitcode ("push", "acc");
3003           accPushed = TRUE;
3004         }
3005       unsaveRegisters (ic);
3006     }
3007
3008 //  /* if register bank was saved then pop them */
3009 //  if (restoreBank)
3010 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3011
3012   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3013     {
3014       if (resultInF0)
3015           emitcode ("mov", "c,F0");
3016
3017       aopOp (IC_RESULT (ic), ic, FALSE);
3018       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3019       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3020     }
3021
3022   if (accPushed)
3023     emitcode ("pop", "acc");
3024 }
3025
3026 /*-----------------------------------------------------------------*/
3027 /* genPcall - generates a call by pointer statement                */
3028 /*-----------------------------------------------------------------*/
3029 static void
3030 genPcall (iCode * ic)
3031 {
3032   sym_link *dtype;
3033   sym_link *etype;
3034   symbol *rlbl = newiTempLabel (NULL);
3035 //  bool restoreBank=FALSE;
3036   bool swapBanks = FALSE;
3037   bool resultInF0 = FALSE;
3038
3039   D (emitcode (";", "genPcall"));
3040
3041   dtype = operandType (IC_LEFT (ic))->next;
3042   etype = getSpec(dtype);
3043   /* if caller saves & we have not saved then */
3044   if (!ic->regsSaved)
3045     saveRegisters (ic);
3046
3047   /* if we are calling a not _naked function that is not using
3048      the same register bank then we need to save the
3049      destination registers on the stack */
3050   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3051       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3052       !IFFUNC_ISISR (dtype))
3053     {
3054 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3055 //    restoreBank=TRUE;
3056       swapBanks = TRUE;
3057       // need caution message to user here
3058     }
3059
3060   if (IS_LITERAL (etype))
3061     {
3062       /* if send set is not empty then assign */
3063       if (_G.sendSet)
3064         {
3065           genSend(reverseSet(_G.sendSet));
3066           _G.sendSet = NULL;
3067         }
3068
3069       if (swapBanks)
3070         {
3071           emitcode ("mov", "psw,#0x%02x",
3072            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3073         }
3074
3075       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3076         {
3077           if (IFFUNC_CALLEESAVES (dtype))
3078             {
3079               werror (E_BANKED_WITH_CALLEESAVES);
3080             }
3081           else
3082             {
3083               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3084
3085               emitcode ("mov", "r0,#%s", l);
3086               emitcode ("mov", "r1,#(%s >> 8)", l);
3087               emitcode ("mov", "r2,#(%s >> 16)", l);
3088               emitcode ("lcall", "__sdcc_banked_call");
3089             }
3090         }
3091       else
3092         {
3093           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3094         }
3095     }
3096   else
3097     {
3098       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3099         {
3100           if (IFFUNC_CALLEESAVES (dtype))
3101             {
3102               werror (E_BANKED_WITH_CALLEESAVES);
3103             }
3104           else
3105             {
3106               aopOp (IC_LEFT (ic), ic, FALSE);
3107
3108               if (!swapBanks)
3109                 {
3110                   /* what if aopGet needs r0 or r1 ??? */
3111                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3112                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3113                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3114                 }
3115               else
3116                 {
3117                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3118                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3119                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3120                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3121                 }
3122
3123               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3124
3125               /* if send set is not empty then assign */
3126               if (_G.sendSet)
3127                 {
3128                   genSend(reverseSet(_G.sendSet));
3129                   _G.sendSet = NULL;
3130                 }
3131
3132               if (swapBanks)
3133                 {
3134                   emitcode ("mov", "psw,#0x%02x",
3135                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3136                 }
3137
3138               /* make the call */
3139               emitcode ("lcall", "__sdcc_banked_call");
3140             }
3141         }
3142       else if (_G.sendSet)
3143         {
3144           /* push the return address on to the stack */
3145           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3148           emitcode ("push", "acc");
3149
3150           /* now push the calling address */
3151           aopOp (IC_LEFT (ic), ic, FALSE);
3152
3153           pushSide (IC_LEFT (ic), FPTRSIZE);
3154
3155           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3156
3157           /* if send set is not empty the assign */
3158           if (_G.sendSet)
3159             {
3160               genSend(reverseSet(_G.sendSet));
3161               _G.sendSet = NULL;
3162             }
3163
3164           if (swapBanks)
3165             {
3166               emitcode ("mov", "psw,#0x%02x",
3167                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3168             }
3169
3170           /* make the call */
3171           emitcode ("ret", "");
3172           emitLabel (rlbl);
3173         }
3174       else /* the send set is empty */
3175         {
3176           char *l;
3177           /* now get the calling address into dptr */
3178           aopOp (IC_LEFT (ic), ic, FALSE);
3179
3180           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3181           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3182             {
3183               emitcode ("mov", "r0,%s", l);
3184               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3185               emitcode ("mov", "dph,%s", l);
3186               emitcode ("mov", "dpl,r0");
3187             }
3188           else
3189             {
3190               emitcode ("mov", "dpl,%s", l);
3191               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3192               emitcode ("mov", "dph,%s", l);
3193             }
3194
3195           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3196
3197           if (swapBanks)
3198             {
3199               emitcode ("mov", "psw,#0x%02x",
3200                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3201             }
3202
3203           /* make the call */
3204           emitcode ("lcall", "__sdcc_call_dptr");
3205         }
3206     }
3207   if (swapBanks)
3208     {
3209       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3210     }
3211
3212   /* if we need assign a result value */
3213   if ((IS_ITEMP (IC_RESULT (ic)) &&
3214        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3215        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3216         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3217       IS_TRUE_SYMOP (IC_RESULT (ic)))
3218     {
3219
3220       _G.accInUse++;
3221       aopOp (IC_RESULT (ic), ic, FALSE);
3222       _G.accInUse--;
3223
3224       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3225
3226       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3227     }
3228
3229   /* adjust the stack for parameters if required */
3230   if (ic->parmBytes)
3231     {
3232       int i;
3233       if (ic->parmBytes > 3)
3234         {
3235           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3236               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3237             {
3238               emitcode ("mov", "F0,c");
3239               resultInF0 = TRUE;
3240             }
3241
3242           emitcode ("mov", "a,%s", spname);
3243           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3244           emitcode ("mov", "%s,a", spname);
3245         }
3246       else
3247         for (i = 0; i < ic->parmBytes; i++)
3248           emitcode ("dec", "%s", spname);
3249     }
3250
3251 //  /* if register bank was saved then unsave them */
3252 //  if (restoreBank)
3253 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3254
3255   /* if we had saved some registers then unsave them */
3256   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3257     unsaveRegisters (ic);
3258
3259   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3260     {
3261       if (resultInF0)
3262           emitcode ("mov", "c,F0");
3263
3264       aopOp (IC_RESULT (ic), ic, FALSE);
3265       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3266       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3267     }
3268 }
3269
3270 /*-----------------------------------------------------------------*/
3271 /* resultRemat - result  is rematerializable                       */
3272 /*-----------------------------------------------------------------*/
3273 static int
3274 resultRemat (iCode * ic)
3275 {
3276   if (SKIP_IC (ic) || ic->op == IFX)
3277     return 0;
3278
3279   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3280     {
3281       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3282       if (sym->remat && !POINTER_SET (ic))
3283         return 1;
3284     }
3285
3286   return 0;
3287 }
3288
3289 /*-----------------------------------------------------------------*/
3290 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3291 /*-----------------------------------------------------------------*/
3292 static int
3293 regsCmp(void *p1, void *p2)
3294 {
3295   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3296 }
3297
3298 static bool
3299 inExcludeList (char *s)
3300 {
3301   const char *p = setFirstItem(options.excludeRegsSet);
3302
3303   if (p == NULL || STRCASECMP(p, "none") == 0)
3304     return FALSE;
3305
3306
3307   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3308 }
3309
3310 /*-----------------------------------------------------------------*/
3311 /* genFunction - generated code for function entry                 */
3312 /*-----------------------------------------------------------------*/
3313 static void
3314 genFunction (iCode * ic)
3315 {
3316   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3317   sym_link *ftype;
3318   bool     switchedPSW = FALSE;
3319   int      calleesaves_saved_register = -1;
3320   int      stackAdjust = sym->stack;
3321   int      accIsFree = sym->recvSize < 4;
3322   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3323   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3324
3325   _G.nRegsSaved = 0;
3326   /* create the function header */
3327   emitcode (";", "-----------------------------------------");
3328   emitcode (";", " function %s", sym->name);
3329   emitcode (";", "-----------------------------------------");
3330
3331   emitcode ("", "%s:", sym->rname);
3332   lineCurr->isLabel = 1;
3333   ftype = operandType (IC_LEFT (ic));
3334   _G.currentFunc = sym;
3335
3336   if (IFFUNC_ISNAKED(ftype))
3337   {
3338       emitcode(";", "naked function: no prologue.");
3339       return;
3340   }
3341
3342   /* here we need to generate the equates for the
3343      register bank if required */
3344   if (FUNC_REGBANK (ftype) != rbank)
3345     {
3346       int i;
3347
3348       rbank = FUNC_REGBANK (ftype);
3349       for (i = 0; i < mcs51_nRegs; i++)
3350         {
3351           if (regs8051[i].type != REG_BIT)
3352             {
3353               if (strcmp (regs8051[i].base, "0") == 0)
3354                 emitcode ("", "%s = 0x%02x",
3355                           regs8051[i].dname,
3356                           8 * rbank + regs8051[i].offset);
3357               else
3358                 emitcode ("", "%s = %s + 0x%02x",
3359                           regs8051[i].dname,
3360                           regs8051[i].base,
3361                           8 * rbank + regs8051[i].offset);
3362             }
3363         }
3364     }
3365
3366   /* if this is an interrupt service routine then
3367      save acc, b, dpl, dph  */
3368   if (IFFUNC_ISISR (sym->type))
3369     {
3370       bitVect *rsavebits;
3371
3372       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3373       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3374         {
3375           emitcode ("push", "bits");
3376           BitBankUsed = 1;
3377         }
3378       freeBitVect (rsavebits);
3379
3380       if (!inExcludeList ("acc"))
3381         emitcode ("push", "acc");
3382       if (!inExcludeList ("b"))
3383         emitcode ("push", "b");
3384       if (!inExcludeList ("dpl"))
3385         emitcode ("push", "dpl");
3386       if (!inExcludeList ("dph"))
3387         emitcode ("push", "dph");
3388       /* if this isr has no bank i.e. is going to
3389          run with bank 0 , then we need to save more
3390          registers :-) */
3391       if (!FUNC_REGBANK (sym->type))
3392         {
3393           int i;
3394
3395           /* if this function does not call any other
3396              function then we can be economical and
3397              save only those registers that are used */
3398           if (!IFFUNC_HASFCALL(sym->type))
3399             {
3400               /* if any registers used */
3401               if (sym->regsUsed)
3402                 {
3403                   /* save the registers used */
3404                   for (i = 0; i < sym->regsUsed->size; i++)
3405                     {
3406                       if (bitVectBitValue (sym->regsUsed, i))
3407                         pushReg (i, TRUE);
3408                     }
3409                 }
3410             }
3411           else
3412             {
3413               /* this function has a function call. We cannot
3414                  determine register usage so we will have to push the
3415                  entire bank */
3416                 saveRBank (0, ic, FALSE);
3417                 if (options.parms_in_bank1) {
3418                     for (i=0; i < 8 ; i++ ) {
3419                         emitcode ("push","%s",rb1regs[i]);
3420                     }
3421                 }
3422             }
3423         }
3424       else
3425         {
3426             /* This ISR uses a non-zero bank.
3427              *
3428              * We assume that the bank is available for our
3429              * exclusive use.
3430              *
3431              * However, if this ISR calls a function which uses some
3432              * other bank, we must save that bank entirely.
3433              */
3434             unsigned long banksToSave = 0;
3435
3436             if (IFFUNC_HASFCALL(sym->type))
3437             {
3438
3439 #define MAX_REGISTER_BANKS 4
3440
3441                 iCode *i;
3442                 int ix;
3443
3444                 for (i = ic; i; i = i->next)
3445                 {
3446                     if (i->op == ENDFUNCTION)
3447                     {
3448                         /* we got to the end OK. */
3449                         break;
3450                     }
3451
3452                     if (i->op == CALL)
3453                     {
3454                         sym_link *dtype;
3455
3456                         dtype = operandType (IC_LEFT(i));
3457                         if (dtype
3458                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3459                         {
3460                              /* Mark this bank for saving. */
3461                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3462                              {
3463                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3464                              }
3465                              else
3466                              {
3467                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3468                              }
3469
3470                              /* And note that we don't need to do it in
3471                               * genCall.
3472                               */
3473                              i->bankSaved = 1;
3474                         }
3475                     }
3476                     if (i->op == PCALL)
3477                     {
3478                         /* This is a mess; we have no idea what
3479                          * register bank the called function might
3480                          * use.
3481                          *
3482                          * The only thing I can think of to do is
3483                          * throw a warning and hope.
3484                          */
3485                         werror(W_FUNCPTR_IN_USING_ISR);
3486                     }
3487                 }
3488
3489                 if (banksToSave && options.useXstack)
3490                 {
3491                     /* Since we aren't passing it an ic,
3492                      * saveRBank will assume r0 is available to abuse.
3493                      *
3494                      * So switch to our (trashable) bank now, so
3495                      * the caller's R0 isn't trashed.
3496                      */
3497                     emitcode ("push", "psw");
3498                     emitcode ("mov", "psw,#0x%02x",
3499                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3500                     switchedPSW = TRUE;
3501                 }
3502
3503                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3504                 {
3505                      if (banksToSave & (1 << ix))
3506                      {
3507                          saveRBank(ix, NULL, FALSE);
3508                      }
3509                 }
3510             }
3511             // TODO: this needs a closer look
3512             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3513         }
3514
3515       /* Set the register bank to the desired value if nothing else */
3516       /* has done so yet. */
3517       if (!switchedPSW)
3518         {
3519           emitcode ("push", "psw");
3520           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3521         }
3522     }
3523   else
3524     {
3525       /* This is a non-ISR function. The caller has already switched register */
3526       /* banks, if necessary, so just handle the callee-saves option. */
3527
3528       /* if callee-save to be used for this function
3529          then save the registers being used in this function */
3530       if (IFFUNC_CALLEESAVES(sym->type))
3531         {
3532           int i;
3533
3534           /* if any registers used */
3535           if (sym->regsUsed)
3536             {
3537               bool bits_pushed = FALSE;
3538               /* save the registers used */
3539               for (i = 0; i < sym->regsUsed->size; i++)
3540                 {
3541                   if (bitVectBitValue (sym->regsUsed, i))
3542                     {
3543                       /* remember one saved register for later usage */
3544                       if (calleesaves_saved_register < 0)
3545                         calleesaves_saved_register = i;
3546                       bits_pushed = pushReg (i, bits_pushed);
3547                       _G.nRegsSaved++;
3548                     }
3549                 }
3550             }
3551         }
3552     }
3553
3554   if (fReentrant)
3555     {
3556       if (options.useXstack)
3557         {
3558           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3559             {
3560               emitcode ("mov", "r0,%s", spname);
3561               emitcode ("inc", "%s", spname);
3562               emitcode ("xch", "a,_bpx");
3563               emitcode ("movx", "@r0,a");
3564               emitcode ("inc", "r0");
3565               emitcode ("mov", "a,r0");
3566               emitcode ("xch", "a,_bpx");
3567             }
3568           if (sym->stack)
3569             {
3570               emitcode ("push", "_bp");     /* save the callers stack  */
3571               emitcode ("mov", "_bp,sp");
3572             }
3573         }
3574       else
3575         {
3576           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3577             {
3578               /* set up the stack */
3579               emitcode ("push", "_bp");     /* save the callers stack  */
3580               emitcode ("mov", "_bp,sp");
3581             }
3582         }
3583     }
3584
3585   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3586   /* before setting up the stack frame completely. */
3587   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3588     {
3589       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3590
3591       if (rsym->isitmp)
3592         {
3593           if (rsym && rsym->regType == REG_CND)
3594             rsym = NULL;
3595           if (rsym && (rsym->accuse || rsym->ruonly))
3596             rsym = NULL;
3597           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3598             rsym = rsym->usl.spillLoc;
3599         }
3600
3601       /* If the RECEIVE operand immediately spills to the first entry on the */
3602       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3603       /* rather than the usual @r0/r1 machinations. */
3604       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3605         {
3606           int ofs;
3607
3608           _G.current_iCode = ric;
3609           D(emitcode (";", "genReceive"));
3610           for (ofs=0; ofs < sym->recvSize; ofs++)
3611             {
3612               if (!strcmp (fReturn[ofs], "a"))
3613                 emitcode ("push", "acc");
3614               else
3615                 emitcode ("push", fReturn[ofs]);
3616             }
3617           stackAdjust -= sym->recvSize;
3618           if (stackAdjust<0)
3619             {
3620               assert (stackAdjust>=0);
3621               stackAdjust = 0;
3622             }
3623           _G.current_iCode = ic;
3624           ric->generated = 1;
3625           accIsFree = 1;
3626         }
3627       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3628       /* to free up the accumulator. */
3629       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3630         {
3631           int ofs;
3632
3633           _G.current_iCode = ric;
3634           D(emitcode (";", "genReceive"));
3635           for (ofs=0; ofs < sym->recvSize; ofs++)
3636             {
3637               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3638             }
3639           _G.current_iCode = ic;
3640           ric->generated = 1;
3641           accIsFree = 1;
3642         }
3643     }
3644
3645   /* adjust the stack for the function */
3646   if (stackAdjust)
3647     {
3648       int i = stackAdjust;
3649       if (i > 256)
3650         werror (W_STACK_OVERFLOW, sym->name);
3651
3652       if (i > 3 && accIsFree)
3653         {
3654           emitcode ("mov", "a,sp");
3655           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3656           emitcode ("mov", "sp,a");
3657         }
3658       else if (i > 5)
3659         {
3660           /* The accumulator is not free, so we will need another register */
3661           /* to clobber. No need to worry about a possible conflict with */
3662           /* the above early RECEIVE optimizations since they would have */
3663           /* freed the accumulator if they were generated. */
3664
3665           if (IFFUNC_CALLEESAVES(sym->type))
3666             {
3667               /* if it's a callee-saves function we need a saved register */
3668               if (calleesaves_saved_register >= 0)
3669                 {
3670                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3671                   emitcode ("mov", "a,sp");
3672                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3673                   emitcode ("mov", "sp,a");
3674                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3675                 }
3676               else
3677                 /* do it the hard way */
3678                 while (i--)
3679                   emitcode ("inc", "sp");
3680             }
3681           else
3682             {
3683               /* not callee-saves, we can clobber r0 */
3684               emitcode ("mov", "r0,a");
3685               emitcode ("mov", "a,sp");
3686               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3687               emitcode ("mov", "sp,a");
3688               emitcode ("mov", "a,r0");
3689             }
3690         }
3691       else
3692         while (i--)
3693           emitcode ("inc", "sp");
3694     }
3695
3696   if (sym->xstack)
3697     {
3698       char i = ((char) sym->xstack & 0xff);
3699
3700       if (i > 3 && accIsFree)
3701         {
3702           emitcode ("mov", "a,_spx");
3703           emitcode ("add", "a,#0x%02x", i & 0xff);
3704           emitcode ("mov", "_spx,a");
3705         }
3706       else if (i > 5)
3707         {
3708           emitcode ("push", "acc");
3709           emitcode ("mov", "a,_spx");
3710           emitcode ("add", "a,#0x%02x", i & 0xff);
3711           emitcode ("mov", "_spx,a");
3712           emitcode ("pop", "acc");
3713         }
3714       else
3715         {
3716           while (i--)
3717             emitcode ("inc", "_spx");
3718         }
3719     }
3720
3721   /* if critical function then turn interrupts off */
3722   if (IFFUNC_ISCRITICAL (ftype))
3723     {
3724       symbol *tlbl = newiTempLabel (NULL);
3725       emitcode ("setb", "c");
3726       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3727       emitcode ("clr", "c");
3728       emitLabel (tlbl);
3729       emitcode ("push", "psw"); /* save old ea via c in psw */
3730     }
3731 }
3732
3733 /*-----------------------------------------------------------------*/
3734 /* genEndFunction - generates epilogue for functions               */
3735 /*-----------------------------------------------------------------*/
3736 static void
3737 genEndFunction (iCode * ic)
3738 {
3739   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3740   lineNode *lnp = lineCurr;
3741   bitVect  *regsUsed;
3742   bitVect  *regsUsedPrologue;
3743   bitVect  *regsUnneeded;
3744   int      idx;
3745
3746   _G.currentFunc = NULL;
3747   if (IFFUNC_ISNAKED(sym->type))
3748   {
3749       emitcode(";", "naked function: no epilogue.");
3750       if (options.debug && currFunc)
3751         debugFile->writeEndFunction (currFunc, ic, 0);
3752       return;
3753   }
3754
3755   if (IFFUNC_ISCRITICAL (sym->type))
3756     {
3757       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3758         {
3759           emitcode ("rlc", "a");   /* save c in a */
3760           emitcode ("pop", "psw"); /* restore ea via c in psw */
3761           emitcode ("mov", "ea,c");
3762           emitcode ("rrc", "a");   /* restore c from a */
3763         }
3764       else
3765         {
3766           emitcode ("pop", "psw"); /* restore ea via c in psw */
3767           emitcode ("mov", "ea,c");
3768         }
3769     }
3770
3771   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3772     {
3773       if (options.useXstack)
3774         {
3775           if (sym->stack)
3776             {
3777               emitcode ("mov", "sp,_bp");
3778               emitcode ("pop", "_bp");
3779             }
3780           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3781             {
3782               emitcode ("xch", "a,_bpx");
3783               emitcode ("mov", "r0,a");
3784               emitcode ("dec", "r0");
3785               emitcode ("movx", "a,@r0");
3786               emitcode ("xch", "a,_bpx");
3787               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3788             }
3789         }
3790       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3791         {
3792           if (sym->stack)
3793             emitcode ("mov", "sp,_bp");
3794           emitcode ("pop", "_bp");
3795         }
3796     }
3797
3798   /* restore the register bank  */
3799   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3800   {
3801     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3802      || !options.useXstack)
3803     {
3804         /* Special case of ISR using non-zero bank with useXstack
3805          * is handled below.
3806          */
3807         emitcode ("pop", "psw");
3808     }
3809   }
3810
3811   if (IFFUNC_ISISR (sym->type))
3812     {
3813       bitVect *rsavebits;
3814
3815       /* now we need to restore the registers */
3816       /* if this isr has no bank i.e. is going to
3817          run with bank 0 , then we need to save more
3818          registers :-) */
3819       if (!FUNC_REGBANK (sym->type))
3820         {
3821           int i;
3822           /* if this function does not call any other
3823              function then we can be economical and
3824              save only those registers that are used */
3825           if (!IFFUNC_HASFCALL(sym->type))
3826             {
3827               /* if any registers used */
3828               if (sym->regsUsed)
3829                 {
3830                   /* save the registers used */
3831                   for (i = sym->regsUsed->size; i >= 0; i--)
3832                     {
3833                       if (bitVectBitValue (sym->regsUsed, i))
3834                         popReg (i, TRUE);
3835                     }
3836                 }
3837             }
3838           else
3839             {
3840               if (options.parms_in_bank1) {
3841                   for (i = 7 ; i >= 0 ; i-- ) {
3842                       emitcode ("pop","%s",rb1regs[i]);
3843                   }
3844               }
3845               /* this function has a function call. We cannot
3846                  determine register usage so we will have to pop the
3847                  entire bank */
3848               unsaveRBank (0, ic, FALSE);
3849             }
3850         }
3851         else
3852         {
3853             /* This ISR uses a non-zero bank.
3854              *
3855              * Restore any register banks saved by genFunction
3856              * in reverse order.
3857              */
3858             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3859             int ix;
3860
3861             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3862             {
3863                 if (savedBanks & (1 << ix))
3864                 {
3865                     unsaveRBank(ix, NULL, FALSE);
3866                 }
3867             }
3868
3869             if (options.useXstack)
3870             {
3871                 /* Restore bank AFTER calling unsaveRBank,
3872                  * since it can trash r0.
3873                  */
3874                 emitcode ("pop", "psw");
3875             }
3876         }
3877
3878       if (!inExcludeList ("dph"))
3879         emitcode ("pop", "dph");
3880       if (!inExcludeList ("dpl"))
3881         emitcode ("pop", "dpl");
3882       if (!inExcludeList ("b"))
3883         emitcode ("pop", "b");
3884       if (!inExcludeList ("acc"))
3885         emitcode ("pop", "acc");
3886
3887       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3888       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3889         emitcode ("pop", "bits");
3890       freeBitVect (rsavebits);
3891
3892       /* if debug then send end of function */
3893       if (options.debug && currFunc)
3894         {
3895           debugFile->writeEndFunction (currFunc, ic, 1);
3896         }
3897
3898       emitcode ("reti", "");
3899     }
3900   else
3901     {
3902       if (IFFUNC_CALLEESAVES(sym->type))
3903         {
3904           int i;
3905
3906           /* if any registers used */
3907           if (sym->regsUsed)
3908             {
3909               /* save the registers used */
3910               for (i = sym->regsUsed->size; i >= 0; i--)
3911                 {
3912                   if (bitVectBitValue (sym->regsUsed, i) ||
3913                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3914                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3915                 }
3916             }
3917           else if (mcs51_ptrRegReq)
3918             {
3919               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3920               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3921             }
3922
3923         }
3924
3925       /* if debug then send end of function */
3926       if (options.debug && currFunc)
3927         {
3928           debugFile->writeEndFunction (currFunc, ic, 1);
3929         }
3930
3931       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3932         {
3933           emitcode ("ljmp", "__sdcc_banked_ret");
3934         }
3935       else
3936         {
3937           emitcode ("ret", "");
3938         }
3939     }
3940
3941   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3942     return;
3943
3944   /* If this was an interrupt handler using bank 0 that called another */
3945   /* function, then all registers must be saved; nothing to optimized. */
3946   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3947       && !FUNC_REGBANK(sym->type))
3948     return;
3949
3950   /* There are no push/pops to optimize if not callee-saves or ISR */
3951   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3952     return;
3953
3954   /* If there were stack parameters, we cannot optimize without also    */
3955   /* fixing all of the stack offsets; this is too dificult to consider. */
3956   if (FUNC_HASSTACKPARM(sym->type))
3957     return;
3958
3959   /* Compute the registers actually used */
3960   regsUsed = newBitVect (mcs51_nRegs);
3961   regsUsedPrologue = newBitVect (mcs51_nRegs);
3962   while (lnp)
3963     {
3964       if (lnp->ic && lnp->ic->op == FUNCTION)
3965         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3966       else
3967         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3968
3969       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3970           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3971         break;
3972       if (!lnp->prev)
3973         break;
3974       lnp = lnp->prev;
3975     }
3976
3977   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3978       && !bitVectBitValue (regsUsed, CND_IDX))
3979     {
3980       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3981       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3982           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3983         bitVectUnSetBit (regsUsed, CND_IDX);
3984     }
3985   else
3986     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3987
3988   /* If this was an interrupt handler that called another function */
3989   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3990   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3991     {
3992       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3997     }
3998
3999   /* Remove the unneeded push/pops */
4000   regsUnneeded = newBitVect (mcs51_nRegs);
4001   while (lnp)
4002     {
4003       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4004         {
4005           if (!strncmp(lnp->line, "push", 4))
4006             {
4007               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4008               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4009                 {
4010                   connectLine (lnp->prev, lnp->next);
4011                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4012                 }
4013             }
4014           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4015             {
4016               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4017               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4018                 {
4019                   connectLine (lnp->prev, lnp->next);
4020                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4021                 }
4022             }
4023         }
4024       lnp = lnp->next;
4025     }
4026
4027   for (idx = 0; idx < regsUnneeded->size; idx++)
4028     if (bitVectBitValue (regsUnneeded, idx))
4029       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4030
4031   freeBitVect (regsUnneeded);
4032   freeBitVect (regsUsed);
4033   freeBitVect (regsUsedPrologue);
4034 }
4035
4036 /*-----------------------------------------------------------------*/
4037 /* genRet - generate code for return statement                     */
4038 /*-----------------------------------------------------------------*/
4039 static void
4040 genRet (iCode * ic)
4041 {
4042   int size, offset = 0, pushed = 0;
4043
4044   D (emitcode (";", "genRet"));
4045
4046   /* if we have no return value then
4047      just generate the "ret" */
4048   if (!IC_LEFT (ic))
4049     goto jumpret;
4050
4051   /* we have something to return then
4052      move the return value into place */
4053   aopOp (IC_LEFT (ic), ic, FALSE);
4054   size = AOP_SIZE (IC_LEFT (ic));
4055
4056   if (IS_BIT(_G.currentFunc->etype))
4057     {
4058       if (!(IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->ruonly))
4059         toCarry (IC_LEFT (ic));
4060     }
4061   else
4062     {
4063       while (size--)
4064         {
4065           char *l;
4066           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4067             {
4068               /* #NOCHANGE */
4069               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4070               emitcode ("push", "%s", l);
4071               pushed++;
4072             }
4073           else
4074             {
4075               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4076               if (strcmp (fReturn[offset], l))
4077                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4078             }
4079         }
4080
4081       while (pushed)
4082         {
4083           pushed--;
4084           if (strcmp (fReturn[pushed], "a"))
4085             emitcode ("pop", fReturn[pushed]);
4086           else
4087             emitcode ("pop", "acc");
4088         }
4089     }
4090   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4091
4092 jumpret:
4093   /* generate a jump to the return label
4094      if the next is not the return statement */
4095   if (!(ic->next && ic->next->op == LABEL &&
4096         IC_LABEL (ic->next) == returnLabel))
4097
4098     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4099
4100 }
4101
4102 /*-----------------------------------------------------------------*/
4103 /* genLabel - generates a label                                    */
4104 /*-----------------------------------------------------------------*/
4105 static void
4106 genLabel (iCode * ic)
4107 {
4108   /* special case never generate */
4109   if (IC_LABEL (ic) == entryLabel)
4110     return;
4111
4112   emitLabel (IC_LABEL (ic));
4113 }
4114
4115 /*-----------------------------------------------------------------*/
4116 /* genGoto - generates a ljmp                                      */
4117 /*-----------------------------------------------------------------*/
4118 static void
4119 genGoto (iCode * ic)
4120 {
4121   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4122 }
4123
4124 /*-----------------------------------------------------------------*/
4125 /* findLabelBackwards: walks back through the iCode chain looking  */
4126 /* for the given label. Returns number of iCode instructions     */
4127 /* between that label and given ic.          */
4128 /* Returns zero if label not found.          */
4129 /*-----------------------------------------------------------------*/
4130 static int
4131 findLabelBackwards (iCode * ic, int key)
4132 {
4133   int count = 0;
4134
4135   while (ic->prev)
4136     {
4137       ic = ic->prev;
4138       count++;
4139
4140       /* If we have any pushes or pops, we cannot predict the distance.
4141          I don't like this at all, this should be dealt with in the
4142          back-end */
4143       if (ic->op == IPUSH || ic->op == IPOP) {
4144         return 0;
4145       }
4146
4147       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4148         {
4149           return count;
4150         }
4151     }
4152
4153   return 0;
4154 }
4155
4156 /*-----------------------------------------------------------------*/
4157 /* genPlusIncr :- does addition with increment if possible         */
4158 /*-----------------------------------------------------------------*/
4159 static bool
4160 genPlusIncr (iCode * ic)
4161 {
4162   unsigned int icount;
4163   unsigned int size = getDataSize (IC_RESULT (ic));
4164
4165   /* will try to generate an increment */
4166   /* if the right side is not a literal
4167      we cannot */
4168   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4169     return FALSE;
4170
4171   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4172
4173   D(emitcode (";","genPlusIncr"));
4174
4175   /* if increment >=16 bits in register or direct space */
4176   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4177         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4178         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4179       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4180       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4181       (size > 1) &&
4182       (icount == 1))
4183     {
4184       symbol *tlbl;
4185       int emitTlbl;
4186       int labelRange;
4187
4188       /* If the next instruction is a goto and the goto target
4189        * is < 10 instructions previous to this, we can generate
4190        * jumps straight to that target.
4191        */
4192       if (ic->next && ic->next->op == GOTO
4193           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4194           && labelRange <= 10)
4195         {
4196           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4197           tlbl = IC_LABEL (ic->next);
4198           emitTlbl = 0;
4199         }
4200       else
4201         {
4202           tlbl = newiTempLabel (NULL);
4203           emitTlbl = 1;
4204         }
4205       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4206       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4207           IS_AOP_PREG (IC_RESULT (ic)))
4208         emitcode ("cjne", "%s,#0x00,%05d$",
4209                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4210                   tlbl->key + 100);
4211       else
4212         {
4213           emitcode ("clr", "a");
4214           emitcode ("cjne", "a,%s,%05d$",
4215                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4216                     tlbl->key + 100);
4217         }
4218
4219       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4220       if (size > 2)
4221         {
4222           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4223               IS_AOP_PREG (IC_RESULT (ic)))
4224             emitcode ("cjne", "%s,#0x00,%05d$",
4225                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4226                       tlbl->key + 100);
4227           else
4228             emitcode ("cjne", "a,%s,%05d$",
4229                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4230                       tlbl->key + 100);
4231
4232           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4233         }
4234       if (size > 3)
4235         {
4236           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4237               IS_AOP_PREG (IC_RESULT (ic)))
4238             emitcode ("cjne", "%s,#0x00,%05d$",
4239                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4240                       tlbl->key + 100);
4241           else
4242             {
4243               emitcode ("cjne", "a,%s,%05d$",
4244                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4245                         tlbl->key + 100);
4246             }
4247           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4248         }
4249
4250       if (emitTlbl)
4251         {
4252           emitLabel (tlbl);
4253         }
4254       return TRUE;
4255     }
4256
4257   /* if result is dptr */
4258   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4259       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4260       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4261       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4262     {
4263       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4264         return FALSE;
4265
4266       if (icount > 9)
4267         return FALSE;
4268
4269       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4270         return FALSE;
4271
4272       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4273       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4274       while (icount--)
4275         emitcode ("inc", "dptr");
4276
4277       return TRUE;
4278     }
4279
4280   /* if the literal value of the right hand side
4281      is greater than 4 then it is not worth it */
4282   if (icount > 4)
4283     return FALSE;
4284
4285   /* if the sizes are greater than 1 then we cannot */
4286   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4287       AOP_SIZE (IC_LEFT (ic)) > 1)
4288     return FALSE;
4289
4290   /* we can if the aops of the left & result match or
4291      if they are in registers and the registers are the
4292      same */
4293   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4294     {
4295       if (icount > 3)
4296         {
4297           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4298           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4299           aopPut (IC_RESULT (ic), "a", 0);
4300         }
4301       else
4302         {
4303           while (icount--)
4304             {
4305               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4306             }
4307         }
4308
4309       return TRUE;
4310     }
4311
4312   if (icount == 1)
4313     {
4314       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4315       emitcode ("inc", "a");
4316       aopPut (IC_RESULT (ic), "a", 0);
4317       return TRUE;
4318     }
4319
4320   return FALSE;
4321 }
4322
4323 /*-----------------------------------------------------------------*/
4324 /* outBitAcc - output a bit in acc                                 */
4325 /*-----------------------------------------------------------------*/
4326 static void
4327 outBitAcc (operand * result)
4328 {
4329   symbol *tlbl = newiTempLabel (NULL);
4330   /* if the result is a bit */
4331   if (AOP_TYPE (result) == AOP_CRY)
4332     {
4333       aopPut (result, "a", 0);
4334     }
4335   else
4336     {
4337       emitcode ("jz", "%05d$", tlbl->key + 100);
4338       emitcode ("mov", "a,%s", one);
4339       emitLabel (tlbl);
4340       outAcc (result);
4341     }
4342 }
4343
4344 /*-----------------------------------------------------------------*/
4345 /* genPlusBits - generates code for addition of two bits           */
4346 /*-----------------------------------------------------------------*/
4347 static void
4348 genPlusBits (iCode * ic)
4349 {
4350   D (emitcode (";", "genPlusBits"));
4351
4352   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4353   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4354     {
4355       symbol *lbl = newiTempLabel (NULL);
4356       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4357       emitcode ("cpl", "c");
4358       emitLabel (lbl);
4359       outBitC (IC_RESULT (ic));
4360     }
4361   else
4362     {
4363       emitcode ("clr", "a");
4364       emitcode ("rlc", "a");
4365       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4366       emitcode ("addc", "a,%s", zero);
4367       outAcc (IC_RESULT (ic));
4368     }
4369 }
4370
4371 #if 0
4372 /* This is the original version of this code.
4373
4374  * This is being kept around for reference,
4375  * because I am not entirely sure I got it right...
4376  */
4377 static void
4378 adjustArithmeticResult (iCode * ic)
4379 {
4380   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4381       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4382       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4383     aopPut (IC_RESULT (ic),
4384             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4385             2);
4386
4387   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4388       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4389       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4390     aopPut (IC_RESULT (ic),
4391             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4392             2);
4393
4394   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4395       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4396       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4397       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4398       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4399     {
4400       char buffer[5];
4401       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4402       aopPut (IC_RESULT (ic), buffer, 2);
4403     }
4404 }
4405 #else
4406 /* This is the pure and virtuous version of this code.
4407  * I'm pretty certain it's right, but not enough to toss the old
4408  * code just yet...
4409  */
4410 static void
4411 adjustArithmeticResult (iCode * ic)
4412 {
4413   if (opIsGptr (IC_RESULT (ic)) &&
4414       opIsGptr (IC_LEFT (ic)) &&
4415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4416     {
4417       aopPut (IC_RESULT (ic),
4418               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4419               GPTRSIZE - 1);
4420     }
4421
4422   if (opIsGptr (IC_RESULT (ic)) &&
4423       opIsGptr (IC_RIGHT (ic)) &&
4424       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4425     {
4426       aopPut (IC_RESULT (ic),
4427               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4428               GPTRSIZE - 1);
4429     }
4430
4431   if (opIsGptr (IC_RESULT (ic)) &&
4432       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4433       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4434       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4435       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4436     {
4437       char buffer[5];
4438       SNPRINTF (buffer, sizeof(buffer),
4439                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4440       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4441     }
4442 }
4443 #endif
4444
4445 /*-----------------------------------------------------------------*/
4446 /* genPlus - generates code for addition                           */
4447 /*-----------------------------------------------------------------*/
4448 static void
4449 genPlus (iCode * ic)
4450 {
4451   int size, offset = 0;
4452   int skip_bytes = 0;
4453   char *add = "add";
4454   bool swappedLR = FALSE;
4455   operand *leftOp, *rightOp;
4456   operand * op;
4457
4458   D (emitcode (";", "genPlus"));
4459
4460   /* special cases :- */
4461
4462   aopOp (IC_LEFT (ic), ic, FALSE);
4463   aopOp (IC_RIGHT (ic), ic, FALSE);
4464   aopOp (IC_RESULT (ic), ic, TRUE);
4465
4466   /* if literal, literal on the right or
4467      if left requires ACC or right is already
4468      in ACC */
4469   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4470       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4471       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4472     {
4473       operand *t = IC_RIGHT (ic);
4474       IC_RIGHT (ic) = IC_LEFT (ic);
4475       IC_LEFT (ic) = t;
4476       swappedLR = TRUE;
4477     }
4478
4479   /* if both left & right are in bit
4480      space */
4481   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4482       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4483     {
4484       genPlusBits (ic);
4485       goto release;
4486     }
4487
4488   /* if left in bit space & right literal */
4489   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4490       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4491     {
4492       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4493       /* if result in bit space */
4494       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4495         {
4496           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4497             emitcode ("cpl", "c");
4498           outBitC (IC_RESULT (ic));
4499         }
4500       else
4501         {
4502           size = getDataSize (IC_RESULT (ic));
4503           while (size--)
4504             {
4505               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4506               emitcode ("addc", "a,%s", zero);
4507               aopPut (IC_RESULT (ic), "a", offset++);
4508             }
4509         }
4510       goto release;
4511     }
4512
4513   /* if I can do an increment instead
4514      of add then GOOD for ME */
4515   if (genPlusIncr (ic) == TRUE)
4516     goto release;
4517
4518   size = getDataSize (IC_RESULT (ic));
4519   leftOp = IC_LEFT(ic);
4520   rightOp = IC_RIGHT(ic);
4521   op = IC_LEFT(ic);
4522
4523   /* if this is an add for an array access
4524      at a 256 byte boundary */
4525   if ( 2 == size
4526        && AOP_TYPE (op) == AOP_IMMD
4527        && IS_SYMOP (op)
4528        && IS_SPEC (OP_SYM_ETYPE (op))
4529        && SPEC_ABSA (OP_SYM_ETYPE (op))
4530        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4531      )
4532     {
4533       D(emitcode (";", "genPlus aligned array"));
4534       aopPut (IC_RESULT (ic),
4535               aopGet (rightOp, 0, FALSE, FALSE),
4536               0);
4537
4538       if( 1 == getDataSize (IC_RIGHT (ic)) )
4539         {
4540           aopPut (IC_RESULT (ic),
4541                   aopGet (leftOp, 1, FALSE, FALSE),
4542                   1);
4543         }
4544       else
4545         {
4546           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4547           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4548           aopPut (IC_RESULT (ic), "a", 1);
4549         }
4550       goto release;
4551     }
4552
4553   /* if the lower bytes of a literal are zero skip the addition */
4554   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4555     {
4556        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4557               (skip_bytes+1 < size))
4558          {
4559            skip_bytes++;
4560          }
4561        if (skip_bytes)
4562          D(emitcode (";", "genPlus shortcut"));
4563     }
4564
4565   while (size--)
4566     {
4567       if( offset >= skip_bytes )
4568         {
4569           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4570             {
4571               bool pushedB;
4572               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4573               pushedB = pushB ();
4574               emitcode("xch", "a,b");
4575               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4576               emitcode (add, "a,b");
4577               popB (pushedB);
4578             }
4579           else if (aopGetUsesAcc (leftOp, offset))
4580             {
4581               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4582               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4583             }
4584           else
4585             {
4586               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4587               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4588             }
4589           aopPut (IC_RESULT (ic), "a", offset);
4590           add = "addc";  /* further adds must propagate carry */
4591         }
4592       else
4593         {
4594           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4595               isOperandVolatile (IC_RESULT (ic), FALSE))
4596             {
4597               /* just move */
4598               aopPut (IC_RESULT (ic),
4599                       aopGet (leftOp, offset, FALSE, FALSE),
4600                       offset);
4601             }
4602         }
4603       offset++;
4604     }
4605
4606   adjustArithmeticResult (ic);
4607
4608 release:
4609   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4610   if (!swappedLR)
4611     {
4612       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4613       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614     }
4615   else
4616     {
4617       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4618       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4619     }
4620 }
4621
4622 /*-----------------------------------------------------------------*/
4623 /* genMinusDec :- does subtraction with decrement if possible      */
4624 /*-----------------------------------------------------------------*/
4625 static bool
4626 genMinusDec (iCode * ic)
4627 {
4628   unsigned int icount;
4629   unsigned int size = getDataSize (IC_RESULT (ic));
4630
4631   /* will try to generate an increment */
4632   /* if the right side is not a literal
4633      we cannot */
4634   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4635     return FALSE;
4636
4637   /* if the literal value of the right hand side
4638      is greater than 4 then it is not worth it */
4639   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4640     return FALSE;
4641
4642   D (emitcode (";", "genMinusDec"));
4643
4644   /* if decrement >=16 bits in register or direct space */
4645   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4646         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4647         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4648       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4649       (size > 1) &&
4650       (icount == 1))
4651     {
4652       symbol *tlbl;
4653       int emitTlbl;
4654       int labelRange;
4655
4656       /* If the next instruction is a goto and the goto target
4657        * is <= 10 instructions previous to this, we can generate
4658        * jumps straight to that target.
4659        */
4660       if (ic->next && ic->next->op == GOTO
4661           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4662           && labelRange <= 10)
4663         {
4664           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4665           tlbl = IC_LABEL (ic->next);
4666           emitTlbl = 0;
4667         }
4668       else
4669         {
4670           tlbl = newiTempLabel (NULL);
4671           emitTlbl = 1;
4672         }
4673
4674       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4675       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4676           IS_AOP_PREG (IC_RESULT (ic)))
4677         emitcode ("cjne", "%s,#0xff,%05d$"
4678                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4679                   ,tlbl->key + 100);
4680       else
4681         {
4682           emitcode ("mov", "a,#0xff");
4683           emitcode ("cjne", "a,%s,%05d$"
4684                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4685                     ,tlbl->key + 100);
4686         }
4687       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4688       if (size > 2)
4689         {
4690           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4691               IS_AOP_PREG (IC_RESULT (ic)))
4692             emitcode ("cjne", "%s,#0xff,%05d$"
4693                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4694                       ,tlbl->key + 100);
4695           else
4696             {
4697               emitcode ("cjne", "a,%s,%05d$"
4698                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4699                         ,tlbl->key + 100);
4700             }
4701           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4702         }
4703       if (size > 3)
4704         {
4705           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4706               IS_AOP_PREG (IC_RESULT (ic)))
4707             emitcode ("cjne", "%s,#0xff,%05d$"
4708                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4709                       ,tlbl->key + 100);
4710           else
4711             {
4712               emitcode ("cjne", "a,%s,%05d$"
4713                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4714                         ,tlbl->key + 100);
4715             }
4716           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4717         }
4718       if (emitTlbl)
4719         {
4720           emitLabel (tlbl);
4721         }
4722       return TRUE;
4723     }
4724
4725   /* if the sizes are greater than 1 then we cannot */
4726   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4727       AOP_SIZE (IC_LEFT (ic)) > 1)
4728     return FALSE;
4729
4730   /* we can if the aops of the left & result match or
4731      if they are in registers and the registers are the
4732      same */
4733   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4734     {
4735       char *l;
4736
4737       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4738         {
4739           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4740           l = "a";
4741         }
4742       else
4743         {
4744           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4745         }
4746
4747       while (icount--)
4748         {
4749           emitcode ("dec", "%s", l);
4750         }
4751
4752       if (AOP_NEEDSACC (IC_RESULT (ic)))
4753         aopPut (IC_RESULT (ic), "a", 0);
4754
4755       return TRUE;
4756     }
4757
4758   if (icount == 1)
4759     {
4760       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4761       emitcode ("dec", "a");
4762       aopPut (IC_RESULT (ic), "a", 0);
4763       return TRUE;
4764     }
4765
4766   return FALSE;
4767 }
4768
4769 /*-----------------------------------------------------------------*/
4770 /* addSign - complete with sign                                    */
4771 /*-----------------------------------------------------------------*/
4772 static void
4773 addSign (operand * result, int offset, int sign)
4774 {
4775   int size = (getDataSize (result) - offset);
4776   if (size > 0)
4777     {
4778       if (sign)
4779         {
4780           emitcode ("rlc", "a");
4781           emitcode ("subb", "a,acc");
4782           while (size--)
4783             {
4784               aopPut (result, "a", offset++);
4785             }
4786         }
4787       else
4788         {
4789           while (size--)
4790             {
4791               aopPut (result, zero, offset++);
4792             }
4793         }
4794     }
4795 }
4796
4797 /*-----------------------------------------------------------------*/
4798 /* genMinusBits - generates code for subtraction  of two bits      */
4799 /*-----------------------------------------------------------------*/
4800 static void
4801 genMinusBits (iCode * ic)
4802 {
4803   symbol *lbl = newiTempLabel (NULL);
4804
4805   D (emitcode (";", "genMinusBits"));
4806
4807   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4808     {
4809       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4810       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4811       emitcode ("cpl", "c");
4812       emitLabel (lbl);
4813       outBitC (IC_RESULT (ic));
4814     }
4815   else
4816     {
4817       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4818       emitcode ("subb", "a,acc");
4819       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4820       emitcode ("inc", "a");
4821       emitLabel (lbl);
4822       aopPut (IC_RESULT (ic), "a", 0);
4823       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4824     }
4825 }
4826
4827 /*-----------------------------------------------------------------*/
4828 /* genMinus - generates code for subtraction                       */
4829 /*-----------------------------------------------------------------*/
4830 static void
4831 genMinus (iCode * ic)
4832 {
4833   int size, offset = 0;
4834
4835   D (emitcode (";", "genMinus"));
4836
4837   aopOp (IC_LEFT (ic), ic, FALSE);
4838   aopOp (IC_RIGHT (ic), ic, FALSE);
4839   aopOp (IC_RESULT (ic), ic, TRUE);
4840
4841   /* special cases :- */
4842   /* if both left & right are in bit space */
4843   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4844       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4845     {
4846       genMinusBits (ic);
4847       goto release;
4848     }
4849
4850   /* if I can do an decrement instead
4851      of subtract then GOOD for ME */
4852   if (genMinusDec (ic) == TRUE)
4853     goto release;
4854
4855   size = getDataSize (IC_RESULT (ic));
4856
4857   /* if literal, add a,#-lit, else normal subb */
4858   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4859     {
4860       unsigned long lit = 0L;
4861       bool useCarry = FALSE;
4862
4863       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4864       lit = -(long) lit;
4865
4866       while (size--)
4867         {
4868           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4869             {
4870               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4871               if (!offset && !size && lit== (unsigned long) -1)
4872                 {
4873                   emitcode ("dec", "a");
4874                 }
4875               else if (!useCarry)
4876                 {
4877                   /* first add without previous c */
4878                   emitcode ("add", "a,#0x%02x",
4879                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4880                   useCarry = TRUE;
4881                 }
4882               else
4883                 {
4884                   emitcode ("addc", "a,#0x%02x",
4885                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4886                 }
4887               aopPut (IC_RESULT (ic), "a", offset++);
4888             }
4889           else
4890             {
4891               /* no need to add zeroes */
4892               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4893                 {
4894                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4895                           offset);
4896                 }
4897               offset++;
4898             }
4899         }
4900     }
4901   else
4902     {
4903       operand *leftOp, *rightOp;
4904
4905       leftOp = IC_LEFT(ic);
4906       rightOp = IC_RIGHT(ic);
4907
4908       while (size--)
4909         {
4910           if (aopGetUsesAcc(rightOp, offset)) {
4911             if (aopGetUsesAcc(leftOp, offset)) {
4912               bool pushedB;
4913
4914               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4915               pushedB = pushB ();
4916               emitcode ("mov", "b,a");
4917               if (offset == 0)
4918                 CLRC;
4919               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4920               emitcode ("subb", "a,b");
4921               popB (pushedB);
4922             } else {
4923               /* reverse subtraction with 2's complement */
4924               if (offset == 0)
4925                 emitcode( "setb", "c");
4926               else
4927                 emitcode( "cpl", "c");
4928               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4929               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4930               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4931               emitcode("cpl", "a");
4932               if (size) /* skip if last byte */
4933                 emitcode( "cpl", "c");
4934             }
4935           } else {
4936             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4937             if (offset == 0)
4938               CLRC;
4939             emitcode ("subb", "a,%s",
4940                       aopGet(rightOp, offset, FALSE, TRUE));
4941           }
4942
4943           aopPut (IC_RESULT (ic), "a", offset++);
4944         }
4945     }
4946
4947   adjustArithmeticResult (ic);
4948
4949 release:
4950   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4951   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4952   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4953 }
4954
4955
4956 /*-----------------------------------------------------------------*/
4957 /* genMultbits :- multiplication of bits                           */
4958 /*-----------------------------------------------------------------*/
4959 static void
4960 genMultbits (operand * left,
4961              operand * right,
4962              operand * result)
4963 {
4964   D (emitcode (";", "genMultbits"));
4965
4966   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4967   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4968   outBitC (result);
4969 }
4970
4971 /*-----------------------------------------------------------------*/
4972 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4973 /*-----------------------------------------------------------------*/
4974 static void
4975 genMultOneByte (operand * left,
4976                 operand * right,
4977                 operand * result)
4978 {
4979   symbol *lbl;
4980   int size = AOP_SIZE (result);
4981   bool runtimeSign, compiletimeSign;
4982   bool lUnsigned, rUnsigned, pushedB;
4983
4984   D (emitcode (";", "genMultOneByte"));
4985
4986   if (size < 1 || size > 2)
4987     {
4988       /* this should never happen */
4989       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4990                AOP_SIZE(result), __FILE__, lineno);
4991       exit (1);
4992     }
4993
4994   /* (if two literals: the value is computed before) */
4995   /* if one literal, literal on the right */
4996   if (AOP_TYPE (left) == AOP_LIT)
4997     {
4998       operand *t = right;
4999       right = left;
5000       left = t;
5001       /* emitcode (";", "swapped left and right"); */
5002     }
5003   /* if no literal, unsigned on the right: shorter code */
5004   if (   AOP_TYPE (right) != AOP_LIT
5005       && SPEC_USIGN (getSpec (operandType (left))))
5006     {
5007       operand *t = right;
5008       right = left;
5009       left = t;
5010     }
5011
5012   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5013   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5014
5015   pushedB = pushB ();
5016
5017   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5018                    no need to take care about the signedness! */
5019       || (lUnsigned && rUnsigned))
5020     {
5021       /* just an unsigned 8 * 8 = 8 multiply
5022          or 8u * 8u = 16u */
5023       /* emitcode (";","unsigned"); */
5024       /* TODO: check for accumulator clash between left & right aops? */
5025
5026       if (AOP_TYPE (right) == AOP_LIT)
5027         {
5028           /* moving to accumulator first helps peepholes */
5029           MOVA (aopGet (left, 0, FALSE, FALSE));
5030           MOVB (aopGet (right, 0, FALSE, FALSE));
5031         }
5032       else
5033         {
5034           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5035           MOVA (aopGet (left, 0, FALSE, FALSE));
5036         }
5037
5038       emitcode ("mul", "ab");
5039       aopPut (result, "a", 0);
5040       if (size == 2)
5041         aopPut (result, "b", 1);
5042
5043       popB (pushedB);
5044       return;
5045     }
5046
5047   /* we have to do a signed multiply */
5048   /* emitcode (";", "signed"); */
5049
5050   /* now sign adjust for both left & right */
5051
5052   /* let's see what's needed: */
5053   /* apply negative sign during runtime */
5054   runtimeSign = FALSE;
5055   /* negative sign from literals */
5056   compiletimeSign = FALSE;
5057
5058   if (!lUnsigned)
5059     {
5060       if (AOP_TYPE(left) == AOP_LIT)
5061         {
5062           /* signed literal */
5063           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5064           if (val < 0)
5065             compiletimeSign = TRUE;
5066         }
5067       else
5068         /* signed but not literal */
5069         runtimeSign = TRUE;
5070     }
5071
5072   if (!rUnsigned)
5073     {
5074       if (AOP_TYPE(right) == AOP_LIT)
5075         {
5076           /* signed literal */
5077           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5078           if (val < 0)
5079             compiletimeSign ^= TRUE;
5080         }
5081       else
5082         /* signed but not literal */
5083         runtimeSign = TRUE;
5084     }
5085
5086   /* initialize F0, which stores the runtime sign */
5087   if (runtimeSign)
5088     {
5089       if (compiletimeSign)
5090         emitcode ("setb", "F0"); /* set sign flag */
5091       else
5092         emitcode ("clr", "F0"); /* reset sign flag */
5093     }
5094
5095   /* save the signs of the operands */
5096   if (AOP_TYPE(right) == AOP_LIT)
5097     {
5098       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5099
5100       if (!rUnsigned && val < 0)
5101         emitcode ("mov", "b,#0x%02x", -val);
5102       else
5103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5104     }
5105   else /* ! literal */
5106     {
5107       if (rUnsigned)  /* emitcode (";", "signed"); */
5108         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5109       else
5110         {
5111           MOVA (aopGet (right, 0, FALSE, FALSE));
5112           lbl = newiTempLabel (NULL);
5113           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5114           emitcode ("cpl", "F0"); /* complement sign flag */
5115           emitcode ("cpl", "a");  /* 2's complement */
5116           emitcode ("inc", "a");
5117           emitLabel (lbl);
5118           emitcode ("mov", "b,a");
5119         }
5120     }
5121
5122   if (AOP_TYPE(left) == AOP_LIT)
5123     {
5124       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5125
5126       if (!lUnsigned && val < 0)
5127         emitcode ("mov", "a,#0x%02x", -val);
5128       else
5129         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5130     }
5131   else /* ! literal */
5132     {
5133       MOVA (aopGet (left, 0, FALSE, FALSE));
5134
5135       if (!lUnsigned)
5136         {
5137           lbl = newiTempLabel (NULL);
5138           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5139           emitcode ("cpl", "F0"); /* complement sign flag */
5140           emitcode ("cpl", "a"); /* 2's complement */
5141           emitcode ("inc", "a");
5142           emitLabel (lbl);
5143         }
5144     }
5145
5146   /* now the multiplication */
5147   emitcode ("mul", "ab");
5148   if (runtimeSign || compiletimeSign)
5149     {
5150       lbl = newiTempLabel (NULL);
5151       if (runtimeSign)
5152         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5153       emitcode ("cpl", "a"); /* lsb 2's complement */
5154       if (size != 2)
5155         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5156       else
5157         {
5158           emitcode ("add", "a,#1"); /* this sets carry flag */
5159           emitcode ("xch", "a,b");
5160           emitcode ("cpl", "a"); /* msb 2's complement */
5161           emitcode ("addc", "a,#0");
5162           emitcode ("xch", "a,b");
5163         }
5164       emitLabel (lbl);
5165     }
5166   aopPut (result, "a", 0);
5167   if (size == 2)
5168     aopPut (result, "b", 1);
5169
5170   popB (pushedB);
5171 }
5172
5173 /*-----------------------------------------------------------------*/
5174 /* genMult - generates code for multiplication                     */
5175 /*-----------------------------------------------------------------*/
5176 static void
5177 genMult (iCode * ic)
5178 {
5179   operand *left = IC_LEFT (ic);
5180   operand *right = IC_RIGHT (ic);
5181   operand *result = IC_RESULT (ic);
5182
5183   D (emitcode (";", "genMult"));
5184
5185   /* assign the asmops */
5186   aopOp (left, ic, FALSE);
5187   aopOp (right, ic, FALSE);
5188   aopOp (result, ic, TRUE);
5189
5190   /* special cases first */
5191   /* both are bits */
5192   if (AOP_TYPE (left) == AOP_CRY &&
5193       AOP_TYPE (right) == AOP_CRY)
5194     {
5195       genMultbits (left, right, result);
5196       goto release;
5197     }
5198
5199   /* if both are of size == 1 */
5200 #if 0 // one of them can be a sloc shared with the result
5201     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5202 #else
5203   if (getSize(operandType(left)) == 1 &&
5204       getSize(operandType(right)) == 1)
5205 #endif
5206     {
5207       genMultOneByte (left, right, result);
5208       goto release;
5209     }
5210
5211   /* should have been converted to function call */
5212     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5213              getSize(OP_SYMBOL(right)->type));
5214   assert (0);
5215
5216 release:
5217   freeAsmop (result, NULL, ic, TRUE);
5218   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5219   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5220 }
5221
5222 /*-----------------------------------------------------------------*/
5223 /* genDivbits :- division of bits                                  */
5224 /*-----------------------------------------------------------------*/
5225 static void
5226 genDivbits (operand * left,
5227             operand * right,
5228             operand * result)
5229 {
5230   char *l;
5231   bool pushedB;
5232
5233   D(emitcode (";", "genDivbits"));
5234
5235   pushedB = pushB ();
5236
5237   /* the result must be bit */
5238   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5239   l = aopGet (left, 0, FALSE, FALSE);
5240
5241   MOVA (l);
5242
5243   emitcode ("div", "ab");
5244   emitcode ("rrc", "a");
5245
5246   popB (pushedB);
5247
5248   aopPut (result, "c", 0);
5249 }
5250
5251 /*-----------------------------------------------------------------*/
5252 /* genDivOneByte : 8 bit division                                  */
5253 /*-----------------------------------------------------------------*/
5254 static void
5255 genDivOneByte (operand * left,
5256                operand * right,
5257                operand * result)
5258 {
5259   bool lUnsigned, rUnsigned, pushedB;
5260   bool runtimeSign, compiletimeSign;
5261   bool accuse = FALSE;
5262   bool pushedA = FALSE;
5263   symbol *lbl;
5264   int size, offset;
5265
5266   D(emitcode (";", "genDivOneByte"));
5267
5268   /* Why is it necessary that genDivOneByte() can return an int result?
5269      Have a look at:
5270
5271         volatile unsigned char uc;
5272         volatile signed char sc1, sc2;
5273         volatile int i;
5274
5275         uc  = 255;
5276         sc1 = -1;
5277         i = uc / sc1;
5278
5279      Or:
5280
5281         sc1 = -128;
5282         sc2 = -1;
5283         i = sc1 / sc2;
5284
5285      In all cases a one byte result would overflow, the following cast to int
5286      would return the wrong result.
5287
5288      Two possible solution:
5289         a) cast operands to int, if ((unsigned) / (signed)) or
5290            ((signed) / (signed))
5291         b) return an 16 bit signed int; this is what we're doing here!
5292   */
5293
5294   size = AOP_SIZE (result) - 1;
5295   offset = 1;
5296   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5297   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5298
5299   pushedB = pushB ();
5300
5301   /* signed or unsigned */
5302   if (lUnsigned && rUnsigned)
5303     {
5304       /* unsigned is easy */
5305       MOVB (aopGet (right, 0, FALSE, FALSE));
5306       MOVA (aopGet (left, 0, FALSE, FALSE));
5307       emitcode ("div", "ab");
5308       aopPut (result, "a", 0);
5309       while (size--)
5310         aopPut (result, zero, offset++);
5311
5312       popB (pushedB);
5313       return;
5314     }
5315
5316   /* signed is a little bit more difficult */
5317
5318   /* now sign adjust for both left & right */
5319
5320   /* let's see what's needed: */
5321   /* apply negative sign during runtime */
5322   runtimeSign = FALSE;
5323   /* negative sign from literals */
5324   compiletimeSign = FALSE;
5325
5326   if (!lUnsigned)
5327     {
5328       if (AOP_TYPE(left) == AOP_LIT)
5329         {
5330           /* signed literal */
5331           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5332           if (val < 0)
5333             compiletimeSign = TRUE;
5334         }
5335       else
5336         /* signed but not literal */
5337         runtimeSign = TRUE;
5338     }
5339
5340   if (!rUnsigned)
5341     {
5342       if (AOP_TYPE(right) == AOP_LIT)
5343         {
5344           /* signed literal */
5345           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5346           if (val < 0)
5347             compiletimeSign ^= TRUE;
5348         }
5349       else
5350         /* signed but not literal */
5351         runtimeSign = TRUE;
5352     }
5353
5354   /* initialize F0, which stores the runtime sign */
5355   if (runtimeSign)
5356     {
5357       if (compiletimeSign)
5358         emitcode ("setb", "F0"); /* set sign flag */
5359       else
5360         emitcode ("clr", "F0"); /* reset sign flag */
5361     }
5362
5363   /* save the signs of the operands */
5364   if (AOP_TYPE(right) == AOP_LIT)
5365     {
5366       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5367
5368       if (!rUnsigned && val < 0)
5369         emitcode ("mov", "b,#0x%02x", -val);
5370       else
5371         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5372     }
5373   else /* ! literal */
5374     {
5375       if (rUnsigned)
5376         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5377       else
5378         {
5379           MOVA (aopGet (right, 0, FALSE, FALSE));
5380           lbl = newiTempLabel (NULL);
5381           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5382           emitcode ("cpl", "F0"); /* complement sign flag */
5383           emitcode ("cpl", "a");  /* 2's complement */
5384           emitcode ("inc", "a");
5385           emitLabel (lbl);
5386           emitcode ("mov", "b,a");
5387         }
5388     }
5389
5390   if (AOP_TYPE(left) == AOP_LIT)
5391     {
5392       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5393
5394       if (!lUnsigned && val < 0)
5395         emitcode ("mov", "a,#0x%02x", -val);
5396       else
5397         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5398     }
5399   else /* ! literal */
5400     {
5401       MOVA (aopGet (left, 0, FALSE, FALSE));
5402
5403       if (!lUnsigned)
5404         {
5405           lbl = newiTempLabel (NULL);
5406           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5407           emitcode ("cpl", "F0"); /* complement sign flag */
5408           emitcode ("cpl", "a");  /* 2's complement */
5409           emitcode ("inc", "a");
5410           emitLabel (lbl);
5411         }
5412     }
5413
5414   /* now the division */
5415   emitcode ("div", "ab");
5416
5417   if (runtimeSign || compiletimeSign)
5418     {
5419       lbl = newiTempLabel (NULL);
5420       if (runtimeSign)
5421         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5422       emitcode ("cpl", "a"); /* lsb 2's complement */
5423       emitcode ("inc", "a");
5424       emitLabel (lbl);
5425
5426       accuse = aopPut (result, "a", 0);
5427       if (size > 0)
5428         {
5429           /* msb is 0x00 or 0xff depending on the sign */
5430           if (runtimeSign)
5431             {
5432               if (accuse)
5433                 {
5434                   emitcode ("push", "acc");
5435                   pushedA = TRUE;
5436                 }
5437               emitcode ("mov", "c,F0");
5438               emitcode ("subb", "a,acc");
5439               while (size--)
5440                 aopPut (result, "a", offset++);
5441             }
5442           else /* compiletimeSign */
5443             {
5444               if (aopPutUsesAcc (result, "#0xFF", offset))
5445                 {
5446                   emitcode ("push", "acc");
5447                   pushedA = TRUE;
5448                 }
5449               while (size--)
5450                 aopPut (result, "#0xff", offset++);
5451             }
5452         }
5453     }
5454   else
5455     {
5456       aopPut (result, "a", 0);
5457       while (size--)
5458         aopPut (result, zero, offset++);
5459     }
5460
5461   if (pushedA)
5462     emitcode ("pop", "acc");
5463   popB (pushedB);
5464 }
5465
5466 /*-----------------------------------------------------------------*/
5467 /* genDiv - generates code for division                            */
5468 /*-----------------------------------------------------------------*/
5469 static void
5470 genDiv (iCode * ic)
5471 {
5472   operand *left = IC_LEFT (ic);
5473   operand *right = IC_RIGHT (ic);
5474   operand *result = IC_RESULT (ic);
5475
5476   D (emitcode (";", "genDiv"));
5477
5478   /* assign the asmops */
5479   aopOp (left, ic, FALSE);
5480   aopOp (right, ic, FALSE);
5481   aopOp (result, ic, TRUE);
5482
5483   /* special cases first */
5484   /* both are bits */
5485   if (AOP_TYPE (left) == AOP_CRY &&
5486       AOP_TYPE (right) == AOP_CRY)
5487     {
5488       genDivbits (left, right, result);
5489       goto release;
5490     }
5491
5492   /* if both are of size == 1 */
5493   if (AOP_SIZE (left) == 1 &&
5494       AOP_SIZE (right) == 1)
5495     {
5496       genDivOneByte (left, right, result);
5497       goto release;
5498     }
5499
5500   /* should have been converted to function call */
5501   assert (0);
5502 release:
5503   freeAsmop (result, NULL, ic, TRUE);
5504   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5505   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5506 }
5507
5508 /*-----------------------------------------------------------------*/
5509 /* genModbits :- modulus of bits                                   */
5510 /*-----------------------------------------------------------------*/
5511 static void
5512 genModbits (operand * left,
5513             operand * right,
5514             operand * result)
5515 {
5516   char *l;
5517   bool pushedB;
5518
5519   D (emitcode (";", "genModbits"));
5520
5521   pushedB = pushB ();
5522
5523   /* the result must be bit */
5524   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5525   l = aopGet (left, 0, FALSE, FALSE);
5526
5527   MOVA (l);
5528
5529   emitcode ("div", "ab");
5530   emitcode ("mov", "a,b");
5531   emitcode ("rrc", "a");
5532
5533   popB (pushedB);
5534
5535   aopPut (result, "c", 0);
5536 }
5537
5538 /*-----------------------------------------------------------------*/
5539 /* genModOneByte : 8 bit modulus                                   */
5540 /*-----------------------------------------------------------------*/
5541 static void
5542 genModOneByte (operand * left,
5543                operand * right,
5544                operand * result)
5545 {
5546   bool lUnsigned, rUnsigned, pushedB;
5547   bool runtimeSign, compiletimeSign;
5548   symbol *lbl;
5549   int size, offset;
5550
5551   D (emitcode (";", "genModOneByte"));
5552
5553   size = AOP_SIZE (result) - 1;
5554   offset = 1;
5555   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5556   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5557
5558   /* if right is a literal, check it for 2^n */
5559   if (AOP_TYPE(right) == AOP_LIT)
5560     {
5561       unsigned char val = abs((int) operandLitValue(right));
5562       symbol *lbl2 = NULL;
5563
5564       switch (val)
5565         {
5566           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5567           case 2:
5568           case 4:
5569           case 8:
5570           case 16:
5571           case 32:
5572           case 64:
5573           case 128:
5574             if (lUnsigned)
5575               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5576                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5577               /* because iCode should have been changed to genAnd  */
5578               /* see file "SDCCopt.c", function "convertToFcall()" */
5579
5580             MOVA (aopGet (left, 0, FALSE, FALSE));
5581             emitcode ("mov", "c,acc.7");
5582             emitcode ("anl", "a,#0x%02x", val - 1);
5583             lbl = newiTempLabel (NULL);
5584             emitcode ("jz", "%05d$", (lbl->key + 100));
5585             emitcode ("jnc", "%05d$", (lbl->key + 100));
5586             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5587             if (size)
5588               {
5589                 int size2 = size;
5590                 int offs2 = offset;
5591
5592                 aopPut (result, "a", 0);
5593                 while (size2--)
5594                   aopPut (result, "#0xff", offs2++);
5595                 lbl2 = newiTempLabel (NULL);
5596                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5597               }
5598             emitLabel (lbl);
5599             aopPut (result, "a", 0);
5600             while (size--)
5601               aopPut (result, zero, offset++);
5602             if (lbl2)
5603               {
5604                 emitLabel (lbl2);
5605               }
5606             return;
5607
5608           default:
5609             break;
5610         }
5611     }
5612
5613   pushedB = pushB ();
5614
5615   /* signed or unsigned */
5616   if (lUnsigned && rUnsigned)
5617     {
5618       /* unsigned is easy */
5619       MOVB (aopGet (right, 0, FALSE, FALSE));
5620       MOVA (aopGet (left, 0, FALSE, FALSE));
5621       emitcode ("div", "ab");
5622       aopPut (result, "b", 0);
5623       while (size--)
5624         aopPut (result, zero, offset++);
5625
5626       popB (pushedB);
5627       return;
5628     }
5629
5630   /* signed is a little bit more difficult */
5631
5632   /* now sign adjust for both left & right */
5633
5634   /* modulus: sign of the right operand has no influence on the result! */
5635   if (AOP_TYPE(right) == AOP_LIT)
5636     {
5637       signed char val = (char) operandLitValue(right);
5638
5639       if (!rUnsigned && val < 0)
5640         emitcode ("mov", "b,#0x%02x", -val);
5641       else
5642         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5643     }
5644   else /* not literal */
5645     {
5646       if (rUnsigned)
5647         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5648       else
5649         {
5650           MOVA (aopGet (right, 0, FALSE, FALSE));
5651           lbl = newiTempLabel (NULL);
5652           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5653           emitcode ("cpl", "a"); /* 2's complement */
5654           emitcode ("inc", "a");
5655           emitLabel (lbl);
5656           emitcode ("mov", "b,a");
5657         }
5658     }
5659
5660   /* let's see what's needed: */
5661   /* apply negative sign during runtime */
5662   runtimeSign = FALSE;
5663   /* negative sign from literals */
5664   compiletimeSign = FALSE;
5665
5666   /* sign adjust left side */
5667   if (AOP_TYPE(left) == AOP_LIT)
5668     {
5669       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5670
5671       if (!lUnsigned && val < 0)
5672         {
5673           compiletimeSign = TRUE; /* set sign flag */
5674           emitcode ("mov", "a,#0x%02x", -val);
5675         }
5676       else
5677         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5678     }
5679   else /* ! literal */
5680     {
5681       MOVA (aopGet (left, 0, FALSE, FALSE));
5682
5683       if (!lUnsigned)
5684         {
5685           runtimeSign = TRUE;
5686           emitcode ("clr", "F0"); /* clear sign flag */
5687
5688           lbl = newiTempLabel (NULL);
5689           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5690           emitcode ("setb", "F0"); /* set sign flag */
5691           emitcode ("cpl", "a");   /* 2's complement */
5692           emitcode ("inc", "a");
5693           emitLabel (lbl);
5694         }
5695     }
5696
5697   /* now the modulus */
5698   emitcode ("div", "ab");
5699
5700   if (runtimeSign || compiletimeSign)
5701     {
5702       emitcode ("mov", "a,b");
5703       lbl = newiTempLabel (NULL);
5704       if (runtimeSign)
5705         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5706       emitcode ("cpl", "a"); /* 2's complement */
5707       emitcode ("inc", "a");
5708       emitLabel (lbl);
5709
5710       aopPut (result, "a", 0);
5711       if (size > 0)
5712         {
5713           /* msb is 0x00 or 0xff depending on the sign */
5714           if (runtimeSign)
5715             {
5716               emitcode ("mov", "c,F0");
5717               emitcode ("subb", "a,acc");
5718               while (size--)
5719                 aopPut (result, "a", offset++);
5720             }
5721           else /* compiletimeSign */
5722             while (size--)
5723               aopPut (result, "#0xff", offset++);
5724         }
5725     }
5726   else
5727     {
5728       aopPut (result, "b", 0);
5729       while (size--)
5730         aopPut (result, zero, offset++);
5731     }
5732
5733   popB (pushedB);
5734 }
5735
5736 /*-----------------------------------------------------------------*/
5737 /* genMod - generates code for division                            */
5738 /*-----------------------------------------------------------------*/
5739 static void
5740 genMod (iCode * ic)
5741 {
5742   operand *left = IC_LEFT (ic);
5743   operand *right = IC_RIGHT (ic);
5744   operand *result = IC_RESULT (ic);
5745
5746   D (emitcode (";", "genMod"));
5747
5748   /* assign the asmops */
5749   aopOp (left, ic, FALSE);
5750   aopOp (right, ic, FALSE);
5751   aopOp (result, ic, TRUE);
5752
5753   /* special cases first */
5754   /* both are bits */
5755   if (AOP_TYPE (left) == AOP_CRY &&
5756       AOP_TYPE (right) == AOP_CRY)
5757     {
5758       genModbits (left, right, result);
5759       goto release;
5760     }
5761
5762   /* if both are of size == 1 */
5763   if (AOP_SIZE (left) == 1 &&
5764       AOP_SIZE (right) == 1)
5765     {
5766       genModOneByte (left, right, result);
5767       goto release;
5768     }
5769
5770   /* should have been converted to function call */
5771   assert (0);
5772
5773 release:
5774   freeAsmop (result, NULL, ic, TRUE);
5775   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5776   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5777 }
5778
5779 /*-----------------------------------------------------------------*/
5780 /* genIfxJump :- will create a jump depending on the ifx           */
5781 /*-----------------------------------------------------------------*/
5782 static void
5783 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5784 {
5785   symbol *jlbl;
5786   symbol *tlbl = newiTempLabel (NULL);
5787   char *inst;
5788
5789   D (emitcode (";", "genIfxJump"));
5790
5791   /* if true label then we jump if condition
5792      supplied is true */
5793   if (IC_TRUE (ic))
5794     {
5795       jlbl = IC_TRUE (ic);
5796       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5797                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5798     }
5799   else
5800     {
5801       /* false label is present */
5802       jlbl = IC_FALSE (ic);
5803       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5804                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5805     }
5806   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5807     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5808   else
5809     emitcode (inst, "%05d$", tlbl->key + 100);
5810   freeForBranchAsmop (result);
5811   freeForBranchAsmop (right);
5812   freeForBranchAsmop (left);
5813   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5814   emitLabel (tlbl);
5815
5816   /* mark the icode as generated */
5817   ic->generated = 1;
5818 }
5819
5820 /*-----------------------------------------------------------------*/
5821 /* genCmp :- greater or less than comparison                       */
5822 /*-----------------------------------------------------------------*/
5823 static void
5824 genCmp (operand * left, operand * right,
5825         operand * result, iCode * ifx, int sign, iCode *ic)
5826 {
5827   int size, offset = 0;
5828   unsigned long lit = 0L;
5829   bool rightInB;
5830
5831   D (emitcode (";", "genCmp"));
5832
5833   /* if left & right are bit variables */
5834   if (AOP_TYPE (left) == AOP_CRY &&
5835       AOP_TYPE (right) == AOP_CRY)
5836     {
5837       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5838       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5839     }
5840   else
5841     {
5842       /* subtract right from left if at the
5843          end the carry flag is set then we know that
5844          left is greater than right */
5845       size = max (AOP_SIZE (left), AOP_SIZE (right));
5846
5847       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5848       if ((size == 1) && !sign &&
5849           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5850         {
5851           symbol *lbl = newiTempLabel (NULL);
5852           emitcode ("cjne", "%s,%s,%05d$",
5853                     aopGet (left, offset, FALSE, FALSE),
5854                     aopGet (right, offset, FALSE, FALSE),
5855                     lbl->key + 100);
5856           emitLabel (lbl);
5857         }
5858       else
5859         {
5860           if (AOP_TYPE (right) == AOP_LIT)
5861             {
5862               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5863               /* optimize if(x < 0) or if(x >= 0) */
5864               if (lit == 0L)
5865                 {
5866                   if (!sign)
5867                     {
5868                       CLRC;
5869                     }
5870                   else
5871                     {
5872                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5873                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5874                         {
5875                           genIfxJump (ifx, "acc.7", left, right, result);
5876                           freeAsmop (right, NULL, ic, TRUE);
5877                           freeAsmop (left, NULL, ic, TRUE);
5878
5879                           return;
5880                         }
5881                       else
5882                         {
5883                           emitcode ("rlc", "a");
5884                         }
5885                     }
5886                   goto release;
5887                 }
5888               else
5889                 {//nonzero literal
5890                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5891                   while (size && (bytelit == 0))
5892                     {
5893                       offset++;
5894                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5895                       size--;
5896                     }
5897                   CLRC;
5898                   while (size--)
5899                     {
5900                       MOVA (aopGet (left, offset, FALSE, FALSE));
5901                       if (sign && size == 0)
5902                         {
5903                           emitcode ("xrl", "a,#0x80");
5904                           emitcode ("subb", "a,#0x%02x",
5905                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5906                         }
5907                       else
5908                         {
5909                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5910                         }
5911                       offset++;
5912                     }
5913                   goto release;
5914                 }
5915             }
5916           CLRC;
5917           while (size--)
5918             {
5919               bool pushedB = FALSE;
5920               rightInB = aopGetUsesAcc(right, offset);
5921               if (rightInB)
5922                 {
5923                   pushedB = pushB ();
5924                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5925                 }
5926               MOVA (aopGet (left, offset, FALSE, FALSE));
5927               if (sign && size == 0)
5928                 {
5929                   emitcode ("xrl", "a,#0x80");
5930                   if (!rightInB)
5931                     {
5932                       pushedB = pushB ();
5933                       rightInB++;
5934                       MOVB (aopGet (right, offset, FALSE, FALSE));
5935                     }
5936                   emitcode ("xrl", "b,#0x80");
5937                   emitcode ("subb", "a,b");
5938                 }
5939               else
5940                 {
5941                   if (rightInB)
5942                     emitcode ("subb", "a,b");
5943                   else
5944                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5945                 }
5946               if (rightInB)
5947                 popB (pushedB);
5948               offset++;
5949             }
5950         }
5951     }
5952
5953 release:
5954   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5955   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5956   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5957     {
5958       outBitC (result);
5959     }
5960   else
5961     {
5962       /* if the result is used in the next
5963          ifx conditional branch then generate
5964          code a little differently */
5965       if (ifx)
5966         {
5967           genIfxJump (ifx, "c", NULL, NULL, result);
5968         }
5969       else
5970         {
5971           outBitC (result);
5972         }
5973       /* leave the result in acc */
5974     }
5975 }
5976
5977 /*-----------------------------------------------------------------*/
5978 /* genCmpGt :- greater than comparison                             */
5979 /*-----------------------------------------------------------------*/
5980 static void
5981 genCmpGt (iCode * ic, iCode * ifx)
5982 {
5983   operand *left, *right, *result;
5984   sym_link *letype, *retype;
5985   int sign;
5986
5987   D (emitcode (";", "genCmpGt"));
5988
5989   left = IC_LEFT (ic);
5990   right = IC_RIGHT (ic);
5991   result = IC_RESULT (ic);
5992
5993   letype = getSpec (operandType (left));
5994   retype = getSpec (operandType (right));
5995   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5996            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5997   /* assign the asmops */
5998   aopOp (result, ic, TRUE);
5999   aopOp (left, ic, FALSE);
6000   aopOp (right, ic, FALSE);
6001
6002   genCmp (right, left, result, ifx, sign, ic);
6003
6004   freeAsmop (result, NULL, ic, TRUE);
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genCmpLt - less than comparisons                                */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genCmpLt (iCode * ic, iCode * ifx)
6012 {
6013   operand *left, *right, *result;
6014   sym_link *letype, *retype;
6015   int sign;
6016
6017   D (emitcode (";", "genCmpLt"));
6018
6019   left = IC_LEFT (ic);
6020   right = IC_RIGHT (ic);
6021   result = IC_RESULT (ic);
6022
6023   letype = getSpec (operandType (left));
6024   retype = getSpec (operandType (right));
6025   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6026            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6027   /* assign the asmops */
6028   aopOp (result, ic, TRUE);
6029   aopOp (left, ic, FALSE);
6030   aopOp (right, ic, FALSE);
6031
6032   genCmp (left, right, result, ifx, sign, ic);
6033
6034   freeAsmop (result, NULL, ic, TRUE);
6035 }
6036
6037 /*-----------------------------------------------------------------*/
6038 /* gencjneshort - compare and jump if not equal                    */
6039 /*-----------------------------------------------------------------*/
6040 static void
6041 gencjneshort (operand * left, operand * right, symbol * lbl)
6042 {
6043   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6044   int offset = 0;
6045   unsigned long lit = 0L;
6046
6047   D (emitcode (";", "gencjneshort"));
6048
6049   /* if the left side is a literal or
6050      if the right is in a pointer register and left
6051      is not */
6052   if ((AOP_TYPE (left) == AOP_LIT)  ||
6053       (AOP_TYPE (left) == AOP_IMMD) ||
6054       (AOP_TYPE (left) == AOP_DIR)  ||
6055       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6056     {
6057       operand *t = right;
6058       right = left;
6059       left = t;
6060     }
6061
6062   if (AOP_TYPE (right) == AOP_LIT)
6063     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6064
6065   /* if the right side is a literal then anything goes */
6066   if (AOP_TYPE (right) == AOP_LIT &&
6067       AOP_TYPE (left) != AOP_DIR  &&
6068       AOP_TYPE (left) != AOP_IMMD)
6069     {
6070       while (size--)
6071         {
6072           emitcode ("cjne", "%s,%s,%05d$",
6073                     aopGet (left, offset, FALSE, FALSE),
6074                     aopGet (right, offset, FALSE, FALSE),
6075                     lbl->key + 100);
6076           offset++;
6077         }
6078     }
6079
6080   /* if the right side is in a register or in direct space or
6081      if the left is a pointer register & right is not */
6082   else if (AOP_TYPE (right) == AOP_REG ||
6083            AOP_TYPE (right) == AOP_DIR ||
6084            AOP_TYPE (right) == AOP_LIT ||
6085            AOP_TYPE (right) == AOP_IMMD ||
6086            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6087            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6088     {
6089       while (size--)
6090         {
6091           MOVA (aopGet (left, offset, FALSE, FALSE));
6092           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6093               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6094             emitcode ("jnz", "%05d$", lbl->key + 100);
6095           else
6096             emitcode ("cjne", "a,%s,%05d$",
6097                       aopGet (right, offset, FALSE, TRUE),
6098                       lbl->key + 100);
6099           offset++;
6100         }
6101     }
6102   else
6103     {
6104       /* right is a pointer reg need both a & b */
6105       while (size--)
6106         {
6107           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6108           wassertl(!BINUSE, "B was in use");
6109           MOVB (aopGet (left, offset, FALSE, FALSE));
6110           MOVA (aopGet (right, offset, FALSE, FALSE));
6111           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6112           offset++;
6113         }
6114     }
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /* gencjne - compare and jump if not equal                         */
6119 /*-----------------------------------------------------------------*/
6120 static void
6121 gencjne (operand * left, operand * right, symbol * lbl)
6122 {
6123   symbol *tlbl = newiTempLabel (NULL);
6124
6125   D (emitcode (";", "gencjne"));
6126
6127   gencjneshort (left, right, lbl);
6128
6129   emitcode ("mov", "a,%s", one);
6130   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6131   emitLabel (lbl);
6132   emitcode ("clr", "a");
6133   emitLabel (tlbl);
6134 }
6135
6136 /*-----------------------------------------------------------------*/
6137 /* genCmpEq - generates code for equal to                          */
6138 /*-----------------------------------------------------------------*/
6139 static void
6140 genCmpEq (iCode * ic, iCode * ifx)
6141 {
6142   bool swappedLR = FALSE;
6143   operand *left, *right, *result;
6144
6145   D (emitcode (";", "genCmpEq"));
6146
6147   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6148   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6149   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6150
6151   /* if literal, literal on the right or
6152      if the right is in a pointer register and left
6153      is not */
6154   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6155       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6156     {
6157       operand *t = IC_RIGHT (ic);
6158       IC_RIGHT (ic) = IC_LEFT (ic);
6159       IC_LEFT (ic) = t;
6160       swappedLR = TRUE;
6161     }
6162
6163   if (ifx && !AOP_SIZE (result))
6164     {
6165       symbol *tlbl;
6166       /* if they are both bit variables */
6167       if (AOP_TYPE (left) == AOP_CRY &&
6168           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6169         {
6170           if (AOP_TYPE (right) == AOP_LIT)
6171             {
6172               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6173               if (lit == 0L)
6174                 {
6175                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6176                   emitcode ("cpl", "c");
6177                 }
6178               else if (lit == 1L)
6179                 {
6180                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6181                 }
6182               else
6183                 {
6184                   emitcode ("clr", "c");
6185                 }
6186               /* AOP_TYPE(right) == AOP_CRY */
6187             }
6188           else
6189             {
6190               symbol *lbl = newiTempLabel (NULL);
6191               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6192               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6193               emitcode ("cpl", "c");
6194               emitLabel (lbl);
6195             }
6196           /* if true label then we jump if condition
6197              supplied is true */
6198           tlbl = newiTempLabel (NULL);
6199           if (IC_TRUE (ifx))
6200             {
6201               emitcode ("jnc", "%05d$", tlbl->key + 100);
6202               freeForBranchAsmop (result);
6203               freeForBranchAsmop (right);
6204               freeForBranchAsmop (left);
6205               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6206             }
6207           else
6208             {
6209               emitcode ("jc", "%05d$", tlbl->key + 100);
6210               freeForBranchAsmop (result);
6211               freeForBranchAsmop (right);
6212               freeForBranchAsmop (left);
6213               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6214             }
6215           emitLabel (tlbl);
6216         }
6217       else
6218         {
6219           tlbl = newiTempLabel (NULL);
6220           gencjneshort (left, right, tlbl);
6221           if (IC_TRUE (ifx))
6222             {
6223               freeForBranchAsmop (result);
6224               freeForBranchAsmop (right);
6225               freeForBranchAsmop (left);
6226               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6227               emitLabel (tlbl);
6228             }
6229           else
6230             {
6231               symbol *lbl = newiTempLabel (NULL);
6232               emitcode ("sjmp", "%05d$", lbl->key + 100);
6233               emitLabel (tlbl);
6234               freeForBranchAsmop (result);
6235               freeForBranchAsmop (right);
6236               freeForBranchAsmop (left);
6237               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6238               emitLabel (lbl);
6239             }
6240         }
6241       /* mark the icode as generated */
6242       ifx->generated = 1;
6243       goto release;
6244     }
6245
6246   /* if they are both bit variables */
6247   if (AOP_TYPE (left) == AOP_CRY &&
6248       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6249     {
6250       if (AOP_TYPE (right) == AOP_LIT)
6251         {
6252           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6253           if (lit == 0L)
6254             {
6255               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6256               emitcode ("cpl", "c");
6257             }
6258           else if (lit == 1L)
6259             {
6260               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6261             }
6262           else
6263             {
6264               emitcode ("clr", "c");
6265             }
6266           /* AOP_TYPE(right) == AOP_CRY */
6267         }
6268       else
6269         {
6270           symbol *lbl = newiTempLabel (NULL);
6271           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6272           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6273           emitcode ("cpl", "c");
6274           emitLabel (lbl);
6275         }
6276       /* c = 1 if egal */
6277       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6278         {
6279           outBitC (result);
6280           goto release;
6281         }
6282       if (ifx)
6283         {
6284           genIfxJump (ifx, "c", left, right, result);
6285           goto release;
6286         }
6287       /* if the result is used in an arithmetic operation
6288          then put the result in place */
6289       outBitC (result);
6290     }
6291   else
6292     {
6293       gencjne (left, right, newiTempLabel (NULL));
6294       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6295         {
6296           aopPut (result, "a", 0);
6297           goto release;
6298         }
6299       if (ifx)
6300         {
6301           genIfxJump (ifx, "a", left, right, result);
6302           goto release;
6303         }
6304       /* if the result is used in an arithmetic operation
6305          then put the result in place */
6306       if (AOP_TYPE (result) != AOP_CRY)
6307         outAcc (result);
6308       /* leave the result in acc */
6309     }
6310
6311 release:
6312   freeAsmop (result, NULL, ic, TRUE);
6313   if (!swappedLR)
6314     {
6315       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6316       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6317     }
6318   else
6319     {
6320       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6321       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6322     }
6323 }
6324
6325 /*-----------------------------------------------------------------*/
6326 /* ifxForOp - returns the icode containing the ifx for operand     */
6327 /*-----------------------------------------------------------------*/
6328 static iCode *
6329 ifxForOp (operand * op, iCode * ic)
6330 {
6331   /* if true symbol then needs to be assigned */
6332   if (IS_TRUE_SYMOP (op))
6333     return NULL;
6334
6335   /* if this has register type condition and
6336      the next instruction is ifx with the same operand
6337      and live to of the operand is upto the ifx only then */
6338   if (ic->next &&
6339       ic->next->op == IFX &&
6340       IC_COND (ic->next)->key == op->key &&
6341       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6342     return ic->next;
6343
6344   return NULL;
6345 }
6346
6347 /*-----------------------------------------------------------------*/
6348 /* hasInc - operand is incremented before any other use            */
6349 /*-----------------------------------------------------------------*/
6350 static iCode *
6351 hasInc (operand *op, iCode *ic, int osize)
6352 {
6353   sym_link *type = operandType(op);
6354   sym_link *retype = getSpec (type);
6355   iCode *lic = ic->next;
6356   int isize ;
6357
6358   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6359   if (!IS_SYMOP(op)) return NULL;
6360
6361   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6362   if (IS_AGGREGATE(type->next)) return NULL;
6363   if (osize != (isize = getSize(type->next))) return NULL;
6364
6365   while (lic) {
6366     /* if operand of the form op = op + <sizeof *op> */
6367     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6368         isOperandEqual(IC_RESULT(lic),op) &&
6369         isOperandLiteral(IC_RIGHT(lic)) &&
6370         operandLitValue(IC_RIGHT(lic)) == isize) {
6371       return lic;
6372     }
6373     /* if the operand used or deffed */
6374     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6375       return NULL;
6376     }
6377     /* if GOTO or IFX */
6378     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6379     lic = lic->next;
6380   }
6381   return NULL;
6382 }
6383
6384 /*-----------------------------------------------------------------*/
6385 /* genAndOp - for && operation                                     */
6386 /*-----------------------------------------------------------------*/
6387 static void
6388 genAndOp (iCode * ic)
6389 {
6390   operand *left, *right, *result;
6391   symbol *tlbl;
6392
6393   D (emitcode (";", "genAndOp"));
6394
6395   /* note here that && operations that are in an
6396      if statement are taken away by backPatchLabels
6397      only those used in arthmetic operations remain */
6398   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6399   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6400   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6401
6402   /* if both are bit variables */
6403   if (AOP_TYPE (left) == AOP_CRY &&
6404       AOP_TYPE (right) == AOP_CRY)
6405     {
6406       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6407       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6408       outBitC (result);
6409     }
6410   else
6411     {
6412       tlbl = newiTempLabel (NULL);
6413       toBoolean (left);
6414       emitcode ("jz", "%05d$", tlbl->key + 100);
6415       toBoolean (right);
6416       emitLabel (tlbl);
6417       outBitAcc (result);
6418     }
6419
6420   freeAsmop (result, NULL, ic, TRUE);
6421   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6422   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6423 }
6424
6425
6426 /*-----------------------------------------------------------------*/
6427 /* genOrOp - for || operation                                      */
6428 /*-----------------------------------------------------------------*/
6429 static void
6430 genOrOp (iCode * ic)
6431 {
6432   operand *left, *right, *result;
6433   symbol *tlbl;
6434
6435   D (emitcode (";", "genOrOp"));
6436
6437   /* note here that || operations that are in an
6438      if statement are taken away by backPatchLabels
6439      only those used in arthmetic operations remain */
6440   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6441   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6442   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6443
6444   /* if both are bit variables */
6445   if (AOP_TYPE (left) == AOP_CRY &&
6446       AOP_TYPE (right) == AOP_CRY)
6447     {
6448       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6449       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6450       outBitC (result);
6451     }
6452   else
6453     {
6454       tlbl = newiTempLabel (NULL);
6455       toBoolean (left);
6456       emitcode ("jnz", "%05d$", tlbl->key + 100);
6457       toBoolean (right);
6458       emitLabel (tlbl);
6459       outBitAcc (result);
6460     }
6461
6462   freeAsmop (result, NULL, ic, TRUE);
6463   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6464   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6465 }
6466
6467 /*-----------------------------------------------------------------*/
6468 /* isLiteralBit - test if lit == 2^n                               */
6469 /*-----------------------------------------------------------------*/
6470 static int
6471 isLiteralBit (unsigned long lit)
6472 {
6473   unsigned long pw[32] =
6474   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6475    0x100L, 0x200L, 0x400L, 0x800L,
6476    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6477    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6478    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6479    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6480    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6481   int idx;
6482
6483   for (idx = 0; idx < 32; idx++)
6484     if (lit == pw[idx])
6485       return idx + 1;
6486   return 0;
6487 }
6488
6489 /*-----------------------------------------------------------------*/
6490 /* continueIfTrue -                                                */
6491 /*-----------------------------------------------------------------*/
6492 static void
6493 continueIfTrue (iCode * ic)
6494 {
6495   if (IC_TRUE (ic))
6496     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6497   ic->generated = 1;
6498 }
6499
6500 /*-----------------------------------------------------------------*/
6501 /* jmpIfTrue -                                                     */
6502 /*-----------------------------------------------------------------*/
6503 static void
6504 jumpIfTrue (iCode * ic)
6505 {
6506   if (!IC_TRUE (ic))
6507     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6508   ic->generated = 1;
6509 }
6510
6511 /*-----------------------------------------------------------------*/
6512 /* jmpTrueOrFalse -                                                */
6513 /*-----------------------------------------------------------------*/
6514 static void
6515 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6516 {
6517   // ugly but optimized by peephole
6518   if (IC_TRUE (ic))
6519     {
6520       symbol *nlbl = newiTempLabel (NULL);
6521       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6522       emitLabel (tlbl);
6523       freeForBranchAsmop (result);
6524       freeForBranchAsmop (right);
6525       freeForBranchAsmop (left);
6526       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6527       emitLabel (nlbl);
6528     }
6529   else
6530     {
6531       freeForBranchAsmop (result);
6532       freeForBranchAsmop (right);
6533       freeForBranchAsmop (left);
6534       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6535       emitLabel (tlbl);
6536     }
6537   ic->generated = 1;
6538 }
6539
6540 /*-----------------------------------------------------------------*/
6541 /* genAnd  - code for and                                          */
6542 /*-----------------------------------------------------------------*/
6543 static void
6544 genAnd (iCode * ic, iCode * ifx)
6545 {
6546   operand *left, *right, *result;
6547   int size, offset = 0;
6548   unsigned long lit = 0L;
6549   int bytelit = 0;
6550   char buffer[10];
6551
6552   D (emitcode (";", "genAnd"));
6553
6554   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6555   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6556   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6557
6558 #ifdef DEBUG_TYPE
6559   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6560             AOP_TYPE (result),
6561             AOP_TYPE (left), AOP_TYPE (right));
6562   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6563             AOP_SIZE (result),
6564             AOP_SIZE (left), AOP_SIZE (right));
6565 #endif
6566
6567   /* if left is a literal & right is not then exchange them */
6568   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6569       AOP_NEEDSACC (left))
6570     {
6571       operand *tmp = right;
6572       right = left;
6573       left = tmp;
6574     }
6575
6576   /* if result = right then exchange left and right */
6577   if (sameRegs (AOP (result), AOP (right)))
6578     {
6579       operand *tmp = right;
6580       right = left;
6581       left = tmp;
6582     }
6583
6584   /* if right is bit then exchange them */
6585   if (AOP_TYPE (right) == AOP_CRY &&
6586       AOP_TYPE (left) != AOP_CRY)
6587     {
6588       operand *tmp = right;
6589       right = left;
6590       left = tmp;
6591     }
6592   if (AOP_TYPE (right) == AOP_LIT)
6593     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6594
6595   size = AOP_SIZE (result);
6596
6597   // if(bit & yy)
6598   // result = bit & yy;
6599   if (AOP_TYPE (left) == AOP_CRY)
6600     {
6601       // c = bit & literal;
6602       if (AOP_TYPE (right) == AOP_LIT)
6603         {
6604           if (lit & 1)
6605             {
6606               if (size && sameRegs (AOP (result), AOP (left)))
6607                 // no change
6608                 goto release;
6609               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6610             }
6611           else
6612             {
6613               // bit(result) = 0;
6614               if (size && (AOP_TYPE (result) == AOP_CRY))
6615                 {
6616                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6617                   goto release;
6618                 }
6619               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6620                 {
6621                   jumpIfTrue (ifx);
6622                   goto release;
6623                 }
6624               emitcode ("clr", "c");
6625             }
6626         }
6627       else
6628         {
6629           if (AOP_TYPE (right) == AOP_CRY)
6630             {
6631               // c = bit & bit;
6632               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6633               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6634             }
6635           else
6636             {
6637               // c = bit & val;
6638               MOVA (aopGet (right, 0, FALSE, FALSE));
6639               // c = lsb
6640               emitcode ("rrc", "a");
6641               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6642             }
6643         }
6644       // bit = c
6645       // val = c
6646       if (size)
6647         outBitC (result);
6648       // if(bit & ...)
6649       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6650         genIfxJump (ifx, "c", left, right, result);
6651       goto release;
6652     }
6653
6654   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6655   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6656   if ((AOP_TYPE (right) == AOP_LIT) &&
6657       (AOP_TYPE (result) == AOP_CRY) &&
6658       (AOP_TYPE (left) != AOP_CRY))
6659     {
6660       int posbit = isLiteralBit (lit);
6661       /* left &  2^n */
6662       if (posbit)
6663         {
6664           posbit--;
6665           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6666           // bit = left & 2^n
6667           if (size)
6668             {
6669               switch (posbit & 0x07)
6670                 {
6671                   case 0: emitcode ("rrc", "a");
6672                           break;
6673                   case 7: emitcode ("rlc", "a");
6674                           break;
6675                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6676                           break;
6677                 }
6678             }
6679           // if(left &  2^n)
6680           else
6681             {
6682               if (ifx)
6683                 {
6684                   SNPRINTF (buffer, sizeof(buffer),
6685                             "acc.%d", posbit & 0x07);
6686                   genIfxJump (ifx, buffer, left, right, result);
6687                 }
6688               else
6689                 {// what is this case? just found it in ds390/gen.c
6690                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6691                 }
6692               goto release;
6693             }
6694         }
6695       else
6696         {
6697           symbol *tlbl = newiTempLabel (NULL);
6698           int sizel = AOP_SIZE (left);
6699           if (size)
6700             emitcode ("setb", "c");
6701           while (sizel--)
6702             {
6703               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6704                 {
6705                   MOVA (aopGet (left, offset, FALSE, FALSE));
6706                   // byte ==  2^n ?
6707                   if ((posbit = isLiteralBit (bytelit)) != 0)
6708                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6709                   else
6710                     {
6711                       if (bytelit != 0x0FFL)
6712                         emitcode ("anl", "a,%s",
6713                                   aopGet (right, offset, FALSE, TRUE));
6714                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6715                     }
6716                 }
6717               offset++;
6718             }
6719           // bit = left & literal
6720           if (size)
6721             {
6722               emitcode ("clr", "c");
6723               emitLabel (tlbl);
6724             }
6725           // if(left & literal)
6726           else
6727             {
6728               if (ifx)
6729                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6730               else
6731                 emitLabel (tlbl);
6732               goto release;
6733             }
6734         }
6735       outBitC (result);
6736       goto release;
6737     }
6738
6739   /* if left is same as result */
6740   if (sameRegs (AOP (result), AOP (left)))
6741     {
6742       for (; size--; offset++)
6743         {
6744           if (AOP_TYPE (right) == AOP_LIT)
6745             {
6746               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6747               if (bytelit == 0x0FF)
6748                 {
6749                   /* dummy read of volatile operand */
6750                   if (isOperandVolatile (left, FALSE))
6751                     MOVA (aopGet (left, offset, FALSE, FALSE));
6752                   else
6753                     continue;
6754                 }
6755               else if (bytelit == 0)
6756                 {
6757                   aopPut (result, zero, offset);
6758                 }
6759               else if (IS_AOP_PREG (result))
6760                 {
6761                   MOVA (aopGet (left, offset, FALSE, TRUE));
6762                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6763                   aopPut (result, "a", offset);
6764                 }
6765               else
6766                 emitcode ("anl", "%s,%s",
6767                           aopGet (left, offset, FALSE, TRUE),
6768                           aopGet (right, offset, FALSE, FALSE));
6769             }
6770           else
6771             {
6772               if (AOP_TYPE (left) == AOP_ACC)
6773                 {
6774                   if (offset)
6775                     emitcode("mov", "a,b");
6776                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6777                 }
6778               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6779                 {
6780                   MOVB (aopGet (left, offset, FALSE, FALSE));
6781                   MOVA (aopGet (right, offset, FALSE, FALSE));
6782                   emitcode ("anl", "a,b");
6783                   aopPut (result, "a", offset);
6784                 }
6785               else if (aopGetUsesAcc (left, offset))
6786                 {
6787                   MOVA (aopGet (left, offset, FALSE, FALSE));
6788                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6789                   aopPut (result, "a", offset);
6790                 }
6791               else
6792                 {
6793                   MOVA (aopGet (right, offset, FALSE, FALSE));
6794                   if (IS_AOP_PREG (result))
6795                     {
6796                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6797                       aopPut (result, "a", offset);
6798                     }
6799                   else
6800                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6801                 }
6802             }
6803         }
6804     }
6805   else
6806     {
6807       // left & result in different registers
6808       if (AOP_TYPE (result) == AOP_CRY)
6809         {
6810           // result = bit
6811           // if(size), result in bit
6812           // if(!size && ifx), conditional oper: if(left & right)
6813           symbol *tlbl = newiTempLabel (NULL);
6814           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6815           if (size)
6816             emitcode ("setb", "c");
6817           while (sizer--)
6818             {
6819               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6820                   && AOP_TYPE(left)==AOP_ACC)
6821                 {
6822                   if (offset)
6823                     emitcode("mov", "a,b");
6824                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6825                 }
6826               else if (AOP_TYPE(left)==AOP_ACC)
6827                 {
6828                   if (!offset)
6829                     {
6830                       bool pushedB = pushB ();
6831                       emitcode("mov", "b,a");
6832                       MOVA (aopGet (right, offset, FALSE, FALSE));
6833                       emitcode("anl", "a,b");
6834                       popB (pushedB);
6835                     }
6836                   else
6837                     {
6838                       MOVA (aopGet (right, offset, FALSE, FALSE));
6839                       emitcode("anl", "a,b");
6840                     }
6841                 }
6842               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6843                 {
6844                   MOVB (aopGet (left, offset, FALSE, FALSE));
6845                   MOVA (aopGet (right, offset, FALSE, FALSE));
6846                   emitcode ("anl", "a,b");
6847                 }
6848               else if (aopGetUsesAcc (left, offset))
6849                 {
6850                   MOVA (aopGet (left, offset, FALSE, FALSE));
6851                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6852                     }
6853               else
6854                 {
6855                   MOVA (aopGet (right, offset, FALSE, FALSE));
6856                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6857                 }
6858
6859               emitcode ("jnz", "%05d$", tlbl->key + 100);
6860               offset++;
6861             }
6862           if (size)
6863             {
6864               CLRC;
6865               emitLabel (tlbl);
6866               outBitC (result);
6867             }
6868           else if (ifx)
6869             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6870           else
6871             emitLabel (tlbl);
6872         }
6873       else
6874         {
6875           for (; (size--); offset++)
6876             {
6877               // normal case
6878               // result = left & right
6879               if (AOP_TYPE (right) == AOP_LIT)
6880                 {
6881                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6882                   if (bytelit == 0x0FF)
6883                     {
6884                       aopPut (result,
6885                               aopGet (left, offset, FALSE, FALSE),
6886                               offset);
6887                       continue;
6888                     }
6889                   else if (bytelit == 0)
6890                     {
6891                       /* dummy read of volatile operand */
6892                       if (isOperandVolatile (left, FALSE))
6893                         MOVA (aopGet (left, offset, FALSE, FALSE));
6894                       aopPut (result, zero, offset);
6895                       continue;
6896                     }
6897                   else if (AOP_TYPE (left) == AOP_ACC)
6898                     {
6899                       if (!offset)
6900                         {
6901                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6902                           aopPut (result, "a", offset);
6903                           continue;
6904                         }
6905                       else
6906                         {
6907                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6908                           aopPut (result, "b", offset);
6909                           continue;
6910                         }
6911                     }
6912                 }
6913               // faster than result <- left, anl result,right
6914               // and better if result is SFR
6915               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6916                   && AOP_TYPE(left)==AOP_ACC)
6917                 {
6918                   if (offset)
6919                     emitcode("mov", "a,b");
6920                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6921                 }
6922               else if (AOP_TYPE(left)==AOP_ACC)
6923                 {
6924                   if (!offset)
6925                     {
6926                       bool pushedB = pushB ();
6927                       emitcode("mov", "b,a");
6928                       MOVA (aopGet (right, offset, FALSE, FALSE));
6929                       emitcode("anl", "a,b");
6930                       popB (pushedB);
6931                     }
6932                   else
6933                     {
6934                       MOVA (aopGet (right, offset, FALSE, FALSE));
6935                       emitcode("anl", "a,b");
6936                     }
6937                 }
6938               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6939                 {
6940                   MOVB (aopGet (left, offset, FALSE, FALSE));
6941                   MOVA (aopGet (right, offset, FALSE, FALSE));
6942                   emitcode ("anl", "a,b");
6943                 }
6944               else if (aopGetUsesAcc (left, offset))
6945                 {
6946                   MOVA (aopGet (left, offset, FALSE, FALSE));
6947                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6948                 }
6949               else
6950                 {
6951                   MOVA (aopGet (right, offset, FALSE, FALSE));
6952                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6953                 }
6954               aopPut (result, "a", offset);
6955             }
6956         }
6957     }
6958
6959 release:
6960   freeAsmop (result, NULL, ic, TRUE);
6961   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6962   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6963 }
6964
6965 /*-----------------------------------------------------------------*/
6966 /* genOr  - code for or                                            */
6967 /*-----------------------------------------------------------------*/
6968 static void
6969 genOr (iCode * ic, iCode * ifx)
6970 {
6971   operand *left, *right, *result;
6972   int size, offset = 0;
6973   unsigned long lit = 0L;
6974   int bytelit = 0;
6975
6976   D (emitcode (";", "genOr"));
6977
6978   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6979   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6980   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6981
6982 #ifdef DEBUG_TYPE
6983   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6984             AOP_TYPE (result),
6985             AOP_TYPE (left), AOP_TYPE (right));
6986   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6987             AOP_SIZE (result),
6988             AOP_SIZE (left), AOP_SIZE (right));
6989 #endif
6990
6991   /* if left is a literal & right is not then exchange them */
6992   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6993       AOP_NEEDSACC (left))
6994     {
6995       operand *tmp = right;
6996       right = left;
6997       left = tmp;
6998     }
6999
7000   /* if result = right then exchange them */
7001   if (sameRegs (AOP (result), AOP (right)))
7002     {
7003       operand *tmp = right;
7004       right = left;
7005       left = tmp;
7006     }
7007
7008   /* if right is bit then exchange them */
7009   if (AOP_TYPE (right) == AOP_CRY &&
7010       AOP_TYPE (left) != AOP_CRY)
7011     {
7012       operand *tmp = right;
7013       right = left;
7014       left = tmp;
7015     }
7016   if (AOP_TYPE (right) == AOP_LIT)
7017     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7018
7019   size = AOP_SIZE (result);
7020
7021   // if(bit | yy)
7022   // xx = bit | yy;
7023   if (AOP_TYPE (left) == AOP_CRY)
7024     {
7025       if (AOP_TYPE (right) == AOP_LIT)
7026         {
7027           // c = bit | literal;
7028           if (lit)
7029             {
7030               // lit != 0 => result = 1
7031               if (AOP_TYPE (result) == AOP_CRY)
7032                 {
7033                   if (size)
7034                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7035                   else if (ifx)
7036                     continueIfTrue (ifx);
7037                   goto release;
7038                 }
7039               emitcode ("setb", "c");
7040             }
7041           else
7042             {
7043               // lit == 0 => result = left
7044               if (size && sameRegs (AOP (result), AOP (left)))
7045                 goto release;
7046               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7047             }
7048         }
7049       else
7050         {
7051           if (AOP_TYPE (right) == AOP_CRY)
7052             {
7053               // c = bit | bit;
7054               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7055               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7056             }
7057           else
7058             {
7059               // c = bit | val;
7060               symbol *tlbl = newiTempLabel (NULL);
7061               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7062                 emitcode ("setb", "c");
7063               emitcode ("jb", "%s,%05d$",
7064                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7065               toBoolean (right);
7066               emitcode ("jnz", "%05d$", tlbl->key + 100);
7067               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7068                 {
7069                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7070                   goto release;
7071                 }
7072               else
7073                 {
7074                   CLRC;
7075                   emitLabel (tlbl);
7076                 }
7077             }
7078         }
7079       // bit = c
7080       // val = c
7081       if (size)
7082         outBitC (result);
7083       // if(bit | ...)
7084       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7085         genIfxJump (ifx, "c", left, right, result);
7086       goto release;
7087     }
7088
7089   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7090   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7091   if ((AOP_TYPE (right) == AOP_LIT) &&
7092       (AOP_TYPE (result) == AOP_CRY) &&
7093       (AOP_TYPE (left) != AOP_CRY))
7094     {
7095       if (lit)
7096         {
7097           // result = 1
7098           if (size)
7099             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7100           else
7101             continueIfTrue (ifx);
7102           goto release;
7103         }
7104       else
7105         {
7106           // lit = 0, result = boolean(left)
7107           if (size)
7108             emitcode ("setb", "c");
7109           toBoolean (right);
7110           if (size)
7111             {
7112               symbol *tlbl = newiTempLabel (NULL);
7113               emitcode ("jnz", "%05d$", tlbl->key + 100);
7114               CLRC;
7115               emitLabel (tlbl);
7116             }
7117           else
7118             {
7119               genIfxJump (ifx, "a", left, right, result);
7120               goto release;
7121             }
7122         }
7123       outBitC (result);
7124       goto release;
7125     }
7126
7127   /* if left is same as result */
7128   if (sameRegs (AOP (result), AOP (left)))
7129     {
7130       for (; size--; offset++)
7131         {
7132           if (AOP_TYPE (right) == AOP_LIT)
7133             {
7134               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7135               if (bytelit == 0)
7136                 {
7137                   /* dummy read of volatile operand */
7138                   if (isOperandVolatile (left, FALSE))
7139                     MOVA (aopGet (left, offset, FALSE, FALSE));
7140                   else
7141                     continue;
7142                 }
7143               else if (bytelit == 0x0FF)
7144                 {
7145                   aopPut (result, "#0xFF", offset);
7146                 }
7147               else if (IS_AOP_PREG (left))
7148                 {
7149                   MOVA (aopGet (left, offset, FALSE, TRUE));
7150                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7151                   aopPut (result, "a", offset);
7152                 }
7153               else
7154                 {
7155                   emitcode ("orl", "%s,%s",
7156                             aopGet (left, offset, FALSE, TRUE),
7157                             aopGet (right, offset, FALSE, FALSE));
7158                 }
7159             }
7160           else
7161             {
7162               if (AOP_TYPE (left) == AOP_ACC)
7163                 {
7164                   if (offset)
7165                     emitcode("mov", "a,b");
7166                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7167                 }
7168               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7169                 {
7170                   MOVB (aopGet (left, offset, FALSE, FALSE));
7171                   MOVA (aopGet (right, offset, FALSE, FALSE));
7172                   emitcode ("orl", "a,b");
7173                   aopPut (result, "a", offset);
7174                 }
7175               else if (aopGetUsesAcc (left, offset))
7176                 {
7177                   MOVA (aopGet (left, offset, FALSE, FALSE));
7178                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7179                   aopPut (result, "a", offset);
7180                 }
7181               else
7182                 {
7183                   MOVA (aopGet (right, offset, FALSE, FALSE));
7184                   if (IS_AOP_PREG (left))
7185                     {
7186                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7187                       aopPut (result, "a", offset);
7188                     }
7189                   else
7190                     {
7191                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7192                     }
7193                 }
7194             }
7195         }
7196     }
7197   else
7198     {
7199       // left & result in different registers
7200       if (AOP_TYPE (result) == AOP_CRY)
7201         {
7202           // result = bit
7203           // if(size), result in bit
7204           // if(!size && ifx), conditional oper: if(left | right)
7205           symbol *tlbl = newiTempLabel (NULL);
7206           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7207           if (size)
7208             emitcode ("setb", "c");
7209           while (sizer--)
7210             {
7211               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7212                   && AOP_TYPE(left)==AOP_ACC)
7213                 {
7214                   if (offset)
7215                     emitcode("mov", "a,b");
7216                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7217                 }
7218               else if (AOP_TYPE(left)==AOP_ACC)
7219                 {
7220                   if (!offset)
7221                     {
7222                       bool pushedB = pushB ();
7223                       emitcode("mov", "b,a");
7224                       MOVA (aopGet (right, offset, FALSE, FALSE));
7225                       emitcode("orl", "a,b");
7226                       popB (pushedB);
7227                     }
7228                   else
7229                     {
7230                       MOVA (aopGet (right, offset, FALSE, FALSE));
7231                       emitcode("orl", "a,b");
7232                     }
7233                 }
7234               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7235                 {
7236                   MOVB (aopGet (left, offset, FALSE, FALSE));
7237                   MOVA (aopGet (right, offset, FALSE, FALSE));
7238                   emitcode ("orl", "a,b");
7239                 }
7240               else if (aopGetUsesAcc (left, offset))
7241                 {
7242                   MOVA (aopGet (left, offset, FALSE, FALSE));
7243                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7244                 }
7245               else
7246                 {
7247                   MOVA (aopGet (right, offset, FALSE, FALSE));
7248                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7249               }
7250
7251               emitcode ("jnz", "%05d$", tlbl->key + 100);
7252               offset++;
7253             }
7254           if (size)
7255             {
7256               CLRC;
7257               emitLabel (tlbl);
7258               outBitC (result);
7259             }
7260           else if (ifx)
7261             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7262           else
7263             emitLabel (tlbl);
7264         }
7265       else
7266         {
7267           for (; (size--); offset++)
7268             {
7269               // normal case
7270               // result = left | right
7271               if (AOP_TYPE (right) == AOP_LIT)
7272                 {
7273                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7274                   if (bytelit == 0)
7275                     {
7276                       aopPut (result,
7277                               aopGet (left, offset, FALSE, FALSE),
7278                               offset);
7279                       continue;
7280                     }
7281                   else if (bytelit == 0x0FF)
7282                     {
7283                       /* dummy read of volatile operand */
7284                       if (isOperandVolatile (left, FALSE))
7285                         MOVA (aopGet (left, offset, FALSE, FALSE));
7286                       aopPut (result, "#0xFF", offset);
7287                       continue;
7288                     }
7289                 }
7290               // faster than result <- left, orl result,right
7291               // and better if result is SFR
7292               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7293                   && AOP_TYPE(left)==AOP_ACC)
7294                 {
7295                   if (offset)
7296                     emitcode("mov", "a,b");
7297                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7298                 }
7299               else if (AOP_TYPE(left)==AOP_ACC)
7300                 {
7301                   if (!offset)
7302                     {
7303                       bool pushedB = pushB ();
7304                       emitcode("mov", "b,a");
7305                       MOVA (aopGet (right, offset, FALSE, FALSE));
7306                       emitcode("orl", "a,b");
7307                       popB (pushedB);
7308                     }
7309                   else
7310                     {
7311                       MOVA (aopGet (right, offset, FALSE, FALSE));
7312                       emitcode("orl", "a,b");
7313                     }
7314                 }
7315               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7316                 {
7317                   MOVB (aopGet (left, offset, FALSE, FALSE));
7318                   MOVA (aopGet (right, offset, FALSE, FALSE));
7319                   emitcode ("orl", "a,b");
7320                 }
7321               else if (aopGetUsesAcc (left, offset))
7322                 {
7323                   MOVA (aopGet (left, offset, FALSE, FALSE));
7324                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7325                 }
7326               else
7327                 {
7328                   MOVA (aopGet (right, offset, FALSE, FALSE));
7329                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7330                 }
7331               aopPut (result, "a", offset);
7332             }
7333         }
7334     }
7335
7336 release:
7337   freeAsmop (result, NULL, ic, TRUE);
7338   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7339   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7340 }
7341
7342 /*-----------------------------------------------------------------*/
7343 /* genXor - code for xclusive or                                   */
7344 /*-----------------------------------------------------------------*/
7345 static void
7346 genXor (iCode * ic, iCode * ifx)
7347 {
7348   operand *left, *right, *result;
7349   int size, offset = 0;
7350   unsigned long lit = 0L;
7351   int bytelit = 0;
7352
7353   D (emitcode (";", "genXor"));
7354
7355   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7356   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7357   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7358
7359 #ifdef DEBUG_TYPE
7360   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7361             AOP_TYPE (result),
7362             AOP_TYPE (left), AOP_TYPE (right));
7363   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7364             AOP_SIZE (result),
7365             AOP_SIZE (left), AOP_SIZE (right));
7366 #endif
7367
7368   /* if left is a literal & right is not ||
7369      if left needs acc & right does not */
7370   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7371       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7372     {
7373       operand *tmp = right;
7374       right = left;
7375       left = tmp;
7376     }
7377
7378   /* if result = right then exchange them */
7379   if (sameRegs (AOP (result), AOP (right)))
7380     {
7381       operand *tmp = right;
7382       right = left;
7383       left = tmp;
7384     }
7385
7386   /* if right is bit then exchange them */
7387   if (AOP_TYPE (right) == AOP_CRY &&
7388       AOP_TYPE (left) != AOP_CRY)
7389     {
7390       operand *tmp = right;
7391       right = left;
7392       left = tmp;
7393     }
7394
7395   if (AOP_TYPE (right) == AOP_LIT)
7396     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7397
7398   size = AOP_SIZE (result);
7399
7400   // if(bit ^ yy)
7401   // xx = bit ^ yy;
7402   if (AOP_TYPE (left) == AOP_CRY)
7403     {
7404       if (AOP_TYPE (right) == AOP_LIT)
7405         {
7406           // c = bit & literal;
7407           if (lit >> 1)
7408             {
7409               // lit>>1  != 0 => result = 1
7410               if (AOP_TYPE (result) == AOP_CRY)
7411                 {
7412                   if (size)
7413                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7414                   else if (ifx)
7415                     continueIfTrue (ifx);
7416                   goto release;
7417                 }
7418               emitcode ("setb", "c");
7419             }
7420           else
7421             {
7422               // lit == (0 or 1)
7423               if (lit == 0)
7424                 {
7425                   // lit == 0, result = left
7426                   if (size && sameRegs (AOP (result), AOP (left)))
7427                     goto release;
7428                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7429                 }
7430               else
7431                 {
7432                   // lit == 1, result = not(left)
7433                   if (size && sameRegs (AOP (result), AOP (left)))
7434                     {
7435                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7436                       goto release;
7437                     }
7438                   else
7439                     {
7440                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7441                       emitcode ("cpl", "c");
7442                     }
7443                 }
7444             }
7445         }
7446       else
7447         {
7448           // right != literal
7449           symbol *tlbl = newiTempLabel (NULL);
7450           if (AOP_TYPE (right) == AOP_CRY)
7451             {
7452               // c = bit ^ bit;
7453               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7454             }
7455           else
7456             {
7457               int sizer = AOP_SIZE (right);
7458               // c = bit ^ val
7459               // if val>>1 != 0, result = 1
7460               emitcode ("setb", "c");
7461               while (sizer)
7462                 {
7463                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7464                   if (sizer == 1)
7465                     // test the msb of the lsb
7466                     emitcode ("anl", "a,#0xfe");
7467                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7468                   sizer--;
7469                 }
7470               // val = (0,1)
7471               emitcode ("rrc", "a");
7472             }
7473           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7474           emitcode ("cpl", "c");
7475           emitLabel (tlbl);
7476         }
7477       // bit = c
7478       // val = c
7479       if (size)
7480         outBitC (result);
7481       // if(bit ^ ...)
7482       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7483         genIfxJump (ifx, "c", left, right, result);
7484       goto release;
7485     }
7486
7487   /* if left is same as result */
7488   if (sameRegs (AOP (result), AOP (left)))
7489     {
7490       for (; size--; offset++)
7491         {
7492           if (AOP_TYPE (right) == AOP_LIT)
7493             {
7494               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7495               if (bytelit == 0)
7496                 {
7497                   /* dummy read of volatile operand */
7498                   if (isOperandVolatile (left, FALSE))
7499                     MOVA (aopGet (left, offset, FALSE, FALSE));
7500                   else
7501                     continue;
7502                 }
7503               else if (IS_AOP_PREG (left))
7504                 {
7505                   MOVA (aopGet (left, offset, FALSE, TRUE));
7506                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7507                   aopPut (result, "a", offset);
7508                 }
7509               else
7510                 {
7511                   emitcode ("xrl", "%s,%s",
7512                             aopGet (left, offset, FALSE, TRUE),
7513                             aopGet (right, offset, FALSE, FALSE));
7514                 }
7515             }
7516           else
7517             {
7518               if (AOP_TYPE (left) == AOP_ACC)
7519                 {
7520                   if (offset)
7521                     emitcode("mov", "a,b");
7522                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7523                 }
7524               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7525                 {
7526                   MOVB (aopGet (left, offset, FALSE, FALSE));
7527                   MOVA (aopGet (right, offset, FALSE, FALSE));
7528                   emitcode ("xrl", "a,b");
7529                   aopPut (result, "a", offset);
7530                 }
7531               else if (aopGetUsesAcc (left, offset))
7532                 {
7533                   MOVA (aopGet (left, offset, FALSE, FALSE));
7534                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7535                   aopPut (result, "a", offset);
7536                 }
7537               else
7538                 {
7539                   MOVA (aopGet (right, offset, FALSE, FALSE));
7540                   if (IS_AOP_PREG (left))
7541                     {
7542                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7543                       aopPut (result, "a", offset);
7544                     }
7545                   else
7546                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7547                 }
7548             }
7549         }
7550     }
7551   else
7552     {
7553       // left & result in different registers
7554       if (AOP_TYPE (result) == AOP_CRY)
7555         {
7556           // result = bit
7557           // if(size), result in bit
7558           // if(!size && ifx), conditional oper: if(left ^ right)
7559           symbol *tlbl = newiTempLabel (NULL);
7560           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7561
7562           if (size)
7563             emitcode ("setb", "c");
7564           while (sizer--)
7565             {
7566               if ((AOP_TYPE (right) == AOP_LIT) &&
7567                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7568                 {
7569                   MOVA (aopGet (left, offset, FALSE, FALSE));
7570                 }
7571               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7572                   && AOP_TYPE(left)==AOP_ACC)
7573                 {
7574                   if (offset)
7575                     emitcode("mov", "a,b");
7576                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7577                 }
7578               else if (AOP_TYPE(left)==AOP_ACC)
7579                 {
7580                   if (!offset)
7581                     {
7582                       bool pushedB = pushB ();
7583                       emitcode("mov", "b,a");
7584                       MOVA (aopGet (right, offset, FALSE, FALSE));
7585                       emitcode("xrl", "a,b");
7586                       popB (pushedB);
7587                     }
7588                   else
7589                     {
7590                       MOVA (aopGet (right, offset, FALSE, FALSE));
7591                       emitcode("xrl", "a,b");
7592                     }
7593                 }
7594               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7595                 {
7596                   MOVB (aopGet (left, offset, FALSE, FALSE));
7597                   MOVA (aopGet (right, offset, FALSE, FALSE));
7598                   emitcode ("xrl", "a,b");
7599                 }
7600               else if (aopGetUsesAcc (left, offset))
7601                 {
7602                   MOVA (aopGet (left, offset, FALSE, FALSE));
7603                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7604                 }
7605               else
7606                 {
7607                   MOVA (aopGet (right, offset, FALSE, FALSE));
7608                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7609                 }
7610
7611               emitcode ("jnz", "%05d$", tlbl->key + 100);
7612               offset++;
7613             }
7614           if (size)
7615             {
7616               CLRC;
7617               emitLabel (tlbl);
7618               outBitC (result);
7619             }
7620           else if (ifx)
7621             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7622         }
7623       else
7624         {
7625           for (; (size--); offset++)
7626             {
7627               // normal case
7628               // result = left ^ right
7629               if (AOP_TYPE (right) == AOP_LIT)
7630                 {
7631                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7632                   if (bytelit == 0)
7633                     {
7634                       aopPut (result,
7635                               aopGet (left, offset, FALSE, FALSE),
7636                               offset);
7637                       continue;
7638                     }
7639                 }
7640               // faster than result <- left, xrl result,right
7641               // and better if result is SFR
7642               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7643                   && AOP_TYPE(left)==AOP_ACC)
7644                 {
7645                   if (offset)
7646                     emitcode("mov", "a,b");
7647                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7648                 }
7649               else if (AOP_TYPE(left)==AOP_ACC)
7650                 {
7651                   if (!offset)
7652                     {
7653                       bool pushedB = pushB ();
7654                       emitcode("mov", "b,a");
7655                       MOVA (aopGet (right, offset, FALSE, FALSE));
7656                       emitcode("xrl", "a,b");
7657                       popB (pushedB);
7658                     }
7659                   else
7660                     {
7661                       MOVA (aopGet (right, offset, FALSE, FALSE));
7662                       emitcode("xrl", "a,b");
7663                     }
7664                 }
7665               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7666                 {
7667                   MOVB (aopGet (left, offset, FALSE, FALSE));
7668                   MOVA (aopGet (right, offset, FALSE, FALSE));
7669                   emitcode ("xrl", "a,b");
7670                 }
7671               else if (aopGetUsesAcc (left, offset))
7672                 {
7673                   MOVA (aopGet (left, offset, FALSE, FALSE));
7674                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7675                 }
7676               else
7677                 {
7678                   MOVA (aopGet (right, offset, FALSE, FALSE));
7679                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7680                 }
7681               aopPut (result, "a", offset);
7682             }
7683         }
7684     }
7685
7686 release:
7687   freeAsmop (result, NULL, ic, TRUE);
7688   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7689   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7690 }
7691
7692 /*-----------------------------------------------------------------*/
7693 /* genInline - write the inline code out                           */
7694 /*-----------------------------------------------------------------*/
7695 static void
7696 genInline (iCode * ic)
7697 {
7698   char *buffer, *bp, *bp1;
7699
7700   D (emitcode (";", "genInline"));
7701
7702   _G.inLine += (!options.asmpeep);
7703
7704   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7705
7706   /* emit each line as a code */
7707   while (*bp)
7708     {
7709       if (*bp == '\n')
7710         {
7711           *bp++ = '\0';
7712           emitcode (bp1, "");
7713           bp1 = bp;
7714         }
7715       else
7716         {
7717           /* Add \n for labels, not dirs such as c:\mydir */
7718           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7719             {
7720               bp++;
7721               *bp = '\0';
7722               bp++;
7723               emitcode (bp1, "");
7724               bp1 = bp;
7725             }
7726           else
7727             bp++;
7728         }
7729     }
7730   if (bp1 != bp)
7731     emitcode (bp1, "");
7732   /*     emitcode("",buffer); */
7733   _G.inLine -= (!options.asmpeep);
7734 }
7735
7736 /*-----------------------------------------------------------------*/
7737 /* genRRC - rotate right with carry                                */
7738 /*-----------------------------------------------------------------*/
7739 static void
7740 genRRC (iCode * ic)
7741 {
7742   operand *left, *result;
7743   int size, offset;
7744   char *l;
7745
7746   D (emitcode (";", "genRRC"));
7747
7748   /* rotate right with carry */
7749   left = IC_LEFT (ic);
7750   result = IC_RESULT (ic);
7751   aopOp (left, ic, FALSE);
7752   aopOp (result, ic, FALSE);
7753
7754   /* move it to the result */
7755   size = AOP_SIZE (result);
7756   offset = size - 1;
7757   if (size == 1) { /* special case for 1 byte */
7758       l = aopGet (left, offset, FALSE, FALSE);
7759       MOVA (l);
7760       emitcode ("rr", "a");
7761       goto release;
7762   }
7763   /* no need to clear carry, bit7 will be written later */
7764   while (size--)
7765     {
7766       l = aopGet (left, offset, FALSE, FALSE);
7767       MOVA (l);
7768       emitcode ("rrc", "a");
7769       if (AOP_SIZE (result) > 1)
7770         aopPut (result, "a", offset--);
7771     }
7772   /* now we need to put the carry into the
7773      highest order byte of the result */
7774   if (AOP_SIZE (result) > 1)
7775     {
7776       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7777       MOVA (l);
7778     }
7779   emitcode ("mov", "acc.7,c");
7780  release:
7781   aopPut (result, "a", AOP_SIZE (result) - 1);
7782   freeAsmop (result, NULL, ic, TRUE);
7783   freeAsmop (left, NULL, ic, TRUE);
7784 }
7785
7786 /*-----------------------------------------------------------------*/
7787 /* genRLC - generate code for rotate left with carry               */
7788 /*-----------------------------------------------------------------*/
7789 static void
7790 genRLC (iCode * ic)
7791 {
7792   operand *left, *result;
7793   int size, offset;
7794   char *l;
7795
7796   D (emitcode (";", "genRLC"));
7797
7798   /* rotate right with carry */
7799   left = IC_LEFT (ic);
7800   result = IC_RESULT (ic);
7801   aopOp (left, ic, FALSE);
7802   aopOp (result, ic, FALSE);
7803
7804   /* move it to the result */
7805   size = AOP_SIZE (result);
7806   offset = 0;
7807   if (size--)
7808     {
7809       l = aopGet (left, offset, FALSE, FALSE);
7810       MOVA (l);
7811       if (size == 0) { /* special case for 1 byte */
7812               emitcode("rl","a");
7813               goto release;
7814       }
7815       emitcode("rlc","a"); /* bit0 will be written later */
7816       if (AOP_SIZE (result) > 1)
7817         {
7818           aopPut (result, "a", offset++);
7819         }
7820
7821       while (size--)
7822         {
7823           l = aopGet (left, offset, FALSE, FALSE);
7824           MOVA (l);
7825           emitcode ("rlc", "a");
7826           if (AOP_SIZE (result) > 1)
7827             aopPut (result, "a", offset++);
7828         }
7829     }
7830   /* now we need to put the carry into the
7831      highest order byte of the result */
7832   if (AOP_SIZE (result) > 1)
7833     {
7834       l = aopGet (result, 0, FALSE, FALSE);
7835       MOVA (l);
7836     }
7837   emitcode ("mov", "acc.0,c");
7838  release:
7839   aopPut (result, "a", 0);
7840   freeAsmop (result, NULL, ic, TRUE);
7841   freeAsmop (left, NULL, ic, TRUE);
7842 }
7843
7844 /*-----------------------------------------------------------------*/
7845 /* genGetHbit - generates code get highest order bit               */
7846 /*-----------------------------------------------------------------*/
7847 static void
7848 genGetHbit (iCode * ic)
7849 {
7850   operand *left, *result;
7851
7852   D (emitcode (";", "genGetHbit"));
7853
7854   left = IC_LEFT (ic);
7855   result = IC_RESULT (ic);
7856   aopOp (left, ic, FALSE);
7857   aopOp (result, ic, FALSE);
7858
7859   /* get the highest order byte into a */
7860   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7861   if (AOP_TYPE (result) == AOP_CRY)
7862     {
7863       emitcode ("rlc", "a");
7864       outBitC (result);
7865     }
7866   else
7867     {
7868       emitcode ("rl", "a");
7869       emitcode ("anl", "a,#0x01");
7870       outAcc (result);
7871     }
7872
7873   freeAsmop (result, NULL, ic, TRUE);
7874   freeAsmop (left, NULL, ic, TRUE);
7875 }
7876
7877 /*-----------------------------------------------------------------*/
7878 /* genGetAbit - generates code get a single bit                    */
7879 /*-----------------------------------------------------------------*/
7880 static void
7881 genGetAbit (iCode * ic)
7882 {
7883   operand *left, *right, *result;
7884   int shCount;
7885
7886   D (emitcode (";", "genGetAbit"));
7887
7888   left = IC_LEFT (ic);
7889   right = IC_RIGHT (ic);
7890   result = IC_RESULT (ic);
7891   aopOp (left, ic, FALSE);
7892   aopOp (right, ic, FALSE);
7893   aopOp (result, ic, FALSE);
7894
7895   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7896
7897   /* get the needed byte into a */
7898   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7899   shCount %= 8;
7900   if (AOP_TYPE (result) == AOP_CRY)
7901     {
7902       if ((shCount) == 7)
7903           emitcode ("rlc", "a");
7904       else if ((shCount) == 0)
7905           emitcode ("rrc", "a");
7906       else
7907           emitcode ("mov", "c,acc[%d]", shCount);
7908       outBitC (result);
7909     }
7910   else
7911     {
7912       switch (shCount)
7913         {
7914         case 2:
7915           emitcode ("rr", "a");
7916           //fallthrough
7917         case 1:
7918           emitcode ("rr", "a");
7919           //fallthrough
7920         case 0:
7921           emitcode ("anl", "a,#0x01");
7922           break;
7923         case 3:
7924         case 5:
7925           emitcode ("mov", "c,acc[%d]", shCount);
7926           emitcode ("clr", "a");
7927           emitcode ("rlc", "a");
7928           break;
7929         case 4:
7930           emitcode ("swap", "a");
7931           emitcode ("anl", "a,#0x01");
7932           break;
7933         case 6:
7934           emitcode ("rl", "a");
7935           //fallthrough
7936         case 7:
7937           emitcode ("rl", "a");
7938           emitcode ("anl", "a,#0x01");
7939           break;
7940         }
7941       outAcc (result);
7942     }
7943
7944   freeAsmop (result, NULL, ic, TRUE);
7945   freeAsmop (right, NULL, ic, TRUE);
7946   freeAsmop (left, NULL, ic, TRUE);
7947 }
7948
7949 /*-----------------------------------------------------------------*/
7950 /* genGetByte - generates code get a single byte                   */
7951 /*-----------------------------------------------------------------*/
7952 static void
7953 genGetByte (iCode * ic)
7954 {
7955   operand *left, *right, *result;
7956   int offset;
7957
7958   D (emitcode (";", "genGetByte"));
7959
7960   left = IC_LEFT (ic);
7961   right = IC_RIGHT (ic);
7962   result = IC_RESULT (ic);
7963   aopOp (left, ic, FALSE);
7964   aopOp (right, ic, FALSE);
7965   aopOp (result, ic, FALSE);
7966
7967   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7968   aopPut (result,
7969           aopGet (left, offset, FALSE, FALSE),
7970           0);
7971
7972   freeAsmop (result, NULL, ic, TRUE);
7973   freeAsmop (right, NULL, ic, TRUE);
7974   freeAsmop (left, NULL, ic, TRUE);
7975 }
7976
7977 /*-----------------------------------------------------------------*/
7978 /* genGetWord - generates code get two bytes                       */
7979 /*-----------------------------------------------------------------*/
7980 static void
7981 genGetWord (iCode * ic)
7982 {
7983   operand *left, *right, *result;
7984   int offset;
7985
7986   D (emitcode (";", "genGetWord"));
7987
7988   left = IC_LEFT (ic);
7989   right = IC_RIGHT (ic);
7990   result = IC_RESULT (ic);
7991   aopOp (left, ic, FALSE);
7992   aopOp (right, ic, FALSE);
7993   aopOp (result, ic, FALSE);
7994
7995   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7996   aopPut (result,
7997           aopGet (left, offset, FALSE, FALSE),
7998           0);
7999   aopPut (result,
8000           aopGet (left, offset+1, FALSE, FALSE),
8001           1);
8002
8003   freeAsmop (result, NULL, ic, TRUE);
8004   freeAsmop (right, NULL, ic, TRUE);
8005   freeAsmop (left, NULL, ic, TRUE);
8006 }
8007
8008 /*-----------------------------------------------------------------*/
8009 /* genSwap - generates code to swap nibbles or bytes               */
8010 /*-----------------------------------------------------------------*/
8011 static void
8012 genSwap (iCode * ic)
8013 {
8014   operand *left, *result;
8015
8016   D(emitcode (";", "genSwap"));
8017
8018   left = IC_LEFT (ic);
8019   result = IC_RESULT (ic);
8020   aopOp (left, ic, FALSE);
8021   aopOp (result, ic, FALSE);
8022
8023   switch (AOP_SIZE (left))
8024     {
8025     case 1: /* swap nibbles in byte */
8026       MOVA (aopGet (left, 0, FALSE, FALSE));
8027       emitcode ("swap", "a");
8028       aopPut (result, "a", 0);
8029       break;
8030     case 2: /* swap bytes in word */
8031       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8032         {
8033           MOVA (aopGet (left, 0, FALSE, FALSE));
8034           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8035           aopPut (result, "a", 1);
8036         }
8037       else if (operandsEqu (left, result))
8038         {
8039           char * reg = "a";
8040           bool pushedB = FALSE, leftInB = FALSE;
8041
8042           MOVA (aopGet (left, 0, FALSE, FALSE));
8043           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8044             {
8045               pushedB = pushB ();
8046               emitcode ("mov", "b,a");
8047               reg = "b";
8048               leftInB = TRUE;
8049             }
8050           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8051           aopPut (result, reg, 1);
8052
8053           if (leftInB)
8054             popB (pushedB);
8055         }
8056       else
8057         {
8058           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8059           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8060         }
8061       break;
8062     default:
8063       wassertl(FALSE, "unsupported SWAP operand size");
8064     }
8065
8066   freeAsmop (result, NULL, ic, TRUE);
8067   freeAsmop (left, NULL, ic, TRUE);
8068 }
8069
8070 /*-----------------------------------------------------------------*/
8071 /* AccRol - rotate left accumulator by known count                 */
8072 /*-----------------------------------------------------------------*/
8073 static void
8074 AccRol (int shCount)
8075 {
8076   shCount &= 0x0007;            // shCount : 0..7
8077
8078   switch (shCount)
8079     {
8080     case 0:
8081       break;
8082     case 1:
8083       emitcode ("rl", "a");
8084       break;
8085     case 2:
8086       emitcode ("rl", "a");
8087       emitcode ("rl", "a");
8088       break;
8089     case 3:
8090       emitcode ("swap", "a");
8091       emitcode ("rr", "a");
8092       break;
8093     case 4:
8094       emitcode ("swap", "a");
8095       break;
8096     case 5:
8097       emitcode ("swap", "a");
8098       emitcode ("rl", "a");
8099       break;
8100     case 6:
8101       emitcode ("rr", "a");
8102       emitcode ("rr", "a");
8103       break;
8104     case 7:
8105       emitcode ("rr", "a");
8106       break;
8107     }
8108 }
8109
8110 /*-----------------------------------------------------------------*/
8111 /* AccLsh - left shift accumulator by known count                  */
8112 /*-----------------------------------------------------------------*/
8113 static void
8114 AccLsh (int shCount)
8115 {
8116   if (shCount != 0)
8117     {
8118       if (shCount == 1)
8119         emitcode ("add", "a,acc");
8120       else if (shCount == 2)
8121         {
8122           emitcode ("add", "a,acc");
8123           emitcode ("add", "a,acc");
8124         }
8125       else
8126         {
8127           /* rotate left accumulator */
8128           AccRol (shCount);
8129           /* and kill the lower order bits */
8130           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8131         }
8132     }
8133 }
8134
8135 /*-----------------------------------------------------------------*/
8136 /* AccRsh - right shift accumulator by known count                 */
8137 /*-----------------------------------------------------------------*/
8138 static void
8139 AccRsh (int shCount)
8140 {
8141   if (shCount != 0)
8142     {
8143       if (shCount == 1)
8144         {
8145           CLRC;
8146           emitcode ("rrc", "a");
8147         }
8148       else
8149         {
8150           /* rotate right accumulator */
8151           AccRol (8 - shCount);
8152           /* and kill the higher order bits */
8153           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8154         }
8155     }
8156 }
8157
8158 /*-----------------------------------------------------------------*/
8159 /* AccSRsh - signed right shift accumulator by known count                 */
8160 /*-----------------------------------------------------------------*/
8161 static void
8162 AccSRsh (int shCount)
8163 {
8164   symbol *tlbl;
8165   if (shCount != 0)
8166     {
8167       if (shCount == 1)
8168         {
8169           emitcode ("mov", "c,acc.7");
8170           emitcode ("rrc", "a");
8171         }
8172       else if (shCount == 2)
8173         {
8174           emitcode ("mov", "c,acc.7");
8175           emitcode ("rrc", "a");
8176           emitcode ("mov", "c,acc.7");
8177           emitcode ("rrc", "a");
8178         }
8179       else
8180         {
8181           tlbl = newiTempLabel (NULL);
8182           /* rotate right accumulator */
8183           AccRol (8 - shCount);
8184           /* and kill the higher order bits */
8185           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8186           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8187           emitcode ("orl", "a,#0x%02x",
8188                     (unsigned char) ~SRMask[shCount]);
8189           emitLabel (tlbl);
8190         }
8191     }
8192 }
8193
8194 /*-----------------------------------------------------------------*/
8195 /* shiftR1Left2Result - shift right one byte from left to result   */
8196 /*-----------------------------------------------------------------*/
8197 static void
8198 shiftR1Left2Result (operand * left, int offl,
8199                     operand * result, int offr,
8200                     int shCount, int sign)
8201 {
8202   MOVA (aopGet (left, offl, FALSE, FALSE));
8203   /* shift right accumulator */
8204   if (sign)
8205     AccSRsh (shCount);
8206   else
8207     AccRsh (shCount);
8208   aopPut (result, "a", offr);
8209 }
8210
8211 /*-----------------------------------------------------------------*/
8212 /* shiftL1Left2Result - shift left one byte from left to result    */
8213 /*-----------------------------------------------------------------*/
8214 static void
8215 shiftL1Left2Result (operand * left, int offl,
8216                     operand * result, int offr, int shCount)
8217 {
8218   char *l;
8219   l = aopGet (left, offl, FALSE, FALSE);
8220   MOVA (l);
8221   /* shift left accumulator */
8222   AccLsh (shCount);
8223   aopPut (result, "a", offr);
8224 }
8225
8226 /*-----------------------------------------------------------------*/
8227 /* movLeft2Result - move byte from left to result                  */
8228 /*-----------------------------------------------------------------*/
8229 static void
8230 movLeft2Result (operand * left, int offl,
8231                 operand * result, int offr, int sign)
8232 {
8233   char *l;
8234   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8235     {
8236       l = aopGet (left, offl, FALSE, FALSE);
8237
8238       if (*l == '@' && (IS_AOP_PREG (result)))
8239         {
8240           emitcode ("mov", "a,%s", l);
8241           aopPut (result, "a", offr);
8242         }
8243       else
8244         {
8245           if (!sign)
8246             {
8247               aopPut (result, l, offr);
8248             }
8249           else
8250             {
8251               /* MSB sign in acc.7 ! */
8252               if (getDataSize (left) == offl + 1)
8253                 {
8254                   MOVA (l);
8255                   aopPut (result, "a", offr);
8256                 }
8257             }
8258         }
8259     }
8260 }
8261
8262 /*-----------------------------------------------------------------*/
8263 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8264 /*-----------------------------------------------------------------*/
8265 static void
8266 AccAXRrl1 (char *x)
8267 {
8268   emitcode ("rrc", "a");
8269   emitcode ("xch", "a,%s", x);
8270   emitcode ("rrc", "a");
8271   emitcode ("xch", "a,%s", x);
8272 }
8273
8274 /*-----------------------------------------------------------------*/
8275 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8276 /*-----------------------------------------------------------------*/
8277 static void
8278 AccAXLrl1 (char *x)
8279 {
8280   emitcode ("xch", "a,%s", x);
8281   emitcode ("rlc", "a");
8282   emitcode ("xch", "a,%s", x);
8283   emitcode ("rlc", "a");
8284 }
8285
8286 /*-----------------------------------------------------------------*/
8287 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8288 /*-----------------------------------------------------------------*/
8289 static void
8290 AccAXLsh1 (char *x)
8291 {
8292   emitcode ("xch", "a,%s", x);
8293   emitcode ("add", "a,acc");
8294   emitcode ("xch", "a,%s", x);
8295   emitcode ("rlc", "a");
8296 }
8297
8298 /*-----------------------------------------------------------------*/
8299 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8300 /*-----------------------------------------------------------------*/
8301 static void
8302 AccAXLsh (char *x, int shCount)
8303 {
8304   switch (shCount)
8305     {
8306     case 0:
8307       break;
8308     case 1:
8309       AccAXLsh1 (x);
8310       break;
8311     case 2:
8312       AccAXLsh1 (x);
8313       AccAXLsh1 (x);
8314       break;
8315     case 3:
8316     case 4:
8317     case 5:                     // AAAAABBB:CCCCCDDD
8318
8319       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8320
8321       emitcode ("anl", "a,#0x%02x",
8322                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8323
8324       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8325
8326       AccRol (shCount);         // DDDCCCCC:BBB00000
8327
8328       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8329
8330       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8331
8332       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8333
8334       emitcode ("anl", "a,#0x%02x",
8335                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8336
8337       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8338
8339       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8340
8341       break;
8342     case 6:                     // AAAAAABB:CCCCCCDD
8343       emitcode ("anl", "a,#0x%02x",
8344                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8345       emitcode ("mov", "c,acc.0");      // c = B
8346       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8347 #if 0 // REMOVE ME
8348       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8349       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8350 #else
8351       emitcode("rrc","a");
8352       emitcode("xch","a,%s", x);
8353       emitcode("rrc","a");
8354       emitcode("mov","c,acc.0"); //<< get correct bit
8355       emitcode("xch","a,%s", x);
8356
8357       emitcode("rrc","a");
8358       emitcode("xch","a,%s", x);
8359       emitcode("rrc","a");
8360       emitcode("xch","a,%s", x);
8361 #endif
8362       break;
8363     case 7:                     // a:x <<= 7
8364
8365       emitcode ("anl", "a,#0x%02x",
8366                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8367
8368       emitcode ("mov", "c,acc.0");      // c = B
8369
8370       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8371
8372       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8373
8374       break;
8375     default:
8376       break;
8377     }
8378 }
8379
8380 /*-----------------------------------------------------------------*/
8381 /* AccAXRsh - right shift a:x known count (0..7)                   */
8382 /*-----------------------------------------------------------------*/
8383 static void
8384 AccAXRsh (char *x, int shCount)
8385 {
8386   switch (shCount)
8387     {
8388     case 0:
8389       break;
8390     case 1:
8391       CLRC;
8392       AccAXRrl1 (x);            // 0->a:x
8393
8394       break;
8395     case 2:
8396       CLRC;
8397       AccAXRrl1 (x);            // 0->a:x
8398
8399       CLRC;
8400       AccAXRrl1 (x);            // 0->a:x
8401
8402       break;
8403     case 3:
8404     case 4:
8405     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8406
8407       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8408
8409       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8410
8411       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8412
8413       emitcode ("anl", "a,#0x%02x",
8414                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8415
8416       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8417
8418       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8419
8420       emitcode ("anl", "a,#0x%02x",
8421                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8422
8423       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8424
8425       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8426
8427       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8428
8429       break;
8430     case 6:                     // AABBBBBB:CCDDDDDD
8431
8432       emitcode ("mov", "c,acc.7");
8433       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8434
8435       emitcode ("mov", "c,acc.7");
8436       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8437
8438       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8439
8440       emitcode ("anl", "a,#0x%02x",
8441                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8442
8443       break;
8444     case 7:                     // ABBBBBBB:CDDDDDDD
8445
8446       emitcode ("mov", "c,acc.7");      // c = A
8447
8448       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8449
8450       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8451
8452       emitcode ("anl", "a,#0x%02x",
8453                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8454
8455       break;
8456     default:
8457       break;
8458     }
8459 }
8460
8461 /*-----------------------------------------------------------------*/
8462 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8463 /*-----------------------------------------------------------------*/
8464 static void
8465 AccAXRshS (char *x, int shCount)
8466 {
8467   symbol *tlbl;
8468   switch (shCount)
8469     {
8470     case 0:
8471       break;
8472     case 1:
8473       emitcode ("mov", "c,acc.7");
8474       AccAXRrl1 (x);            // s->a:x
8475
8476       break;
8477     case 2:
8478       emitcode ("mov", "c,acc.7");
8479       AccAXRrl1 (x);            // s->a:x
8480
8481       emitcode ("mov", "c,acc.7");
8482       AccAXRrl1 (x);            // s->a:x
8483
8484       break;
8485     case 3:
8486     case 4:
8487     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8488
8489       tlbl = newiTempLabel (NULL);
8490       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8491
8492       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8493
8494       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8495
8496       emitcode ("anl", "a,#0x%02x",
8497                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8498
8499       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8500
8501       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8502
8503       emitcode ("anl", "a,#0x%02x",
8504                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8505
8506       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8507
8508       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8509
8510       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8511
8512       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8513       emitcode ("orl", "a,#0x%02x",
8514                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8515
8516       emitLabel (tlbl);
8517       break;                    // SSSSAAAA:BBBCCCCC
8518
8519     case 6:                     // AABBBBBB:CCDDDDDD
8520
8521       tlbl = newiTempLabel (NULL);
8522       emitcode ("mov", "c,acc.7");
8523       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8524
8525       emitcode ("mov", "c,acc.7");
8526       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8527
8528       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8529
8530       emitcode ("anl", "a,#0x%02x",
8531                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8532
8533       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8534       emitcode ("orl", "a,#0x%02x",
8535                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8536
8537       emitLabel (tlbl);
8538       break;
8539     case 7:                     // ABBBBBBB:CDDDDDDD
8540
8541       tlbl = newiTempLabel (NULL);
8542       emitcode ("mov", "c,acc.7");      // c = A
8543
8544       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8545
8546       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8547
8548       emitcode ("anl", "a,#0x%02x",
8549                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8550
8551       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8552       emitcode ("orl", "a,#0x%02x",
8553                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8554
8555       emitLabel (tlbl);
8556       break;
8557     default:
8558       break;
8559     }
8560 }
8561
8562 /*-----------------------------------------------------------------*/
8563 /* shiftL2Left2Result - shift left two bytes from left to result   */
8564 /*-----------------------------------------------------------------*/
8565 static void
8566 shiftL2Left2Result (operand * left, int offl,
8567                     operand * result, int offr, int shCount)
8568 {
8569   char * x;
8570   bool pushedB = FALSE;
8571   bool usedB = FALSE;
8572
8573   if (sameRegs (AOP (result), AOP (left)) &&
8574       ((offl + MSB16) == offr))
8575     {
8576       /* don't crash result[offr] */
8577       MOVA (aopGet (left, offl, FALSE, FALSE));
8578       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8579       usedB = !strncmp(x, "b", 1);
8580     }
8581   else if (aopGetUsesAcc (result, offr))
8582     {
8583       movLeft2Result (left, offl, result, offr, 0);
8584       pushedB = pushB ();
8585       usedB = TRUE;
8586       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8587       MOVA (aopGet (result, offr, FALSE, FALSE));
8588       emitcode ("xch", "a,b");
8589       x = "b";
8590     }
8591   else
8592     {
8593       movLeft2Result (left, offl, result, offr, 0);
8594       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8595       x = aopGet (result, offr, FALSE, FALSE);
8596     }
8597   /* ax << shCount (x = lsb(result)) */
8598   AccAXLsh (x, shCount);
8599   if (usedB)
8600     {
8601       emitcode ("xch", "a,b");
8602       aopPut (result, "a", offr);
8603       aopPut (result, "b", offr + MSB16);
8604       popB (pushedB);
8605     }
8606   else
8607     {
8608       aopPut (result, "a", offr + MSB16);
8609     }
8610 }
8611
8612
8613 /*-----------------------------------------------------------------*/
8614 /* shiftR2Left2Result - shift right two bytes from left to result  */
8615 /*-----------------------------------------------------------------*/
8616 static void
8617 shiftR2Left2Result (operand * left, int offl,
8618                     operand * result, int offr,
8619                     int shCount, int sign)
8620 {
8621   char * x;
8622   bool pushedB = FALSE;
8623   bool usedB = FALSE;
8624
8625   if (sameRegs (AOP (result), AOP (left)) &&
8626       ((offl + MSB16) == offr))
8627     {
8628       /* don't crash result[offr] */
8629       MOVA (aopGet (left, offl, FALSE, FALSE));
8630       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8631       usedB = !strncmp(x, "b", 1);
8632     }
8633   else if (aopGetUsesAcc (result, offr))
8634     {
8635       movLeft2Result (left, offl, result, offr, 0);
8636       pushedB = pushB ();
8637       usedB = TRUE;
8638       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8639       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8640       x = "b";
8641     }
8642   else
8643     {
8644       movLeft2Result (left, offl, result, offr, 0);
8645       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8646       x = aopGet (result, offr, FALSE, FALSE);
8647     }
8648   /* a:x >> shCount (x = lsb(result)) */
8649   if (sign)
8650     AccAXRshS (x, shCount);
8651   else
8652     AccAXRsh (x, shCount);
8653   if (usedB)
8654     {
8655       emitcode ("xch", "a,b");
8656       aopPut (result, "a", offr);
8657       emitcode ("xch", "a,b");
8658       popB (pushedB);
8659     }
8660   if (getDataSize (result) > 1)
8661     aopPut (result, "a", offr + MSB16);
8662 }
8663
8664 /*-----------------------------------------------------------------*/
8665 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8666 /*-----------------------------------------------------------------*/
8667 static void
8668 shiftLLeftOrResult (operand * left, int offl,
8669                     operand * result, int offr, int shCount)
8670 {
8671   MOVA (aopGet (left, offl, FALSE, FALSE));
8672   /* shift left accumulator */
8673   AccLsh (shCount);
8674   /* or with result */
8675   if (aopGetUsesAcc (result, offr))
8676     {
8677       emitcode ("xch", "a,b");
8678       MOVA (aopGet (result, offr, FALSE, FALSE));
8679       emitcode ("orl", "a,b");
8680     }
8681   else
8682     {
8683       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8684     }
8685   /* back to result */
8686   aopPut (result, "a", offr);
8687 }
8688
8689 /*-----------------------------------------------------------------*/
8690 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8691 /*-----------------------------------------------------------------*/
8692 static void
8693 shiftRLeftOrResult (operand * left, int offl,
8694                     operand * result, int offr, int shCount)
8695 {
8696   MOVA (aopGet (left, offl, FALSE, FALSE));
8697   /* shift right accumulator */
8698   AccRsh (shCount);
8699   /* or with result */
8700   if (aopGetUsesAcc(result, offr))
8701     {
8702       emitcode ("xch", "a,b");
8703       MOVA (aopGet (result, offr, FALSE, FALSE));
8704       emitcode ("orl", "a,b");
8705     }
8706   else
8707     {
8708       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8709     }
8710   /* back to result */
8711   aopPut (result, "a", offr);
8712 }
8713
8714 /*-----------------------------------------------------------------*/
8715 /* genlshOne - left shift a one byte quantity by known count       */
8716 /*-----------------------------------------------------------------*/
8717 static void
8718 genlshOne (operand * result, operand * left, int shCount)
8719 {
8720   D (emitcode (";", "genlshOne"));
8721
8722   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8723 }
8724
8725 /*-----------------------------------------------------------------*/
8726 /* genlshTwo - left shift two bytes by known amount != 0           */
8727 /*-----------------------------------------------------------------*/
8728 static void
8729 genlshTwo (operand * result, operand * left, int shCount)
8730 {
8731   int size;
8732
8733   D (emitcode (";", "genlshTwo"));
8734
8735   size = getDataSize (result);
8736
8737   /* if shCount >= 8 */
8738   if (shCount >= 8)
8739     {
8740       shCount -= 8;
8741
8742       if (size > 1)
8743         {
8744           if (shCount)
8745             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8746           else
8747             movLeft2Result (left, LSB, result, MSB16, 0);
8748         }
8749       aopPut (result, zero, LSB);
8750     }
8751
8752   /*  1 <= shCount <= 7 */
8753   else
8754     {
8755       if (size == 1)
8756         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8757       else
8758         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8759     }
8760 }
8761
8762 /*-----------------------------------------------------------------*/
8763 /* shiftLLong - shift left one long from left to result            */
8764 /* offl = LSB or MSB16                                             */
8765 /*-----------------------------------------------------------------*/
8766 static void
8767 shiftLLong (operand * left, operand * result, int offr)
8768 {
8769   char *l;
8770   int size = AOP_SIZE (result);
8771
8772   if (size >= LSB + offr)
8773     {
8774       l = aopGet (left, LSB, FALSE, FALSE);
8775       MOVA (l);
8776       emitcode ("add", "a,acc");
8777       if (sameRegs (AOP (left), AOP (result)) &&
8778           size >= MSB16 + offr && offr != LSB)
8779         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8780       else
8781         aopPut (result, "a", LSB + offr);
8782     }
8783
8784   if (size >= MSB16 + offr)
8785     {
8786       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8787         {
8788           l = aopGet (left, MSB16, FALSE, FALSE);
8789           MOVA (l);
8790         }
8791       emitcode ("rlc", "a");
8792       if (sameRegs (AOP (left), AOP (result)) &&
8793           size >= MSB24 + offr && offr != LSB)
8794         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8795       else
8796         aopPut (result, "a", MSB16 + offr);
8797     }
8798
8799   if (size >= MSB24 + offr)
8800     {
8801       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8802         {
8803           l = aopGet (left, MSB24, FALSE, FALSE);
8804           MOVA (l);
8805         }
8806       emitcode ("rlc", "a");
8807       if (sameRegs (AOP (left), AOP (result)) &&
8808           size >= MSB32 + offr && offr != LSB)
8809         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8810       else
8811         aopPut (result, "a", MSB24 + offr);
8812     }
8813
8814   if (size > MSB32 + offr)
8815     {
8816       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8817         {
8818           l = aopGet (left, MSB32, FALSE, FALSE);
8819           MOVA (l);
8820         }
8821       emitcode ("rlc", "a");
8822       aopPut (result, "a", MSB32 + offr);
8823     }
8824   if (offr != LSB)
8825     aopPut (result, zero, LSB);
8826 }
8827
8828 /*-----------------------------------------------------------------*/
8829 /* genlshFour - shift four byte by a known amount != 0             */
8830 /*-----------------------------------------------------------------*/
8831 static void
8832 genlshFour (operand * result, operand * left, int shCount)
8833 {
8834   int size;
8835
8836   D (emitcode (";", "genlshFour"));
8837
8838   size = AOP_SIZE (result);
8839
8840   /* if shifting more that 3 bytes */
8841   if (shCount >= 24)
8842     {
8843       shCount -= 24;
8844       if (shCount)
8845         /* lowest order of left goes to the highest
8846            order of the destination */
8847         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8848       else
8849         movLeft2Result (left, LSB, result, MSB32, 0);
8850       aopPut (result, zero, LSB);
8851       aopPut (result, zero, MSB16);
8852       aopPut (result, zero, MSB24);
8853       return;
8854     }
8855
8856   /* more than two bytes */
8857   else if (shCount >= 16)
8858     {
8859       /* lower order two bytes goes to higher order two bytes */
8860       shCount -= 16;
8861       /* if some more remaining */
8862       if (shCount)
8863         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8864       else
8865         {
8866           movLeft2Result (left, MSB16, result, MSB32, 0);
8867           movLeft2Result (left, LSB, result, MSB24, 0);
8868         }
8869       aopPut (result, zero, MSB16);
8870       aopPut (result, zero, LSB);
8871       return;
8872     }
8873
8874   /* if more than 1 byte */
8875   else if (shCount >= 8)
8876     {
8877       /* lower order three bytes goes to higher order  three bytes */
8878       shCount -= 8;
8879       if (size == 2)
8880         {
8881           if (shCount)
8882             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8883           else
8884             movLeft2Result (left, LSB, result, MSB16, 0);
8885         }
8886       else
8887         {                       /* size = 4 */
8888           if (shCount == 0)
8889             {
8890               movLeft2Result (left, MSB24, result, MSB32, 0);
8891               movLeft2Result (left, MSB16, result, MSB24, 0);
8892               movLeft2Result (left, LSB, result, MSB16, 0);
8893               aopPut (result, zero, LSB);
8894             }
8895           else if (shCount == 1)
8896             shiftLLong (left, result, MSB16);
8897           else
8898             {
8899               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8900               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8901               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8902               aopPut (result, zero, LSB);
8903             }
8904         }
8905     }
8906
8907   /* 1 <= shCount <= 7 */
8908   else if (shCount <= 2)
8909     {
8910       shiftLLong (left, result, LSB);
8911       if (shCount == 2)
8912         shiftLLong (result, result, LSB);
8913     }
8914   /* 3 <= shCount <= 7, optimize */
8915   else
8916     {
8917       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8918       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8919       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8920     }
8921 }
8922
8923 /*-----------------------------------------------------------------*/
8924 /* genLeftShiftLiteral - left shifting by known count              */
8925 /*-----------------------------------------------------------------*/
8926 static void
8927 genLeftShiftLiteral (operand * left,
8928                      operand * right,
8929                      operand * result,
8930                      iCode * ic)
8931 {
8932   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8933   int size;
8934
8935   D (emitcode (";", "genLeftShiftLiteral"));
8936
8937   freeAsmop (right, NULL, ic, TRUE);
8938
8939   aopOp (left, ic, FALSE);
8940   aopOp (result, ic, FALSE);
8941
8942   size = getSize (operandType (result));
8943
8944 #if VIEW_SIZE
8945   emitcode ("; shift left ", "result %d, left %d", size,
8946             AOP_SIZE (left));
8947 #endif
8948
8949   /* I suppose that the left size >= result size */
8950   if (shCount == 0)
8951     {
8952       while (size--)
8953         {
8954           movLeft2Result (left, size, result, size, 0);
8955         }
8956     }
8957   else if (shCount >= (size * 8))
8958     {
8959       while (size--)
8960         {
8961           aopPut (result, zero, size);
8962         }
8963     }
8964   else
8965     {
8966       switch (size)
8967         {
8968         case 1:
8969           genlshOne (result, left, shCount);
8970           break;
8971
8972         case 2:
8973           genlshTwo (result, left, shCount);
8974           break;
8975
8976         case 4:
8977           genlshFour (result, left, shCount);
8978           break;
8979         default:
8980           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8981                   "*** ack! mystery literal shift!\n");
8982           break;
8983         }
8984     }
8985   freeAsmop (result, NULL, ic, TRUE);
8986   freeAsmop (left, NULL, ic, TRUE);
8987 }
8988
8989 /*-----------------------------------------------------------------*/
8990 /* genLeftShift - generates code for left shifting                 */
8991 /*-----------------------------------------------------------------*/
8992 static void
8993 genLeftShift (iCode * ic)
8994 {
8995   operand *left, *right, *result;
8996   int size, offset;
8997   char *l;
8998   symbol *tlbl, *tlbl1;
8999   bool pushedB;
9000
9001   D (emitcode (";", "genLeftShift"));
9002
9003   right = IC_RIGHT (ic);
9004   left = IC_LEFT (ic);
9005   result = IC_RESULT (ic);
9006
9007   aopOp (right, ic, FALSE);
9008
9009   /* if the shift count is known then do it
9010      as efficiently as possible */
9011   if (AOP_TYPE (right) == AOP_LIT)
9012     {
9013       genLeftShiftLiteral (left, right, result, ic);
9014       return;
9015     }
9016
9017   /* shift count is unknown then we have to form
9018      a loop get the loop count in B : Note: we take
9019      only the lower order byte since shifting
9020      more that 32 bits make no sense anyway, ( the
9021      largest size of an object can be only 32 bits ) */
9022
9023   pushedB = pushB ();
9024   MOVB (aopGet (right, 0, FALSE, FALSE));
9025   emitcode ("inc", "b");
9026   freeAsmop (right, NULL, ic, TRUE);
9027   aopOp (left, ic, FALSE);
9028   aopOp (result, ic, FALSE);
9029
9030   /* now move the left to the result if they are not the same */
9031   if (!sameRegs (AOP (left), AOP (result)) &&
9032       AOP_SIZE (result) > 1)
9033     {
9034
9035       size = AOP_SIZE (result);
9036       offset = 0;
9037       while (size--)
9038         {
9039           l = aopGet (left, offset, FALSE, TRUE);
9040           if (*l == '@' && (IS_AOP_PREG (result)))
9041             {
9042
9043               emitcode ("mov", "a,%s", l);
9044               aopPut (result, "a", offset);
9045             }
9046           else
9047             aopPut (result, l, offset);
9048           offset++;
9049         }
9050     }
9051
9052   tlbl = newiTempLabel (NULL);
9053   size = AOP_SIZE (result);
9054   offset = 0;
9055   tlbl1 = newiTempLabel (NULL);
9056
9057   /* if it is only one byte then */
9058   if (size == 1)
9059     {
9060       symbol *tlbl1 = newiTempLabel (NULL);
9061
9062       l = aopGet (left, 0, FALSE, FALSE);
9063       MOVA (l);
9064       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9065       emitLabel (tlbl);
9066       emitcode ("add", "a,acc");
9067       emitLabel (tlbl1);
9068       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9069       popB (pushedB);
9070       aopPut (result, "a", 0);
9071       goto release;
9072     }
9073
9074   reAdjustPreg (AOP (result));
9075
9076   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9077   emitLabel (tlbl);
9078   l = aopGet (result, offset, FALSE, FALSE);
9079   MOVA (l);
9080   emitcode ("add", "a,acc");
9081   aopPut (result, "a", offset++);
9082   while (--size)
9083     {
9084       l = aopGet (result, offset, FALSE, FALSE);
9085       MOVA (l);
9086       emitcode ("rlc", "a");
9087       aopPut (result, "a", offset++);
9088     }
9089   reAdjustPreg (AOP (result));
9090
9091   emitLabel (tlbl1);
9092   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9093   popB (pushedB);
9094 release:
9095   freeAsmop (result, NULL, ic, TRUE);
9096   freeAsmop (left, NULL, ic, TRUE);
9097 }
9098
9099 /*-----------------------------------------------------------------*/
9100 /* genrshOne - right shift a one byte quantity by known count      */
9101 /*-----------------------------------------------------------------*/
9102 static void
9103 genrshOne (operand * result, operand * left,
9104            int shCount, int sign)
9105 {
9106   D (emitcode (";", "genrshOne"));
9107
9108   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9109 }
9110
9111 /*-----------------------------------------------------------------*/
9112 /* genrshTwo - right shift two bytes by known amount != 0          */
9113 /*-----------------------------------------------------------------*/
9114 static void
9115 genrshTwo (operand * result, operand * left,
9116            int shCount, int sign)
9117 {
9118   D (emitcode (";", "genrshTwo"));
9119
9120   /* if shCount >= 8 */
9121   if (shCount >= 8)
9122     {
9123       shCount -= 8;
9124       if (shCount)
9125         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9126       else
9127         movLeft2Result (left, MSB16, result, LSB, sign);
9128       addSign (result, MSB16, sign);
9129     }
9130
9131   /*  1 <= shCount <= 7 */
9132   else
9133     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9134 }
9135
9136 /*-----------------------------------------------------------------*/
9137 /* shiftRLong - shift right one long from left to result           */
9138 /* offl = LSB or MSB16                                             */
9139 /*-----------------------------------------------------------------*/
9140 static void
9141 shiftRLong (operand * left, int offl,
9142             operand * result, int sign)
9143 {
9144   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9145
9146   if (overlapping && offl>1)
9147     {
9148       // we are in big trouble, but this shouldn't happen
9149       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9150     }
9151
9152   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9153
9154   if (offl==MSB16)
9155     {
9156       // shift is > 8
9157       if (sign)
9158         {
9159           emitcode ("rlc", "a");
9160           emitcode ("subb", "a,acc");
9161           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9162             {
9163               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9164             }
9165           else
9166             {
9167               aopPut (result, "a", MSB32);
9168               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9169             }
9170         }
9171       else
9172         {
9173           if (aopPutUsesAcc (result, zero, MSB32))
9174             {
9175               emitcode("xch", "a,b");
9176               aopPut (result, zero, MSB32);
9177               emitcode("xch", "a,b");
9178             }
9179           else
9180             {
9181               aopPut (result, zero, MSB32);
9182             }
9183         }
9184     }
9185
9186   if (!sign)
9187     {
9188       emitcode ("clr", "c");
9189     }
9190   else
9191     {
9192       emitcode ("mov", "c,acc.7");
9193     }
9194
9195   emitcode ("rrc", "a");
9196
9197   if (overlapping && offl==MSB16 &&
9198       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9199     {
9200       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9201     }
9202   else
9203     {
9204       aopPut (result, "a", MSB32 - offl);
9205       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9206     }
9207
9208   emitcode ("rrc", "a");
9209   if (overlapping && offl==MSB16 &&
9210       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9211     {
9212       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9213     }
9214   else
9215     {
9216       aopPut (result, "a", MSB24 - offl);
9217       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9218     }
9219
9220   emitcode ("rrc", "a");
9221   if (offl != LSB)
9222     {
9223       aopPut (result, "a", MSB16 - offl);
9224     }
9225   else
9226     {
9227       if (overlapping &&
9228           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9229         {
9230           xch_a_aopGet (left, LSB, FALSE, FALSE);
9231         }
9232       else
9233         {
9234           aopPut (result, "a", MSB16 - offl);
9235           MOVA (aopGet (left, LSB, FALSE, FALSE));
9236         }
9237       emitcode ("rrc", "a");
9238       aopPut (result, "a", LSB);
9239     }
9240 }
9241
9242 /*-----------------------------------------------------------------*/
9243 /* genrshFour - shift four byte by a known amount != 0             */
9244 /*-----------------------------------------------------------------*/
9245 static void
9246 genrshFour (operand * result, operand * left,
9247             int shCount, int sign)
9248 {
9249   D (emitcode (";", "genrshFour"));
9250
9251   /* if shifting more that 3 bytes */
9252   if (shCount >= 24)
9253     {
9254       shCount -= 24;
9255       if (shCount)
9256         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9257       else
9258         movLeft2Result (left, MSB32, result, LSB, sign);
9259       addSign (result, MSB16, sign);
9260     }
9261   else if (shCount >= 16)
9262     {
9263       shCount -= 16;
9264       if (shCount)
9265         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9266       else
9267         {
9268           movLeft2Result (left, MSB24, result, LSB, 0);
9269           movLeft2Result (left, MSB32, result, MSB16, sign);
9270         }
9271       addSign (result, MSB24, sign);
9272     }
9273   else if (shCount >= 8)
9274     {
9275       shCount -= 8;
9276       if (shCount == 1)
9277         {
9278           shiftRLong (left, MSB16, result, sign);
9279         }
9280       else if (shCount == 0)
9281         {
9282           movLeft2Result (left, MSB16, result, LSB, 0);
9283           movLeft2Result (left, MSB24, result, MSB16, 0);
9284           movLeft2Result (left, MSB32, result, MSB24, sign);
9285           addSign (result, MSB32, sign);
9286         }
9287       else
9288         {
9289           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9290           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9291           /* the last shift is signed */
9292           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9293           addSign (result, MSB32, sign);
9294         }
9295     }
9296   else
9297     {
9298       /* 1 <= shCount <= 7 */
9299       if (shCount <= 2)
9300         {
9301           shiftRLong (left, LSB, result, sign);
9302           if (shCount == 2)
9303             shiftRLong (result, LSB, result, sign);
9304         }
9305       else
9306         {
9307           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9308           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9309           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9310         }
9311     }
9312 }
9313
9314 /*-----------------------------------------------------------------*/
9315 /* genRightShiftLiteral - right shifting by known count            */
9316 /*-----------------------------------------------------------------*/
9317 static void
9318 genRightShiftLiteral (operand * left,
9319                       operand * right,
9320                       operand * result,
9321                       iCode * ic,
9322                       int sign)
9323 {
9324   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9325   int size;
9326
9327   D (emitcode (";", "genRightShiftLiteral"));
9328
9329   freeAsmop (right, NULL, ic, TRUE);
9330
9331   aopOp (left, ic, FALSE);
9332   aopOp (result, ic, FALSE);
9333
9334 #if VIEW_SIZE
9335   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9336             AOP_SIZE (left));
9337 #endif
9338
9339   size = getDataSize (left);
9340   /* test the LEFT size !!! */
9341
9342   /* I suppose that the left size >= result size */
9343   if (shCount == 0)
9344     {
9345       size = getDataSize (result);
9346       while (size--)
9347         movLeft2Result (left, size, result, size, 0);
9348     }
9349
9350   else if (shCount >= (size * 8))
9351     {
9352       if (sign)
9353         {
9354           /* get sign in acc.7 */
9355           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9356         }
9357       addSign (result, LSB, sign);
9358     }
9359   else
9360     {
9361       switch (size)
9362         {
9363         case 1:
9364           genrshOne (result, left, shCount, sign);
9365           break;
9366
9367         case 2:
9368           genrshTwo (result, left, shCount, sign);
9369           break;
9370
9371         case 4:
9372           genrshFour (result, left, shCount, sign);
9373           break;
9374         default:
9375           break;
9376         }
9377     }
9378   freeAsmop (result, NULL, ic, TRUE);
9379   freeAsmop (left, NULL, ic, TRUE);
9380 }
9381
9382 /*-----------------------------------------------------------------*/
9383 /* genSignedRightShift - right shift of signed number              */
9384 /*-----------------------------------------------------------------*/
9385 static void
9386 genSignedRightShift (iCode * ic)
9387 {
9388   operand *right, *left, *result;
9389   int size, offset;
9390   char *l;
9391   symbol *tlbl, *tlbl1;
9392   bool pushedB;
9393
9394   D (emitcode (";", "genSignedRightShift"));
9395
9396   /* we do it the hard way put the shift count in b
9397      and loop thru preserving the sign */
9398
9399   right = IC_RIGHT (ic);
9400   left = IC_LEFT (ic);
9401   result = IC_RESULT (ic);
9402
9403   aopOp (right, ic, FALSE);
9404
9405
9406   if (AOP_TYPE (right) == AOP_LIT)
9407     {
9408       genRightShiftLiteral (left, right, result, ic, 1);
9409       return;
9410     }
9411   /* shift count is unknown then we have to form
9412      a loop get the loop count in B : Note: we take
9413      only the lower order byte since shifting
9414      more that 32 bits make no sense anyway, ( the
9415      largest size of an object can be only 32 bits ) */
9416
9417   pushedB = pushB ();
9418   MOVB (aopGet (right, 0, FALSE, FALSE));
9419   emitcode ("inc", "b");
9420   freeAsmop (right, NULL, ic, TRUE);
9421   aopOp (left, ic, FALSE);
9422   aopOp (result, ic, FALSE);
9423
9424   /* now move the left to the result if they are not the
9425      same */
9426   if (!sameRegs (AOP (left), AOP (result)) &&
9427       AOP_SIZE (result) > 1)
9428     {
9429
9430       size = AOP_SIZE (result);
9431       offset = 0;
9432       while (size--)
9433         {
9434           l = aopGet (left, offset, FALSE, TRUE);
9435           if (*l == '@' && IS_AOP_PREG (result))
9436             {
9437
9438               emitcode ("mov", "a,%s", l);
9439               aopPut (result, "a", offset);
9440             }
9441           else
9442             aopPut (result, l, offset);
9443           offset++;
9444         }
9445     }
9446
9447   /* mov the highest order bit to OVR */
9448   tlbl = newiTempLabel (NULL);
9449   tlbl1 = newiTempLabel (NULL);
9450
9451   size = AOP_SIZE (result);
9452   offset = size - 1;
9453   MOVA (aopGet (left, offset, FALSE, FALSE));
9454   emitcode ("rlc", "a");
9455   emitcode ("mov", "ov,c");
9456   /* if it is only one byte then */
9457   if (size == 1)
9458     {
9459       l = aopGet (left, 0, FALSE, FALSE);
9460       MOVA (l);
9461       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9462       emitLabel (tlbl);
9463       emitcode ("mov", "c,ov");
9464       emitcode ("rrc", "a");
9465       emitLabel (tlbl1);
9466       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9467       popB (pushedB);
9468       aopPut (result, "a", 0);
9469       goto release;
9470     }
9471
9472   reAdjustPreg (AOP (result));
9473   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9474   emitLabel (tlbl);
9475   emitcode ("mov", "c,ov");
9476   while (size--)
9477     {
9478       l = aopGet (result, offset, FALSE, FALSE);
9479       MOVA (l);
9480       emitcode ("rrc", "a");
9481       aopPut (result, "a", offset--);
9482     }
9483   reAdjustPreg (AOP (result));
9484   emitLabel (tlbl1);
9485   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9486   popB (pushedB);
9487
9488 release:
9489   freeAsmop (result, NULL, ic, TRUE);
9490   freeAsmop (left, NULL, ic, TRUE);
9491 }
9492
9493 /*-----------------------------------------------------------------*/
9494 /* genRightShift - generate code for right shifting                */
9495 /*-----------------------------------------------------------------*/
9496 static void
9497 genRightShift (iCode * ic)
9498 {
9499   operand *right, *left, *result;
9500   sym_link *letype;
9501   int size, offset;
9502   char *l;
9503   symbol *tlbl, *tlbl1;
9504   bool pushedB;
9505
9506   D (emitcode (";", "genRightShift"));
9507
9508   /* if signed then we do it the hard way preserve the
9509      sign bit moving it inwards */
9510   letype = getSpec (operandType (IC_LEFT (ic)));
9511
9512   if (!SPEC_USIGN (letype))
9513     {
9514       genSignedRightShift (ic);
9515       return;
9516     }
9517
9518   /* signed & unsigned types are treated the same : i.e. the
9519      signed is NOT propagated inwards : quoting from the
9520      ANSI - standard : "for E1 >> E2, is equivalent to division
9521      by 2**E2 if unsigned or if it has a non-negative value,
9522      otherwise the result is implementation defined ", MY definition
9523      is that the sign does not get propagated */
9524
9525   right = IC_RIGHT (ic);
9526   left = IC_LEFT (ic);
9527   result = IC_RESULT (ic);
9528
9529   aopOp (right, ic, FALSE);
9530
9531   /* if the shift count is known then do it
9532      as efficiently as possible */
9533   if (AOP_TYPE (right) == AOP_LIT)
9534     {
9535       genRightShiftLiteral (left, right, result, ic, 0);
9536       return;
9537     }
9538
9539   /* shift count is unknown then we have to form
9540      a loop get the loop count in B : Note: we take
9541      only the lower order byte since shifting
9542      more that 32 bits make no sense anyway, ( the
9543      largest size of an object can be only 32 bits ) */
9544
9545   pushedB = pushB ();
9546   MOVB (aopGet (right, 0, FALSE, FALSE));
9547   emitcode ("inc", "b");
9548   freeAsmop (right, NULL, ic, TRUE);
9549   aopOp (left, ic, FALSE);
9550   aopOp (result, ic, FALSE);
9551
9552   /* now move the left to the result if they are not the
9553      same */
9554   if (!sameRegs (AOP (left), AOP (result)) &&
9555       AOP_SIZE (result) > 1)
9556     {
9557       size = AOP_SIZE (result);
9558       offset = 0;
9559       while (size--)
9560         {
9561           l = aopGet (left, offset, FALSE, TRUE);
9562           if (*l == '@' && IS_AOP_PREG (result))
9563             {
9564
9565               emitcode ("mov", "a,%s", l);
9566               aopPut (result, "a", offset);
9567             }
9568           else
9569             aopPut (result, l, offset);
9570           offset++;
9571         }
9572     }
9573
9574   tlbl = newiTempLabel (NULL);
9575   tlbl1 = newiTempLabel (NULL);
9576   size = AOP_SIZE (result);
9577   offset = size - 1;
9578
9579   /* if it is only one byte then */
9580   if (size == 1)
9581     {
9582       l = aopGet (left, 0, FALSE, FALSE);
9583       MOVA (l);
9584       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9585       emitLabel (tlbl);
9586       CLRC;
9587       emitcode ("rrc", "a");
9588       emitLabel (tlbl1);
9589       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9590       popB (pushedB);
9591       aopPut (result, "a", 0);
9592       goto release;
9593     }
9594
9595   reAdjustPreg (AOP (result));
9596   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9597   emitLabel (tlbl);
9598   CLRC;
9599   while (size--)
9600     {
9601       l = aopGet (result, offset, FALSE, FALSE);
9602       MOVA (l);
9603       emitcode ("rrc", "a");
9604       aopPut (result, "a", offset--);
9605     }
9606   reAdjustPreg (AOP (result));
9607
9608   emitLabel (tlbl1);
9609   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9610   popB (pushedB);
9611
9612 release:
9613   freeAsmop (result, NULL, ic, TRUE);
9614   freeAsmop (left, NULL, ic, TRUE);
9615 }
9616
9617 /*-----------------------------------------------------------------*/
9618 /* emitPtrByteGet - emits code to get a byte into A through a      */
9619 /*                  pointer register (R0, R1, or DPTR). The        */
9620 /*                  original value of A can be preserved in B.     */
9621 /*-----------------------------------------------------------------*/
9622 static void
9623 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9624 {
9625   switch (p_type)
9626     {
9627     case IPOINTER:
9628     case POINTER:
9629       if (preserveAinB)
9630         emitcode ("mov", "b,a");
9631       emitcode ("mov", "a,@%s", rname);
9632       break;
9633
9634     case PPOINTER:
9635       if (preserveAinB)
9636         emitcode ("mov", "b,a");
9637       emitcode ("movx", "a,@%s", rname);
9638       break;
9639
9640     case FPOINTER:
9641       if (preserveAinB)
9642         emitcode ("mov", "b,a");
9643       emitcode ("movx", "a,@dptr");
9644       break;
9645
9646     case CPOINTER:
9647       if (preserveAinB)
9648         emitcode ("mov", "b,a");
9649       emitcode ("clr", "a");
9650       emitcode ("movc", "a,@a+dptr");
9651       break;
9652
9653     case GPOINTER:
9654       if (preserveAinB)
9655         {
9656           emitcode ("push", "b");
9657           emitcode ("push", "acc");
9658         }
9659       emitcode ("lcall", "__gptrget");
9660       if (preserveAinB)
9661         emitcode ("pop", "b");
9662       break;
9663     }
9664 }
9665
9666 /*-----------------------------------------------------------------*/
9667 /* emitPtrByteSet - emits code to set a byte from src through a    */
9668 /*                  pointer register (R0, R1, or DPTR).            */
9669 /*-----------------------------------------------------------------*/
9670 static void
9671 emitPtrByteSet (char *rname, int p_type, char *src)
9672 {
9673   switch (p_type)
9674     {
9675     case IPOINTER:
9676     case POINTER:
9677       if (*src=='@')
9678         {
9679           MOVA (src);
9680           emitcode ("mov", "@%s,a", rname);
9681         }
9682       else
9683         emitcode ("mov", "@%s,%s", rname, src);
9684       break;
9685
9686     case PPOINTER:
9687       MOVA (src);
9688       emitcode ("movx", "@%s,a", rname);
9689       break;
9690
9691     case FPOINTER:
9692       MOVA (src);
9693       emitcode ("movx", "@dptr,a");
9694       break;
9695
9696     case GPOINTER:
9697       MOVA (src);
9698       emitcode ("lcall", "__gptrput");
9699       break;
9700     }
9701 }
9702
9703 /*-----------------------------------------------------------------*/
9704 /* genUnpackBits - generates code for unpacking bits               */
9705 /*-----------------------------------------------------------------*/
9706 static void
9707 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9708 {
9709   int offset = 0;       /* result byte offset */
9710   int rsize;            /* result size */
9711   int rlen = 0;         /* remaining bitfield length */
9712   sym_link *etype;      /* bitfield type information */
9713   int blen;             /* bitfield length */
9714   int bstr;             /* bitfield starting bit within byte */
9715   char buffer[10];
9716
9717   D(emitcode (";", "genUnpackBits"));
9718
9719   etype = getSpec (operandType (result));
9720   rsize = getSize (operandType (result));
9721   blen = SPEC_BLEN (etype);
9722   bstr = SPEC_BSTR (etype);
9723
9724   if (ifx && blen <= 8)
9725     {
9726       emitPtrByteGet (rname, ptype, FALSE);
9727       if (blen == 1)
9728         {
9729           SNPRINTF (buffer, sizeof(buffer),
9730                     "acc.%d", bstr);
9731           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9732         }
9733       else
9734         {
9735           if (blen < 8)
9736             emitcode ("anl", "a,#0x%02x",
9737                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9738           genIfxJump (ifx, "a", NULL, NULL, NULL);
9739         }
9740       return;
9741     }
9742   wassert (!ifx);
9743
9744   /* If the bitfield length is less than a byte */
9745   if (blen < 8)
9746     {
9747       emitPtrByteGet (rname, ptype, FALSE);
9748       AccRol (8 - bstr);
9749       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9750       if (!SPEC_USIGN (etype))
9751         {
9752           /* signed bitfield */
9753           symbol *tlbl = newiTempLabel (NULL);
9754
9755           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9756           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9757           emitLabel (tlbl);
9758         }
9759       aopPut (result, "a", offset++);
9760       goto finish;
9761     }
9762
9763   /* Bit field did not fit in a byte. Copy all
9764      but the partial byte at the end.  */
9765   for (rlen=blen;rlen>=8;rlen-=8)
9766     {
9767       emitPtrByteGet (rname, ptype, FALSE);
9768       aopPut (result, "a", offset++);
9769       if (rlen>8)
9770         emitcode ("inc", "%s", rname);
9771     }
9772
9773   /* Handle the partial byte at the end */
9774   if (rlen)
9775     {
9776       emitPtrByteGet (rname, ptype, FALSE);
9777       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9778       if (!SPEC_USIGN (etype))
9779         {
9780           /* signed bitfield */
9781           symbol *tlbl = newiTempLabel (NULL);
9782
9783           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9784           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9785           emitLabel (tlbl);
9786         }
9787       aopPut (result, "a", offset++);
9788     }
9789
9790 finish:
9791   if (offset < rsize)
9792     {
9793       char *source;
9794
9795       if (SPEC_USIGN (etype))
9796         source = zero;
9797       else
9798         {
9799           /* signed bitfield: sign extension with 0x00 or 0xff */
9800           emitcode ("rlc", "a");
9801           emitcode ("subb", "a,acc");
9802
9803           source = "a";
9804         }
9805       rsize -= offset;
9806       while (rsize--)
9807         aopPut (result, source, offset++);
9808     }
9809 }
9810
9811
9812 /*-----------------------------------------------------------------*/
9813 /* genDataPointerGet - generates code when ptr offset is known     */
9814 /*-----------------------------------------------------------------*/
9815 static void
9816 genDataPointerGet (operand * left,
9817                    operand * result,
9818                    iCode * ic)
9819 {
9820   char *l;
9821   char buffer[256];
9822   int size, offset = 0;
9823
9824   D (emitcode (";", "genDataPointerGet"));
9825
9826   aopOp (result, ic, TRUE);
9827
9828   /* get the string representation of the name */
9829   l = aopGet (left, 0, FALSE, TRUE);
9830   l++; // remove #
9831   size = AOP_SIZE (result);
9832   while (size--)
9833     {
9834       if (offset)
9835         {
9836           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9837         }
9838       else
9839         {
9840           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9841         }
9842       aopPut (result, buffer, offset++);
9843     }
9844
9845   freeAsmop (result, NULL, ic, TRUE);
9846   freeAsmop (left, NULL, ic, TRUE);
9847 }
9848
9849 /*-----------------------------------------------------------------*/
9850 /* genNearPointerGet - emitcode for near pointer fetch             */
9851 /*-----------------------------------------------------------------*/
9852 static void
9853 genNearPointerGet (operand * left,
9854                    operand * result,
9855                    iCode * ic,
9856                    iCode * pi,
9857                    iCode * ifx)
9858 {
9859   asmop *aop = NULL;
9860   regs *preg = NULL;
9861   char *rname;
9862   sym_link *rtype, *retype;
9863   sym_link *ltype = operandType (left);
9864   char buffer[80];
9865
9866   D (emitcode (";", "genNearPointerGet"));
9867
9868   rtype = operandType (result);
9869   retype = getSpec (rtype);
9870
9871   aopOp (left, ic, FALSE);
9872
9873   /* if left is rematerialisable and
9874      result is not bitfield variable type and
9875      the left is pointer to data space i.e
9876      lower 128 bytes of space */
9877   if (AOP_TYPE (left) == AOP_IMMD &&
9878       !IS_BITFIELD (retype) &&
9879       DCL_TYPE (ltype) == POINTER)
9880     {
9881       genDataPointerGet (left, result, ic);
9882       return;
9883     }
9884
9885  /* if the value is already in a pointer register
9886      then don't need anything more */
9887   if (!AOP_INPREG (AOP (left)))
9888     {
9889       if (IS_AOP_PREG (left))
9890         {
9891           // Aha, it is a pointer, just in disguise.
9892           rname = aopGet (left, 0, FALSE, FALSE);
9893           if (*rname != '@')
9894             {
9895               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9896                       __FILE__, __LINE__);
9897             }
9898           else
9899             {
9900               // Expected case.
9901               emitcode ("mov", "a%s,%s", rname + 1, rname);
9902               rname++;  // skip the '@'.
9903             }
9904         }
9905       else
9906         {
9907           /* otherwise get a free pointer register */
9908           aop = newAsmop (0);
9909           preg = getFreePtr (ic, &aop, FALSE);
9910           emitcode ("mov", "%s,%s",
9911                     preg->name,
9912                     aopGet (left, 0, FALSE, TRUE));
9913           rname = preg->name;
9914         }
9915     }
9916   else
9917     rname = aopGet (left, 0, FALSE, FALSE);
9918
9919   //aopOp (result, ic, FALSE);
9920   aopOp (result, ic, result?TRUE:FALSE);
9921
9922   /* if bitfield then unpack the bits */
9923   if (IS_BITFIELD (retype))
9924     genUnpackBits (result, rname, POINTER, ifx);
9925   else
9926     {
9927       /* we have can just get the values */
9928       int size = AOP_SIZE (result);
9929       int offset = 0;
9930
9931       while (size--)
9932         {
9933           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9934             {
9935
9936               emitcode ("mov", "a,@%s", rname);
9937               if (!ifx)
9938                 aopPut (result, "a", offset);
9939             }
9940           else
9941             {
9942               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9943               aopPut (result, buffer, offset);
9944             }
9945           offset++;
9946           if (size || pi)
9947             emitcode ("inc", "%s", rname);
9948         }
9949     }
9950
9951   /* now some housekeeping stuff */
9952   if (aop)       /* we had to allocate for this iCode */
9953     {
9954       if (pi) { /* post increment present */
9955         aopPut (left, rname, 0);
9956       }
9957       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9958     }
9959   else
9960     {
9961       /* we did not allocate which means left
9962          already in a pointer register, then
9963          if size > 0 && this could be used again
9964          we have to point it back to where it
9965          belongs */
9966       if ((AOP_SIZE (result) > 1 &&
9967            !OP_SYMBOL (left)->remat &&
9968            (OP_SYMBOL (left)->liveTo > ic->seq ||
9969             ic->depth)) &&
9970           !pi)
9971         {
9972           int size = AOP_SIZE (result) - 1;
9973           while (size--)
9974             emitcode ("dec", "%s", rname);
9975         }
9976     }
9977
9978   if (ifx && !ifx->generated)
9979     {
9980       genIfxJump (ifx, "a", left, NULL, result);
9981     }
9982
9983   /* done */
9984   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9985   freeAsmop (left, NULL, ic, TRUE);
9986   if (pi) pi->generated = 1;
9987 }
9988
9989 /*-----------------------------------------------------------------*/
9990 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9991 /*-----------------------------------------------------------------*/
9992 static void
9993 genPagedPointerGet (operand * left,
9994                     operand * result,
9995                     iCode * ic,
9996                     iCode *pi,
9997                     iCode *ifx)
9998 {
9999   asmop *aop = NULL;
10000   regs *preg = NULL;
10001   char *rname;
10002   sym_link *rtype, *retype;
10003
10004   D (emitcode (";", "genPagedPointerGet"));
10005
10006   rtype = operandType (result);
10007   retype = getSpec (rtype);
10008
10009   aopOp (left, ic, FALSE);
10010
10011   /* if the value is already in a pointer register
10012      then don't need anything more */
10013   if (!AOP_INPREG (AOP (left)))
10014     {
10015       /* otherwise get a free pointer register */
10016       aop = newAsmop (0);
10017       preg = getFreePtr (ic, &aop, FALSE);
10018       emitcode ("mov", "%s,%s",
10019                 preg->name,
10020                 aopGet (left, 0, FALSE, TRUE));
10021       rname = preg->name;
10022     }
10023   else
10024     rname = aopGet (left, 0, FALSE, FALSE);
10025
10026   aopOp (result, ic, FALSE);
10027
10028   /* if bitfield then unpack the bits */
10029   if (IS_BITFIELD (retype))
10030     genUnpackBits (result, rname, PPOINTER, ifx);
10031   else
10032     {
10033       /* we have can just get the values */
10034       int size = AOP_SIZE (result);
10035       int offset = 0;
10036
10037       while (size--)
10038         {
10039
10040           emitcode ("movx", "a,@%s", rname);
10041           if (!ifx)
10042             aopPut (result, "a", offset);
10043
10044           offset++;
10045
10046           if (size || pi)
10047             emitcode ("inc", "%s", rname);
10048         }
10049     }
10050
10051   /* now some housekeeping stuff */
10052   if (aop) /* we had to allocate for this iCode */
10053     {
10054       if (pi)
10055         aopPut (left, rname, 0);
10056       freeAsmop (NULL, aop, ic, TRUE);
10057     }
10058   else
10059     {
10060       /* we did not allocate which means left
10061          already in a pointer register, then
10062          if size > 0 && this could be used again
10063          we have to point it back to where it
10064          belongs */
10065       if ((AOP_SIZE (result) > 1 &&
10066            !OP_SYMBOL (left)->remat &&
10067            (OP_SYMBOL (left)->liveTo > ic->seq ||
10068             ic->depth)) &&
10069           !pi)
10070         {
10071           int size = AOP_SIZE (result) - 1;
10072           while (size--)
10073             emitcode ("dec", "%s", rname);
10074         }
10075     }
10076
10077   if (ifx && !ifx->generated)
10078     {
10079       genIfxJump (ifx, "a", left, NULL, result);
10080     }
10081
10082   /* done */
10083   freeAsmop (result, NULL, ic, TRUE);
10084   freeAsmop (left, NULL, ic, TRUE);
10085   if (pi) pi->generated = 1;
10086 }
10087
10088 /*--------------------------------------------------------------------*/
10089 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10090 /*--------------------------------------------------------------------*/
10091 static void
10092 loadDptrFromOperand (operand *op, bool loadBToo)
10093 {
10094   if (AOP_TYPE (op) != AOP_STR)
10095     {
10096       /* if this is rematerializable */
10097       if (AOP_TYPE (op) == AOP_IMMD)
10098         {
10099           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10100           if (loadBToo)
10101             {
10102               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10103                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10104               else
10105                 {
10106                   wassertl(FALSE, "need pointerCode");
10107                   emitcode (";", "mov b,???");
10108                   /* genPointerGet and genPointerSet originally did different
10109                   ** things for this case. Both seem wrong.
10110                   ** from genPointerGet:
10111                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10112                   ** from genPointerSet:
10113                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10114                   */
10115                 }
10116             }
10117         }
10118       else if (AOP_TYPE (op) == AOP_DPTR)
10119         {
10120           if (loadBToo)
10121             {
10122               MOVA (aopGet (op, 0, FALSE, FALSE));
10123               emitcode ("push", "acc");
10124               MOVA (aopGet (op, 1, FALSE, FALSE));
10125               emitcode ("push", "acc");
10126               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10127               emitcode ("pop", "dph");
10128               emitcode ("pop", "dpl");
10129             }
10130           else
10131             {
10132               MOVA (aopGet (op, 0, FALSE, FALSE));
10133               emitcode ("push", "acc");
10134               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10135               emitcode ("pop", "dpl");
10136             }
10137         }
10138       else
10139         {                       /* we need to get it byte by byte */
10140           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10141           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10142           if (loadBToo)
10143             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10144         }
10145     }
10146 }
10147
10148 /*-----------------------------------------------------------------*/
10149 /* genFarPointerGet - get value from far space                     */
10150 /*-----------------------------------------------------------------*/
10151 static void
10152 genFarPointerGet (operand * left,
10153                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10154 {
10155   int size, offset;
10156   sym_link *retype = getSpec (operandType (result));
10157
10158   D (emitcode (";", "genFarPointerGet"));
10159
10160   aopOp (left, ic, FALSE);
10161   loadDptrFromOperand (left, FALSE);
10162
10163   /* so dptr now contains the address */
10164   aopOp (result, ic, FALSE);
10165
10166   /* if bit then unpack */
10167   if (IS_BITFIELD (retype))
10168     genUnpackBits (result, "dptr", FPOINTER, ifx);
10169   else
10170     {
10171       size = AOP_SIZE (result);
10172       offset = 0;
10173
10174       while (size--)
10175         {
10176           emitcode ("movx", "a,@dptr");
10177           if (!ifx)
10178             aopPut (result, "a", offset++);
10179           if (size || pi)
10180             emitcode ("inc", "dptr");
10181         }
10182     }
10183
10184   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10185     {
10186       aopPut (left, "dpl", 0);
10187       aopPut (left, "dph", 1);
10188       pi->generated = 1;
10189     }
10190
10191   if (ifx && !ifx->generated)
10192     {
10193       genIfxJump (ifx, "a", left, NULL, result);
10194     }
10195
10196   freeAsmop (result, NULL, ic, TRUE);
10197   freeAsmop (left, NULL, ic, TRUE);
10198 }
10199
10200 /*-----------------------------------------------------------------*/
10201 /* genCodePointerGet - get value from code space                   */
10202 /*-----------------------------------------------------------------*/
10203 static void
10204 genCodePointerGet (operand * left,
10205                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10206 {
10207   int size, offset;
10208   sym_link *retype = getSpec (operandType (result));
10209
10210   D (emitcode (";", "genCodePointerGet"));
10211
10212   aopOp (left, ic, FALSE);
10213   loadDptrFromOperand (left, FALSE);
10214
10215   /* so dptr now contains the address */
10216   aopOp (result, ic, FALSE);
10217
10218   /* if bit then unpack */
10219   if (IS_BITFIELD (retype))
10220     genUnpackBits (result, "dptr", CPOINTER, ifx);
10221   else
10222     {
10223       size = AOP_SIZE (result);
10224       offset = 0;
10225
10226       while (size--)
10227         {
10228           emitcode ("clr", "a");
10229           emitcode ("movc", "a,@a+dptr");
10230           if (!ifx)
10231             aopPut (result, "a", offset++);
10232           if (size || pi)
10233             emitcode ("inc", "dptr");
10234         }
10235     }
10236
10237   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10238     {
10239       aopPut (left, "dpl", 0);
10240       aopPut (left, "dph", 1);
10241       pi->generated = 1;
10242     }
10243
10244   if (ifx && !ifx->generated)
10245     {
10246       genIfxJump (ifx, "a", left, NULL, result);
10247     }
10248
10249   freeAsmop (result, NULL, ic, TRUE);
10250   freeAsmop (left, NULL, ic, TRUE);
10251 }
10252
10253 /*-----------------------------------------------------------------*/
10254 /* genGenPointerGet - get value from generic pointer space         */
10255 /*-----------------------------------------------------------------*/
10256 static void
10257 genGenPointerGet (operand * left,
10258                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10259 {
10260   int size, offset;
10261   sym_link *retype = getSpec (operandType (result));
10262
10263   D (emitcode (";", "genGenPointerGet"));
10264
10265   aopOp (left, ic, FALSE);
10266   loadDptrFromOperand (left, TRUE);
10267
10268   /* so dptr now contains the address */
10269   aopOp (result, ic, FALSE);
10270
10271   /* if bit then unpack */
10272   if (IS_BITFIELD (retype))
10273     {
10274       genUnpackBits (result, "dptr", GPOINTER, ifx);
10275     }
10276   else
10277     {
10278       size = AOP_SIZE (result);
10279       offset = 0;
10280
10281       while (size--)
10282         {
10283           emitcode ("lcall", "__gptrget");
10284           if (!ifx)
10285             aopPut (result, "a", offset++);
10286           if (size || pi)
10287             emitcode ("inc", "dptr");
10288         }
10289     }
10290
10291   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10292     {
10293       aopPut (left, "dpl", 0);
10294       aopPut (left, "dph", 1);
10295       pi->generated = 1;
10296     }
10297
10298   if (ifx && !ifx->generated)
10299     {
10300       genIfxJump (ifx, "a", left, NULL, result);
10301     }
10302
10303   freeAsmop (result, NULL, ic, TRUE);
10304   freeAsmop (left, NULL, ic, TRUE);
10305 }
10306
10307 /*-----------------------------------------------------------------*/
10308 /* genPointerGet - generate code for pointer get                   */
10309 /*-----------------------------------------------------------------*/
10310 static void
10311 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10312 {
10313   operand *left, *result;
10314   sym_link *type, *etype;
10315   int p_type;
10316
10317   D (emitcode (";", "genPointerGet"));
10318
10319   left = IC_LEFT (ic);
10320   result = IC_RESULT (ic);
10321
10322   if (getSize (operandType (result))>1)
10323     ifx = NULL;
10324
10325   /* depending on the type of pointer we need to
10326      move it to the correct pointer register */
10327   type = operandType (left);
10328   etype = getSpec (type);
10329   /* if left is of type of pointer then it is simple */
10330   if (IS_PTR (type) && !IS_FUNC (type->next))
10331     p_type = DCL_TYPE (type);
10332   else
10333     {
10334       /* we have to go by the storage class */
10335       p_type = PTR_TYPE (SPEC_OCLS (etype));
10336     }
10337
10338   /* special case when cast remat */
10339   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10340       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10341     {
10342       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10343       type = operandType (left);
10344       p_type = DCL_TYPE (type);
10345     }
10346   /* now that we have the pointer type we assign
10347      the pointer values */
10348   switch (p_type)
10349     {
10350
10351     case POINTER:
10352     case IPOINTER:
10353       genNearPointerGet (left, result, ic, pi, ifx);
10354       break;
10355
10356     case PPOINTER:
10357       genPagedPointerGet (left, result, ic, pi, ifx);
10358       break;
10359
10360     case FPOINTER:
10361       genFarPointerGet (left, result, ic, pi, ifx);
10362       break;
10363
10364     case CPOINTER:
10365       genCodePointerGet (left, result, ic, pi, ifx);
10366       break;
10367
10368     case GPOINTER:
10369       genGenPointerGet (left, result, ic, pi, ifx);
10370       break;
10371     }
10372 }
10373
10374
10375 /*-----------------------------------------------------------------*/
10376 /* genPackBits - generates code for packed bit storage             */
10377 /*-----------------------------------------------------------------*/
10378 static void
10379 genPackBits (sym_link * etype,
10380              operand * right,
10381              char *rname, int p_type)
10382 {
10383   int offset = 0;       /* source byte offset */
10384   int rlen = 0;         /* remaining bitfield length */
10385   int blen;             /* bitfield length */
10386   int bstr;             /* bitfield starting bit within byte */
10387   int litval;           /* source literal value (if AOP_LIT) */
10388   unsigned char mask;   /* bitmask within current byte */
10389
10390   D(emitcode (";", "genPackBits"));
10391
10392   blen = SPEC_BLEN (etype);
10393   bstr = SPEC_BSTR (etype);
10394
10395   /* If the bitfield length is less than a byte */
10396   if (blen < 8)
10397     {
10398       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10399               (unsigned char) (0xFF >> (8 - bstr)));
10400
10401       if (AOP_TYPE (right) == AOP_LIT)
10402         {
10403           /* Case with a bitfield length <8 and literal source
10404           */
10405           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10406           litval <<= bstr;
10407           litval &= (~mask) & 0xff;
10408           emitPtrByteGet (rname, p_type, FALSE);
10409           if ((mask|litval)!=0xff)
10410             emitcode ("anl","a,#0x%02x", mask);
10411           if (litval)
10412             emitcode ("orl","a,#0x%02x", litval);
10413         }
10414       else
10415         {
10416           if ((blen==1) && (p_type!=GPOINTER))
10417             {
10418               /* Case with a bitfield length == 1 and no generic pointer
10419               */
10420               if (AOP_TYPE (right) == AOP_CRY)
10421                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10422               else
10423                 {
10424                   MOVA (aopGet (right, 0, FALSE, FALSE));
10425                   emitcode ("rrc","a");
10426                 }
10427               emitPtrByteGet (rname, p_type, FALSE);
10428               emitcode ("mov","acc.%d,c",bstr);
10429             }
10430           else
10431             {
10432               bool pushedB;
10433               /* Case with a bitfield length < 8 and arbitrary source
10434               */
10435               MOVA (aopGet (right, 0, FALSE, FALSE));
10436               /* shift and mask source value */
10437               AccLsh (bstr);
10438               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10439
10440               pushedB = pushB ();
10441               /* transfer A to B and get next byte */
10442               emitPtrByteGet (rname, p_type, TRUE);
10443
10444               emitcode ("anl", "a,#0x%02x", mask);
10445               emitcode ("orl", "a,b");
10446               if (p_type == GPOINTER)
10447                 emitcode ("pop", "b");
10448
10449               popB (pushedB);
10450            }
10451         }
10452
10453       emitPtrByteSet (rname, p_type, "a");
10454       return;
10455     }
10456
10457   /* Bit length is greater than 7 bits. In this case, copy  */
10458   /* all except the partial byte at the end                 */
10459   for (rlen=blen;rlen>=8;rlen-=8)
10460     {
10461       emitPtrByteSet (rname, p_type,
10462                       aopGet (right, offset++, FALSE, TRUE) );
10463       if (rlen>8)
10464         emitcode ("inc", "%s", rname);
10465     }
10466
10467   /* If there was a partial byte at the end */
10468   if (rlen)
10469     {
10470       mask = (((unsigned char) -1 << rlen) & 0xff);
10471
10472       if (AOP_TYPE (right) == AOP_LIT)
10473         {
10474           /* Case with partial byte and literal source
10475           */
10476           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10477           litval >>= (blen-rlen);
10478           litval &= (~mask) & 0xff;
10479           emitPtrByteGet (rname, p_type, FALSE);
10480           if ((mask|litval)!=0xff)
10481             emitcode ("anl","a,#0x%02x", mask);
10482           if (litval)
10483             emitcode ("orl","a,#0x%02x", litval);
10484         }
10485       else
10486         {
10487           bool pushedB;
10488           /* Case with partial byte and arbitrary source
10489           */
10490           MOVA (aopGet (right, offset++, FALSE, FALSE));
10491           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10492
10493           pushedB = pushB ();
10494           /* transfer A to B and get next byte */
10495           emitPtrByteGet (rname, p_type, TRUE);
10496
10497           emitcode ("anl", "a,#0x%02x", mask);
10498           emitcode ("orl", "a,b");
10499           if (p_type == GPOINTER)
10500             emitcode ("pop", "b");
10501
10502           popB (pushedB);
10503         }
10504       emitPtrByteSet (rname, p_type, "a");
10505     }
10506 }
10507
10508
10509 /*-----------------------------------------------------------------*/
10510 /* genDataPointerSet - remat pointer to data space                 */
10511 /*-----------------------------------------------------------------*/
10512 static void
10513 genDataPointerSet (operand * right,
10514                    operand * result,
10515                    iCode * ic)
10516 {
10517   int size, offset = 0;
10518   char *l, buffer[256];
10519
10520   D (emitcode (";", "genDataPointerSet"));
10521
10522   aopOp (right, ic, FALSE);
10523
10524   l = aopGet (result, 0, FALSE, TRUE);
10525   l++; //remove #
10526   size = AOP_SIZE (right);
10527   while (size--)
10528     {
10529       if (offset)
10530         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10531       else
10532         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10533       emitcode ("mov", "%s,%s", buffer,
10534                 aopGet (right, offset++, FALSE, FALSE));
10535     }
10536
10537   freeAsmop (result, NULL, ic, TRUE);
10538   freeAsmop (right, NULL, ic, TRUE);
10539 }
10540
10541 /*-----------------------------------------------------------------*/
10542 /* genNearPointerSet - emitcode for near pointer put                */
10543 /*-----------------------------------------------------------------*/
10544 static void
10545 genNearPointerSet (operand * right,
10546                    operand * result,
10547                    iCode * ic,
10548                    iCode * pi)
10549 {
10550   asmop *aop = NULL;
10551   regs *preg = NULL;
10552   char *rname, *l;
10553   sym_link *retype, *letype;
10554   sym_link *ptype = operandType (result);
10555
10556   D (emitcode (";", "genNearPointerSet"));
10557
10558   retype = getSpec (operandType (right));
10559   letype = getSpec (ptype);
10560
10561   aopOp (result, ic, FALSE);
10562
10563   /* if the result is rematerializable &
10564      in data space & not a bit variable */
10565   if (AOP_TYPE (result) == AOP_IMMD &&
10566       DCL_TYPE (ptype) == POINTER &&
10567       !IS_BITVAR (retype) &&
10568       !IS_BITVAR (letype))
10569     {
10570       genDataPointerSet (right, result, ic);
10571       return;
10572     }
10573
10574   /* if the value is already in a pointer register
10575      then don't need anything more */
10576   if (!AOP_INPREG (AOP (result)))
10577     {
10578         if (
10579             //AOP_TYPE (result) == AOP_STK
10580             IS_AOP_PREG(result)
10581             )
10582         {
10583             // Aha, it is a pointer, just in disguise.
10584             rname = aopGet (result, 0, FALSE, FALSE);
10585             if (*rname != '@')
10586             {
10587                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10588                         __FILE__, __LINE__);
10589             }
10590             else
10591             {
10592                 // Expected case.
10593                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10594                 rname++;  // skip the '@'.
10595             }
10596         }
10597         else
10598         {
10599             /* otherwise get a free pointer register */
10600             aop = newAsmop (0);
10601             preg = getFreePtr (ic, &aop, FALSE);
10602             emitcode ("mov", "%s,%s",
10603                       preg->name,
10604                       aopGet (result, 0, FALSE, TRUE));
10605             rname = preg->name;
10606         }
10607     }
10608     else
10609     {
10610         rname = aopGet (result, 0, FALSE, FALSE);
10611     }
10612
10613   aopOp (right, ic, FALSE);
10614
10615   /* if bitfield then unpack the bits */
10616   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10617     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10618   else
10619     {
10620       /* we can just get the values */
10621       int size = AOP_SIZE (right);
10622       int offset = 0;
10623
10624       while (size--)
10625         {
10626           l = aopGet (right, offset, FALSE, TRUE);
10627           if ((*l == '@') || (strcmp (l, "acc") == 0))
10628             {
10629               MOVA (l);
10630               emitcode ("mov", "@%s,a", rname);
10631             }
10632           else
10633             emitcode ("mov", "@%s,%s", rname, l);
10634           if (size || pi)
10635             emitcode ("inc", "%s", rname);
10636           offset++;
10637         }
10638     }
10639
10640   /* now some housekeeping stuff */
10641   if (aop) /* we had to allocate for this iCode */
10642     {
10643       if (pi)
10644         aopPut (result, rname, 0);
10645       freeAsmop (NULL, aop, ic, TRUE);
10646     }
10647   else
10648     {
10649       /* we did not allocate which means left
10650          already in a pointer register, then
10651          if size > 0 && this could be used again
10652          we have to point it back to where it
10653          belongs */
10654       if ((AOP_SIZE (right) > 1 &&
10655            !OP_SYMBOL (result)->remat &&
10656            (OP_SYMBOL (result)->liveTo > ic->seq ||
10657             ic->depth)) &&
10658           !pi)
10659         {
10660           int size = AOP_SIZE (right) - 1;
10661           while (size--)
10662             emitcode ("dec", "%s", rname);
10663         }
10664     }
10665
10666   /* done */
10667   if (pi) pi->generated = 1;
10668   freeAsmop (result, NULL, ic, TRUE);
10669   freeAsmop (right, NULL, ic, TRUE);
10670 }
10671
10672 /*-----------------------------------------------------------------*/
10673 /* genPagedPointerSet - emitcode for Paged pointer put             */
10674 /*-----------------------------------------------------------------*/
10675 static void
10676 genPagedPointerSet (operand * right,
10677                     operand * result,
10678                     iCode * ic,
10679                     iCode * pi)
10680 {
10681   asmop *aop = NULL;
10682   regs *preg = NULL;
10683   char *rname, *l;
10684   sym_link *retype, *letype;
10685
10686   D (emitcode (";", "genPagedPointerSet"));
10687
10688   retype = getSpec (operandType (right));
10689   letype = getSpec (operandType (result));
10690
10691   aopOp (result, ic, FALSE);
10692
10693   /* if the value is already in a pointer register
10694      then don't need anything more */
10695   if (!AOP_INPREG (AOP (result)))
10696     {
10697       /* otherwise get a free pointer register */
10698       aop = newAsmop (0);
10699       preg = getFreePtr (ic, &aop, FALSE);
10700       emitcode ("mov", "%s,%s",
10701                 preg->name,
10702                 aopGet (result, 0, FALSE, TRUE));
10703       rname = preg->name;
10704     }
10705   else
10706     rname = aopGet (result, 0, FALSE, FALSE);
10707
10708   aopOp (right, ic, FALSE);
10709
10710   /* if bitfield then unpack the bits */
10711   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10712     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10713   else
10714     {
10715       /* we have can just get the values */
10716       int size = AOP_SIZE (right);
10717       int offset = 0;
10718
10719       while (size--)
10720         {
10721           l = aopGet (right, offset, FALSE, TRUE);
10722           MOVA (l);
10723           emitcode ("movx", "@%s,a", rname);
10724
10725           if (size || pi)
10726             emitcode ("inc", "%s", rname);
10727
10728           offset++;
10729         }
10730     }
10731
10732   /* now some housekeeping stuff */
10733   if (aop) /* we had to allocate for this iCode */
10734     {
10735       if (pi)
10736         aopPut (result, rname, 0);
10737       freeAsmop (NULL, aop, ic, TRUE);
10738     }
10739   else
10740     {
10741       /* we did not allocate which means left
10742          already in a pointer register, then
10743          if size > 0 && this could be used again
10744          we have to point it back to where it
10745          belongs */
10746       if (AOP_SIZE (right) > 1 &&
10747           !OP_SYMBOL (result)->remat &&
10748           (OP_SYMBOL (result)->liveTo > ic->seq ||
10749            ic->depth))
10750         {
10751           int size = AOP_SIZE (right) - 1;
10752           while (size--)
10753             emitcode ("dec", "%s", rname);
10754         }
10755     }
10756
10757   /* done */
10758   if (pi) pi->generated = 1;
10759   freeAsmop (result, NULL, ic, TRUE);
10760   freeAsmop (right, NULL, ic, TRUE);
10761 }
10762
10763 /*-----------------------------------------------------------------*/
10764 /* genFarPointerSet - set value from far space                     */
10765 /*-----------------------------------------------------------------*/
10766 static void
10767 genFarPointerSet (operand * right,
10768                   operand * result, iCode * ic, iCode * pi)
10769 {
10770   int size, offset;
10771   sym_link *retype = getSpec (operandType (right));
10772   sym_link *letype = getSpec (operandType (result));
10773
10774   D(emitcode (";", "genFarPointerSet"));
10775
10776   aopOp (result, ic, FALSE);
10777   loadDptrFromOperand (result, FALSE);
10778
10779   /* so dptr now contains the address */
10780   aopOp (right, ic, FALSE);
10781
10782   /* if bit then unpack */
10783   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10784     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10785   else
10786     {
10787       size = AOP_SIZE (right);
10788       offset = 0;
10789
10790       while (size--)
10791         {
10792           char *l = aopGet (right, offset++, FALSE, FALSE);
10793           MOVA (l);
10794           emitcode ("movx", "@dptr,a");
10795           if (size || pi)
10796             emitcode ("inc", "dptr");
10797         }
10798     }
10799   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10800     aopPut (result, "dpl", 0);
10801     aopPut (result, "dph", 1);
10802     pi->generated=1;
10803   }
10804   freeAsmop (result, NULL, ic, TRUE);
10805   freeAsmop (right, NULL, ic, TRUE);
10806 }
10807
10808 /*-----------------------------------------------------------------*/
10809 /* genGenPointerSet - set value from generic pointer space         */
10810 /*-----------------------------------------------------------------*/
10811 static void
10812 genGenPointerSet (operand * right,
10813                   operand * result, iCode * ic, iCode * pi)
10814 {
10815   int size, offset;
10816   sym_link *retype = getSpec (operandType (right));
10817   sym_link *letype = getSpec (operandType (result));
10818
10819   D (emitcode (";", "genGenPointerSet"));
10820
10821   aopOp (result, ic, FALSE);
10822   loadDptrFromOperand (result, TRUE);
10823
10824   /* so dptr now contains the address */
10825   aopOp (right, ic, FALSE);
10826
10827   /* if bit then unpack */
10828   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10829     {
10830       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10831     }
10832   else
10833     {
10834       size = AOP_SIZE (right);
10835       offset = 0;
10836
10837       while (size--)
10838         {
10839           char *l = aopGet (right, offset++, FALSE, FALSE);
10840           MOVA (l);
10841           emitcode ("lcall", "__gptrput");
10842           if (size || pi)
10843             emitcode ("inc", "dptr");
10844         }
10845     }
10846
10847   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10848     aopPut (result, "dpl", 0);
10849     aopPut (result, "dph", 1);
10850     pi->generated=1;
10851   }
10852   freeAsmop (result, NULL, ic, TRUE);
10853   freeAsmop (right, NULL, ic, TRUE);
10854 }
10855
10856 /*-----------------------------------------------------------------*/
10857 /* genPointerSet - stores the value into a pointer location        */
10858 /*-----------------------------------------------------------------*/
10859 static void
10860 genPointerSet (iCode * ic, iCode *pi)
10861 {
10862   operand *right, *result;
10863   sym_link *type, *etype;
10864   int p_type;
10865
10866   D (emitcode (";", "genPointerSet"));
10867
10868   right = IC_RIGHT (ic);
10869   result = IC_RESULT (ic);
10870
10871   /* depending on the type of pointer we need to
10872      move it to the correct pointer register */
10873   type = operandType (result);
10874   etype = getSpec (type);
10875   /* if left is of type of pointer then it is simple */
10876   if (IS_PTR (type) && !IS_FUNC (type->next))
10877     {
10878       p_type = DCL_TYPE (type);
10879     }
10880   else
10881     {
10882       /* we have to go by the storage class */
10883       p_type = PTR_TYPE (SPEC_OCLS (etype));
10884     }
10885
10886   /* special case when cast remat */
10887   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10888       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10889           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10890           type = operandType (result);
10891           p_type = DCL_TYPE (type);
10892   }
10893
10894   /* now that we have the pointer type we assign
10895      the pointer values */
10896   switch (p_type)
10897     {
10898
10899     case POINTER:
10900     case IPOINTER:
10901       genNearPointerSet (right, result, ic, pi);
10902       break;
10903
10904     case PPOINTER:
10905       genPagedPointerSet (right, result, ic, pi);
10906       break;
10907
10908     case FPOINTER:
10909       genFarPointerSet (right, result, ic, pi);
10910       break;
10911
10912     case GPOINTER:
10913       genGenPointerSet (right, result, ic, pi);
10914       break;
10915
10916     default:
10917       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10918               "genPointerSet: illegal pointer type");
10919     }
10920 }
10921
10922 /*-----------------------------------------------------------------*/
10923 /* genIfx - generate code for Ifx statement                        */
10924 /*-----------------------------------------------------------------*/
10925 static void
10926 genIfx (iCode * ic, iCode * popIc)
10927 {
10928   operand *cond = IC_COND (ic);
10929   int isbit = 0;
10930   char *dup = NULL;
10931
10932   D (emitcode (";", "genIfx"));
10933
10934   aopOp (cond, ic, FALSE);
10935
10936   /* get the value into acc */
10937   if (AOP_TYPE (cond) != AOP_CRY)
10938     {
10939       toBoolean (cond);
10940     }
10941   else
10942     {
10943       isbit = 1;
10944       if (AOP(cond)->aopu.aop_dir)
10945         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10946     }
10947
10948   /* the result is now in the accumulator or a directly addressable bit */
10949   freeAsmop (cond, NULL, ic, TRUE);
10950
10951   /* if there was something to be popped then do it */
10952   if (popIc)
10953     genIpop (popIc);
10954
10955   /* if the condition is a bit variable */
10956   if (isbit && dup)
10957     genIfxJump(ic, dup, NULL, NULL, NULL);
10958   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10959     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10960   else if (isbit && !IS_ITEMP (cond))
10961     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10962   else
10963     genIfxJump (ic, "a", NULL, NULL, NULL);
10964
10965   ic->generated = 1;
10966 }
10967
10968 /*-----------------------------------------------------------------*/
10969 /* genAddrOf - generates code for address of                       */
10970 /*-----------------------------------------------------------------*/
10971 static void
10972 genAddrOf (iCode * ic)
10973 {
10974   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10975   int size, offset;
10976
10977   D (emitcode (";", "genAddrOf"));
10978
10979   aopOp (IC_RESULT (ic), ic, FALSE);
10980
10981   /* if the operand is on the stack then we
10982      need to get the stack offset of this
10983      variable */
10984   if (sym->onStack)
10985     {
10986       /* if it has an offset then we need to compute it */
10987       if (sym->stack)
10988         {
10989           int stack_offset = ((sym->stack < 0) ?
10990                               ((char) (sym->stack - _G.nRegsSaved)) :
10991                               ((char) sym->stack)) & 0xff;
10992           if ((abs(stack_offset) == 1) &&
10993               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10994               !isOperandVolatile (IC_RESULT (ic), FALSE))
10995             {
10996               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10997               if (stack_offset > 0)
10998                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10999               else
11000                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11001             }
11002           else
11003             {
11004               emitcode ("mov", "a,%s", SYM_BP (sym));
11005               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11006               aopPut (IC_RESULT (ic), "a", 0);
11007             }
11008         }
11009       else
11010         {
11011           /* we can just move _bp */
11012           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11013         }
11014       /* fill the result with zero */
11015       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11016
11017       offset = 1;
11018       while (size--)
11019         {
11020           aopPut (IC_RESULT (ic), zero, offset++);
11021         }
11022       goto release;
11023     }
11024
11025   /* object not on stack then we need the name */
11026   size = AOP_SIZE (IC_RESULT (ic));
11027   offset = 0;
11028
11029   while (size--)
11030     {
11031       char s[SDCC_NAME_MAX];
11032       if (offset)
11033         sprintf (s, "#(%s >> %d)",
11034                  sym->rname,
11035                  offset * 8);
11036       else
11037         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11038       aopPut (IC_RESULT (ic), s, offset++);
11039     }
11040
11041 release:
11042   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11043
11044 }
11045
11046 /*-----------------------------------------------------------------*/
11047 /* genFarFarAssign - assignment when both are in far space         */
11048 /*-----------------------------------------------------------------*/
11049 static void
11050 genFarFarAssign (operand * result, operand * right, iCode * ic)
11051 {
11052   int size = AOP_SIZE (right);
11053   int offset = 0;
11054   char *l;
11055
11056   D (emitcode (";", "genFarFarAssign"));
11057
11058   /* first push the right side on to the stack */
11059   while (size--)
11060     {
11061       l = aopGet (right, offset++, FALSE, FALSE);
11062       MOVA (l);
11063       emitcode ("push", "acc");
11064     }
11065
11066   freeAsmop (right, NULL, ic, FALSE);
11067   /* now assign DPTR to result */
11068   aopOp (result, ic, FALSE);
11069   size = AOP_SIZE (result);
11070   while (size--)
11071     {
11072       emitcode ("pop", "acc");
11073       aopPut (result, "a", --offset);
11074     }
11075   freeAsmop (result, NULL, ic, FALSE);
11076 }
11077
11078 /*-----------------------------------------------------------------*/
11079 /* genAssign - generate code for assignment                        */
11080 /*-----------------------------------------------------------------*/
11081 static void
11082 genAssign (iCode * ic)
11083 {
11084   operand *result, *right;
11085   int size, offset;
11086   unsigned long lit = 0L;
11087
11088   D (emitcode (";", "genAssign"));
11089
11090   result = IC_RESULT (ic);
11091   right = IC_RIGHT (ic);
11092
11093   /* if they are the same */
11094   if (operandsEqu (result, right) &&
11095       !isOperandVolatile (result, FALSE) &&
11096       !isOperandVolatile (right, FALSE))
11097     return;
11098
11099   aopOp (right, ic, FALSE);
11100
11101   /* special case both in far space */
11102   if (AOP_TYPE (right) == AOP_DPTR &&
11103       IS_TRUE_SYMOP (result) &&
11104       isOperandInFarSpace (result))
11105     {
11106       genFarFarAssign (result, right, ic);
11107       return;
11108     }
11109
11110   aopOp (result, ic, TRUE);
11111
11112   /* if they are the same registers */
11113   if (sameRegs (AOP (right), AOP (result)) &&
11114       !isOperandVolatile (result, FALSE) &&
11115       !isOperandVolatile (right, FALSE))
11116     goto release;
11117
11118   /* if the result is a bit */
11119   if (AOP_TYPE (result) == AOP_CRY)
11120     {
11121       assignBit (result, right);
11122       goto release;
11123     }
11124
11125   /* bit variables done */
11126   /* general case */
11127   size = AOP_SIZE (result);
11128   offset = 0;
11129   if (AOP_TYPE (right) == AOP_LIT)
11130     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11131
11132   if ((size > 1) &&
11133       (AOP_TYPE (result) != AOP_REG) &&
11134       (AOP_TYPE (right) == AOP_LIT) &&
11135       !IS_FLOAT (operandType (right)) &&
11136       (lit < 256L))
11137     {
11138       while ((size) && (lit))
11139         {
11140           aopPut (result,
11141                   aopGet (right, offset, FALSE, FALSE),
11142                   offset);
11143           lit >>= 8;
11144           offset++;
11145           size--;
11146         }
11147       /* And now fill the rest with zeros. */
11148       if (size)
11149         {
11150           emitcode ("clr", "a");
11151         }
11152       while (size--)
11153         {
11154           aopPut (result, "a", offset);
11155           offset++;
11156         }
11157     }
11158   else
11159     {
11160       while (size--)
11161         {
11162           aopPut (result,
11163                   aopGet (right, offset, FALSE, FALSE),
11164                   offset);
11165           offset++;
11166         }
11167     }
11168
11169 release:
11170   freeAsmop (result, NULL, ic, TRUE);
11171   freeAsmop (right, NULL, ic, TRUE);
11172 }
11173
11174 /*-----------------------------------------------------------------*/
11175 /* genJumpTab - generates code for jump table                      */
11176 /*-----------------------------------------------------------------*/
11177 static void
11178 genJumpTab (iCode * ic)
11179 {
11180   symbol *jtab,*jtablo,*jtabhi;
11181   char *l;
11182   unsigned int count;
11183
11184   D (emitcode (";", "genJumpTab"));
11185
11186   count = elementsInSet( IC_JTLABELS (ic) );
11187
11188   if( count <= 16 )
11189     {
11190       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11191          if the switch argument is in a register.
11192          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11193       /* Peephole may not convert ljmp to sjmp or ret
11194          labelIsReturnOnly & labelInRange must check
11195          currPl->ic->op != JUMPTABLE */
11196       aopOp (IC_JTCOND (ic), ic, FALSE);
11197       /* get the condition into accumulator */
11198       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11199       MOVA (l);
11200       /* multiply by three */
11201       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11202         {
11203           emitcode ("mov", "b,#3");
11204           emitcode ("mul", "ab");
11205         }
11206       else
11207         {
11208           emitcode ("add", "a,acc");
11209           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11210         }
11211       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11212
11213       jtab = newiTempLabel (NULL);
11214       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11215       emitcode ("jmp", "@a+dptr");
11216       emitLabel (jtab);
11217       /* now generate the jump labels */
11218       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11219            jtab = setNextItem (IC_JTLABELS (ic)))
11220         emitcode ("ljmp", "%05d$", jtab->key + 100);
11221     }
11222   else
11223     {
11224       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11225          if the switch argument is in a register.
11226          For n>6 this algorithm may be more compact */
11227       jtablo = newiTempLabel (NULL);
11228       jtabhi = newiTempLabel (NULL);
11229
11230       /* get the condition into accumulator.
11231          Using b as temporary storage, if register push/pop is needed */
11232       aopOp (IC_JTCOND (ic), ic, FALSE);
11233       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11234       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11235           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11236         {
11237           // (MB) what if B is in use???
11238           wassertl(!BINUSE, "B was in use");
11239           emitcode ("mov", "b,%s", l);
11240           l = "b";
11241         }
11242       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11243       MOVA (l);
11244       if( count <= 112 )
11245         {
11246           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11247           emitcode ("movc", "a,@a+pc");
11248           emitcode ("push", "acc");
11249
11250           MOVA (l);
11251           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11252           emitcode ("movc", "a,@a+pc");
11253           emitcode ("push", "acc");
11254         }
11255       else
11256         {
11257           /* this scales up to n<=255, but needs two more bytes
11258              and changes dptr */
11259           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11260           emitcode ("movc", "a,@a+dptr");
11261           emitcode ("push", "acc");
11262
11263           MOVA (l);
11264           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11265           emitcode ("movc", "a,@a+dptr");
11266           emitcode ("push", "acc");
11267         }
11268
11269       emitcode ("ret", "");
11270
11271       /* now generate jump table, LSB */
11272       emitLabel (jtablo);
11273       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11274            jtab = setNextItem (IC_JTLABELS (ic)))
11275         emitcode (".db", "%05d$", jtab->key + 100);
11276
11277       /* now generate jump table, MSB */
11278       emitLabel (jtabhi);
11279       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11280            jtab = setNextItem (IC_JTLABELS (ic)))
11281          emitcode (".db", "%05d$>>8", jtab->key + 100);
11282     }
11283 }
11284
11285 /*-----------------------------------------------------------------*/
11286 /* genCast - gen code for casting                                  */
11287 /*-----------------------------------------------------------------*/
11288 static void
11289 genCast (iCode * ic)
11290 {
11291   operand *result = IC_RESULT (ic);
11292   sym_link *ctype = operandType (IC_LEFT (ic));
11293   sym_link *rtype = operandType (IC_RIGHT (ic));
11294   operand *right = IC_RIGHT (ic);
11295   int size, offset;
11296
11297   D (emitcode (";", "genCast"));
11298
11299   /* if they are equivalent then do nothing */
11300   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11301     return;
11302
11303   aopOp (right, ic, FALSE);
11304   aopOp (result, ic, FALSE);
11305
11306   /* if the result is a bit (and not a bitfield) */
11307   if (IS_BIT (OP_SYMBOL (result)->type))
11308     {
11309       assignBit (result, right);
11310       goto release;
11311     }
11312
11313   /* if they are the same size : or less */
11314   if (AOP_SIZE (result) <= AOP_SIZE (right))
11315     {
11316
11317       /* if they are in the same place */
11318       if (sameRegs (AOP (right), AOP (result)))
11319         goto release;
11320
11321       /* if they in different places then copy */
11322       size = AOP_SIZE (result);
11323       offset = 0;
11324       while (size--)
11325         {
11326           aopPut (result,
11327                   aopGet (right, offset, FALSE, FALSE),
11328                   offset);
11329           offset++;
11330         }
11331       goto release;
11332     }
11333
11334   /* if the result is of type pointer */
11335   if (IS_PTR (ctype))
11336     {
11337
11338       int p_type;
11339       sym_link *type = operandType (right);
11340       sym_link *etype = getSpec (type);
11341
11342       /* pointer to generic pointer */
11343       if (IS_GENPTR (ctype))
11344         {
11345           if (IS_PTR (type))
11346             {
11347               p_type = DCL_TYPE (type);
11348             }
11349           else
11350             {
11351               if (SPEC_SCLS(etype)==S_REGISTER) {
11352                 // let's assume it is a generic pointer
11353                 p_type=GPOINTER;
11354               } else {
11355                 /* we have to go by the storage class */
11356                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11357               }
11358             }
11359
11360           /* the first two bytes are known */
11361           size = GPTRSIZE - 1;
11362           offset = 0;
11363           while (size--)
11364             {
11365               aopPut (result,
11366                       aopGet (right, offset, FALSE, FALSE),
11367                       offset);
11368               offset++;
11369             }
11370           /* the last byte depending on type */
11371             {
11372                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11373                 char gpValStr[10];
11374
11375                 if (gpVal == -1)
11376                 {
11377                     // pointerTypeToGPByte will have bitched.
11378                     exit(1);
11379                 }
11380
11381                 sprintf(gpValStr, "#0x%x", gpVal);
11382                 aopPut (result, gpValStr, GPTRSIZE - 1);
11383             }
11384           goto release;
11385         }
11386
11387       /* just copy the pointers */
11388       size = AOP_SIZE (result);
11389       offset = 0;
11390       while (size--)
11391         {
11392           aopPut (result,
11393                   aopGet (right, offset, FALSE, FALSE),
11394                   offset);
11395           offset++;
11396         }
11397       goto release;
11398     }
11399
11400   /* so we now know that the size of destination is greater
11401      than the size of the source */
11402   /* we move to result for the size of source */
11403   size = AOP_SIZE (right);
11404   offset = 0;
11405   while (size--)
11406     {
11407       aopPut (result,
11408               aopGet (right, offset, FALSE, FALSE),
11409               offset);
11410       offset++;
11411     }
11412
11413   /* now depending on the sign of the source && destination */
11414   size = AOP_SIZE (result) - AOP_SIZE (right);
11415   /* if unsigned or not an integral type */
11416   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11417     {
11418       while (size--)
11419         aopPut (result, zero, offset++);
11420     }
11421   else
11422     {
11423       /* we need to extend the sign :{ */
11424       char *l = aopGet (right, AOP_SIZE (right) - 1,
11425                         FALSE, FALSE);
11426       MOVA (l);
11427       emitcode ("rlc", "a");
11428       emitcode ("subb", "a,acc");
11429       while (size--)
11430         aopPut (result, "a", offset++);
11431     }
11432
11433   /* we are done hurray !!!! */
11434
11435 release:
11436   freeAsmop (result, NULL, ic, TRUE);
11437   freeAsmop (right, NULL, ic, TRUE);
11438 }
11439
11440 /*-----------------------------------------------------------------*/
11441 /* genDjnz - generate decrement & jump if not zero instrucion      */
11442 /*-----------------------------------------------------------------*/
11443 static int
11444 genDjnz (iCode * ic, iCode * ifx)
11445 {
11446   symbol *lbl, *lbl1;
11447   if (!ifx)
11448     return 0;
11449
11450   /* if the if condition has a false label
11451      then we cannot save */
11452   if (IC_FALSE (ifx))
11453     return 0;
11454
11455   /* if the minus is not of the form a = a - 1 */
11456   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11457       !IS_OP_LITERAL (IC_RIGHT (ic)))
11458     return 0;
11459
11460   if (operandLitValue (IC_RIGHT (ic)) != 1)
11461     return 0;
11462
11463   /* if the size of this greater than one then no
11464      saving */
11465   if (getSize (operandType (IC_RESULT (ic))) > 1)
11466     return 0;
11467
11468   /* otherwise we can save BIG */
11469
11470   D (emitcode (";", "genDjnz"));
11471
11472   lbl = newiTempLabel (NULL);
11473   lbl1 = newiTempLabel (NULL);
11474
11475   aopOp (IC_RESULT (ic), ic, FALSE);
11476
11477   if (AOP_NEEDSACC(IC_RESULT(ic)))
11478   {
11479       /* If the result is accessed indirectly via
11480        * the accumulator, we must explicitly write
11481        * it back after the decrement.
11482        */
11483       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11484
11485       if (strcmp(rByte, "a"))
11486       {
11487            /* Something is hopelessly wrong */
11488            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11489                    __FILE__, __LINE__);
11490            /* We can just give up; the generated code will be inefficient,
11491             * but what the hey.
11492             */
11493            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11494            return 0;
11495       }
11496       emitcode ("dec", "%s", rByte);
11497       aopPut (IC_RESULT (ic), rByte, 0);
11498       emitcode ("jnz", "%05d$", lbl->key + 100);
11499   }
11500   else if (IS_AOP_PREG (IC_RESULT (ic)))
11501     {
11502       emitcode ("dec", "%s",
11503                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11504       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11505       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11506       ifx->generated = 1;
11507       emitcode ("jnz", "%05d$", lbl->key + 100);
11508     }
11509   else
11510     {
11511       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11512                 lbl->key + 100);
11513     }
11514   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11515   emitLabel (lbl);
11516   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11517   emitLabel (lbl1);
11518
11519   if (!ifx->generated)
11520       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11521   ifx->generated = 1;
11522   return 1;
11523 }
11524
11525 /*-----------------------------------------------------------------*/
11526 /* genReceive - generate code for a receive iCode                  */
11527 /*-----------------------------------------------------------------*/
11528 static void
11529 genReceive (iCode * ic)
11530 {
11531   int size = getSize (operandType (IC_RESULT (ic)));
11532   int offset = 0;
11533
11534   D (emitcode (";", "genReceive"));
11535
11536   if (ic->argreg == 1)
11537     { /* first parameter */
11538       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11539            isOperandInPagedSpace (IC_RESULT (ic))) &&
11540           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11541            IS_TRUE_SYMOP (IC_RESULT (ic))))
11542         {
11543           regs *tempRegs[4];
11544           int receivingA = 0;
11545           int roffset = 0;
11546
11547           for (offset = 0; offset<size; offset++)
11548             if (!strcmp (fReturn[offset], "a"))
11549               receivingA = 1;
11550
11551           if (!receivingA)
11552             {
11553               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11554                 {
11555                   for (offset = size-1; offset>0; offset--)
11556                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11557                   emitcode("mov","a,%s", fReturn[0]);
11558                   _G.accInUse++;
11559                   aopOp (IC_RESULT (ic), ic, FALSE);
11560                   _G.accInUse--;
11561                   aopPut (IC_RESULT (ic), "a", offset);
11562                   for (offset = 1; offset<size; offset++)
11563                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11564                   goto release;
11565                 }
11566             }
11567           else
11568             {
11569               if (getTempRegs(tempRegs, size, ic))
11570                 {
11571                   for (offset = 0; offset<size; offset++)
11572                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11573                   aopOp (IC_RESULT (ic), ic, FALSE);
11574                   for (offset = 0; offset<size; offset++)
11575                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11576                   goto release;
11577                 }
11578             }
11579
11580           offset = fReturnSizeMCS51 - size;
11581           while (size--)
11582             {
11583               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11584                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11585               offset++;
11586             }
11587           aopOp (IC_RESULT (ic), ic, FALSE);
11588           size = AOP_SIZE (IC_RESULT (ic));
11589           offset = 0;
11590           while (size--)
11591             {
11592               emitcode ("pop", "acc");
11593               aopPut (IC_RESULT (ic), "a", offset++);
11594             }
11595         }
11596       else
11597         {
11598           _G.accInUse++;
11599           aopOp (IC_RESULT (ic), ic, FALSE);
11600           _G.accInUse--;
11601           assignResultValue (IC_RESULT (ic), NULL);
11602         }
11603     }
11604   else if (ic->argreg > 12)
11605     { /* bit parameters */
11606       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11607         {
11608           aopOp (IC_RESULT (ic), ic, FALSE);
11609           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11610           outBitC(IC_RESULT (ic));
11611         }
11612     }
11613   else
11614     { /* other parameters */
11615       int rb1off ;
11616       aopOp (IC_RESULT (ic), ic, FALSE);
11617       rb1off = ic->argreg;
11618       while (size--)
11619         {
11620           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11621         }
11622     }
11623
11624 release:
11625   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11626 }
11627
11628 /*-----------------------------------------------------------------*/
11629 /* genDummyRead - generate code for dummy read of volatiles        */
11630 /*-----------------------------------------------------------------*/
11631 static void
11632 genDummyRead (iCode * ic)
11633 {
11634   operand *op;
11635   int size, offset;
11636
11637   D (emitcode(";", "genDummyRead"));
11638
11639   op = IC_RIGHT (ic);
11640   if (op && IS_SYMOP (op))
11641     {
11642       aopOp (op, ic, FALSE);
11643
11644       /* if the result is a bit */
11645       if (AOP_TYPE (op) == AOP_CRY)
11646         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11647       else
11648         {
11649           /* bit variables done */
11650           /* general case */
11651           size = AOP_SIZE (op);
11652           offset = 0;
11653           while (size--)
11654           {
11655             MOVA (aopGet (op, offset, FALSE, FALSE));
11656             offset++;
11657           }
11658         }
11659
11660       freeAsmop (op, NULL, ic, TRUE);
11661     }
11662
11663   op = IC_LEFT (ic);
11664   if (op && IS_SYMOP (op))
11665     {
11666       aopOp (op, ic, FALSE);
11667
11668       /* if the result is a bit */
11669       if (AOP_TYPE (op) == AOP_CRY)
11670         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11671       else
11672         {
11673           /* bit variables done */
11674           /* general case */
11675           size = AOP_SIZE (op);
11676           offset = 0;
11677           while (size--)
11678           {
11679             MOVA (aopGet (op, offset, FALSE, FALSE));
11680             offset++;
11681           }
11682         }
11683
11684       freeAsmop (op, NULL, ic, TRUE);
11685     }
11686 }
11687
11688 /*-----------------------------------------------------------------*/
11689 /* genCritical - generate code for start of a critical sequence    */
11690 /*-----------------------------------------------------------------*/
11691 static void
11692 genCritical (iCode *ic)
11693 {
11694   symbol *tlbl = newiTempLabel (NULL);
11695
11696   D (emitcode(";", "genCritical"));
11697
11698   if (IC_RESULT (ic))
11699     {
11700       aopOp (IC_RESULT (ic), ic, TRUE);
11701       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11702       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11703       aopPut (IC_RESULT (ic), zero, 0);
11704       emitLabel (tlbl);
11705       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11706     }
11707   else
11708     {
11709       emitcode ("setb", "c");
11710       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11711       emitcode ("clr", "c");
11712       emitLabel (tlbl);
11713       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11714     }
11715 }
11716
11717 /*-----------------------------------------------------------------*/
11718 /* genEndCritical - generate code for end of a critical sequence   */
11719 /*-----------------------------------------------------------------*/
11720 static void
11721 genEndCritical (iCode *ic)
11722 {
11723   D(emitcode(";", "genEndCritical"));
11724
11725   if (IC_RIGHT (ic))
11726     {
11727       aopOp (IC_RIGHT (ic), ic, FALSE);
11728       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11729         {
11730           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11731           emitcode ("mov", "ea,c");
11732         }
11733       else
11734         {
11735           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11736             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11737           emitcode ("rrc", "a");
11738           emitcode ("mov", "ea,c");
11739         }
11740       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11741     }
11742   else
11743     {
11744       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11745       emitcode ("mov", "ea,c");
11746     }
11747 }
11748
11749 /*-----------------------------------------------------------------*/
11750 /* gen51Code - generate code for 8051 based controllers            */
11751 /*-----------------------------------------------------------------*/
11752 void
11753 gen51Code (iCode * lic)
11754 {
11755   iCode *ic;
11756   int cln = 0;
11757   /* int cseq = 0; */
11758
11759   _G.currentFunc = NULL;
11760   lineHead = lineCurr = NULL;
11761
11762   /* print the allocation information */
11763   if (allocInfo && currFunc)
11764     printAllocInfo (currFunc, codeOutBuf);
11765   /* if debug information required */
11766   if (options.debug && currFunc)
11767     {
11768       debugFile->writeFunction (currFunc, lic);
11769     }
11770   /* stack pointer name */
11771   if (options.useXstack)
11772     spname = "_spx";
11773   else
11774     spname = "sp";
11775
11776
11777   for (ic = lic; ic; ic = ic->next)
11778     {
11779       _G.current_iCode = ic;
11780
11781       if (ic->lineno && cln != ic->lineno)
11782         {
11783           if (options.debug)
11784             {
11785               debugFile->writeCLine (ic);
11786             }
11787           if (!options.noCcodeInAsm) {
11788             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11789                       printCLine(ic->filename, ic->lineno));
11790           }
11791           cln = ic->lineno;
11792         }
11793       #if 0
11794       if (ic->seqPoint && ic->seqPoint != cseq)
11795         {
11796           emitcode (";", "sequence point %d", ic->seqPoint);
11797           cseq = ic->seqPoint;
11798         }
11799       #endif
11800       if (options.iCodeInAsm) {
11801         char regsInUse[80];
11802         int i;
11803         char *iLine;
11804
11805         #if 0
11806         for (i=0; i<8; i++) {
11807           sprintf (&regsInUse[i],
11808                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11809         regsInUse[i]=0;
11810         #else
11811         strcpy (regsInUse, "--------");
11812         for (i=0; i < 8; i++) {
11813           if (bitVectBitValue (ic->rMask, i))
11814             {
11815               int offset = regs8051[i].offset;
11816               regsInUse[offset] = offset + '0'; /* show rMask */
11817             }
11818         #endif
11819         }
11820         iLine = printILine(ic);
11821         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11822         dbuf_free(iLine);
11823       }
11824       /* if the result is marked as
11825          spilt and rematerializable or code for
11826          this has already been generated then
11827          do nothing */
11828       if (resultRemat (ic) || ic->generated)
11829         continue;
11830
11831       /* depending on the operation */
11832       switch (ic->op)
11833         {
11834         case '!':
11835           genNot (ic);
11836           break;
11837
11838         case '~':
11839           genCpl (ic);
11840           break;
11841
11842         case UNARYMINUS:
11843           genUminus (ic);
11844           break;
11845
11846         case IPUSH:
11847           genIpush (ic);
11848           break;
11849
11850         case IPOP:
11851           /* IPOP happens only when trying to restore a
11852              spilt live range, if there is an ifx statement
11853              following this pop then the if statement might
11854              be using some of the registers being popped which
11855              would destory the contents of the register so
11856              we need to check for this condition and handle it */
11857           if (ic->next &&
11858               ic->next->op == IFX &&
11859               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11860             genIfx (ic->next, ic);
11861           else
11862             genIpop (ic);
11863           break;
11864
11865         case CALL:
11866           genCall (ic);
11867           break;
11868
11869         case PCALL:
11870           genPcall (ic);
11871           break;
11872
11873         case FUNCTION:
11874           genFunction (ic);
11875           break;
11876
11877         case ENDFUNCTION:
11878           genEndFunction (ic);
11879           break;
11880
11881         case RETURN:
11882           genRet (ic);
11883           break;
11884
11885         case LABEL:
11886           genLabel (ic);
11887           break;
11888
11889         case GOTO:
11890           genGoto (ic);
11891           break;
11892
11893         case '+':
11894           genPlus (ic);
11895           break;
11896
11897         case '-':
11898           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11899             genMinus (ic);
11900           break;
11901
11902         case '*':
11903           genMult (ic);
11904           break;
11905
11906         case '/':
11907           genDiv (ic);
11908           break;
11909
11910         case '%':
11911           genMod (ic);
11912           break;
11913
11914         case '>':
11915           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11916           break;
11917
11918         case '<':
11919           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11920           break;
11921
11922         case LE_OP:
11923         case GE_OP:
11924         case NE_OP:
11925
11926           /* note these two are xlated by algebraic equivalence
11927              in decorateType() in SDCCast.c */
11928           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11929                   "got '>=' or '<=' shouldn't have come here");
11930           break;
11931
11932         case EQ_OP:
11933           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11934           break;
11935
11936         case AND_OP:
11937           genAndOp (ic);
11938           break;
11939
11940         case OR_OP:
11941           genOrOp (ic);
11942           break;
11943
11944         case '^':
11945           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11946           break;
11947
11948         case '|':
11949           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11950           break;
11951
11952         case BITWISEAND:
11953           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11954           break;
11955
11956         case INLINEASM:
11957           genInline (ic);
11958           break;
11959
11960         case RRC:
11961           genRRC (ic);
11962           break;
11963
11964         case RLC:
11965           genRLC (ic);
11966           break;
11967
11968         case GETHBIT:
11969           genGetHbit (ic);
11970           break;
11971
11972         case GETABIT:
11973           genGetAbit (ic);
11974           break;
11975
11976         case GETBYTE:
11977           genGetByte (ic);
11978           break;
11979
11980         case GETWORD:
11981           genGetWord (ic);
11982           break;
11983
11984         case LEFT_OP:
11985           genLeftShift (ic);
11986           break;
11987
11988         case RIGHT_OP:
11989           genRightShift (ic);
11990           break;
11991
11992         case GET_VALUE_AT_ADDRESS:
11993           genPointerGet (ic,
11994                          hasInc (IC_LEFT (ic), ic,
11995                                  getSize (operandType (IC_RESULT (ic)))),
11996                          ifxForOp (IC_RESULT (ic), ic) );
11997           break;
11998
11999         case '=':
12000           if (POINTER_SET (ic))
12001             genPointerSet (ic,
12002                            hasInc (IC_RESULT (ic), ic,
12003                                    getSize (operandType (IC_RIGHT (ic)))));
12004           else
12005             genAssign (ic);
12006           break;
12007
12008         case IFX:
12009           genIfx (ic, NULL);
12010           break;
12011
12012         case ADDRESS_OF:
12013           genAddrOf (ic);
12014           break;
12015
12016         case JUMPTABLE:
12017           genJumpTab (ic);
12018           break;
12019
12020         case CAST:
12021           genCast (ic);
12022           break;
12023
12024         case RECEIVE:
12025           genReceive (ic);
12026           break;
12027
12028         case SEND:
12029           addSet (&_G.sendSet, ic);
12030           break;
12031
12032         case DUMMY_READ_VOLATILE:
12033           genDummyRead (ic);
12034           break;
12035
12036         case CRITICAL:
12037           genCritical (ic);
12038           break;
12039
12040         case ENDCRITICAL:
12041           genEndCritical (ic);
12042           break;
12043
12044         case SWAP:
12045           genSwap (ic);
12046           break;
12047
12048         default:
12049           ic = ic;
12050         }
12051     }
12052
12053   _G.current_iCode = NULL;
12054
12055   /* now we are ready to call the
12056      peep hole optimizer */
12057   if (!options.nopeep)
12058     peepHole (&lineHead);
12059
12060   /* now do the actual printing */
12061   printLine (lineHead, codeOutBuf);
12062   return;
12063 }