* src/mcs51/gen.c, src/avr/gen.c, src/pic/gen.c, src/z80/gen.c,
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
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   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) do if (options.verboseAsm) {x;} while(0)
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                        AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC    emitcode("clr","c")
170 #define SETC    emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227       }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerialzes an object                           */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic)) {
908               sym_link *from_type = operandType(IC_RIGHT(ic));
909               aop->aopu.aop_immd.from_cast_remat = 1;
910               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
911               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
912               continue;
913       } else break;
914
915       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
916     }
917
918   if (val)
919   {
920       SNPRINTF (buffer, sizeof(buffer),
921                 "(%s %c 0x%06x)",
922                 OP_SYMBOL (IC_LEFT (ic))->rname,
923                 val >= 0 ? '+' : '-',
924                 abs (val) & 0xffffff);
925   }
926   else
927   {
928       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
929       {
930           SNPRINTF(buffer, sizeof(buffer),
931                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
932       }
933       else
934       {
935           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
936       }
937   }
938
939   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
940   /* set immd2 field if required */
941   if (aop->aopu.aop_immd.from_cast_remat)
942   {
943       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
944       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
945   }
946
947   return aop;
948 }
949
950 /*-----------------------------------------------------------------*/
951 /* aopHasRegs - returns true if aop has regs between from-to       */
952 /*-----------------------------------------------------------------*/
953 static int aopHasRegs(asmop *aop, int from, int to)
954 {
955     int size =0;
956
957     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
958
959     for (; size < aop->size ; size++) {
960         int reg;
961         for (reg = from ; reg <= to ; reg++)
962             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
963     }
964     return 0;
965 }
966
967 /*-----------------------------------------------------------------*/
968 /* regsInCommon - two operands have some registers in common       */
969 /*-----------------------------------------------------------------*/
970 static bool
971 regsInCommon (operand * op1, operand * op2)
972 {
973   symbol *sym1, *sym2;
974   int i;
975
976   /* if they have registers in common */
977   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
978     return FALSE;
979
980   sym1 = OP_SYMBOL (op1);
981   sym2 = OP_SYMBOL (op2);
982
983   if (sym1->nRegs == 0 || sym2->nRegs == 0)
984     return FALSE;
985
986   for (i = 0; i < sym1->nRegs; i++)
987     {
988       int j;
989       if (!sym1->regs[i])
990         continue;
991
992       for (j = 0; j < sym2->nRegs; j++)
993         {
994           if (!sym2->regs[j])
995             continue;
996
997           if (sym2->regs[j] == sym1->regs[i])
998             return TRUE;
999         }
1000     }
1001
1002   return FALSE;
1003 }
1004
1005 /*-----------------------------------------------------------------*/
1006 /* operandsEqu - equivalent                                        */
1007 /*-----------------------------------------------------------------*/
1008 static bool
1009 operandsEqu (operand * op1, operand * op2)
1010 {
1011   symbol *sym1, *sym2;
1012
1013   /* if they're not symbols */
1014   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1015     return FALSE;
1016
1017   sym1 = OP_SYMBOL (op1);
1018   sym2 = OP_SYMBOL (op2);
1019
1020   /* if both are itemps & one is spilt
1021      and the other is not then false */
1022   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1023       sym1->isspilt != sym2->isspilt)
1024     return FALSE;
1025
1026   /* if they are the same */
1027   if (sym1 == sym2)
1028     return TRUE;
1029
1030   /* if they have the same rname */
1031   if (sym1->rname[0] && sym2->rname[0] &&
1032       strcmp (sym1->rname, sym2->rname) == 0 &&
1033       !(IS_PARM (op2) && IS_ITEMP (op1)))
1034     return TRUE;
1035
1036   /* if left is a tmp & right is not */
1037   if (IS_ITEMP (op1) &&
1038       !IS_ITEMP (op2) &&
1039       sym1->isspilt &&
1040       (sym1->usl.spillLoc == sym2))
1041     return TRUE;
1042
1043   if (IS_ITEMP (op2) &&
1044       !IS_ITEMP (op1) &&
1045       sym2->isspilt &&
1046       sym1->level > 0 &&
1047       (sym2->usl.spillLoc == sym1))
1048     return TRUE;
1049
1050   /* are they spilt to the same location */
1051   if (IS_ITEMP (op2) &&
1052       IS_ITEMP (op1) &&
1053       sym2->isspilt &&
1054       sym1->isspilt &&
1055       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1056     return TRUE;
1057
1058   return FALSE;
1059 }
1060
1061 /*-----------------------------------------------------------------*/
1062 /* sameRegs - two asmops have the same registers                   */
1063 /*-----------------------------------------------------------------*/
1064 static bool
1065 sameRegs (asmop * aop1, asmop * aop2)
1066 {
1067   int i;
1068
1069   if (aop1 == aop2)
1070     {
1071       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1072         {
1073           return FALSE;
1074         }
1075       return TRUE;
1076     }
1077
1078   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1079     return FALSE;
1080
1081   if (aop1->type != aop2->type)
1082     return FALSE;
1083
1084   if (aop1->size != aop2->size)
1085     return FALSE;
1086
1087   for (i = 0; i < aop1->size; i++)
1088     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1089       return FALSE;
1090
1091   return TRUE;
1092 }
1093
1094 /*-----------------------------------------------------------------*/
1095 /* aopOp - allocates an asmop for an operand  :                    */
1096 /*-----------------------------------------------------------------*/
1097 static void
1098 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1099 {
1100   asmop *aop;
1101   symbol *sym;
1102   int i;
1103
1104   if (!op)
1105     return;
1106
1107   /* if this a literal */
1108   if (IS_OP_LITERAL (op))
1109     {
1110       op->aop = aop = newAsmop (AOP_LIT);
1111       aop->aopu.aop_lit = op->operand.valOperand;
1112       aop->size = getSize (operandType (op));
1113       return;
1114     }
1115
1116   /* if already has a asmop then continue */
1117   if (op->aop)
1118     {
1119       if ((op->aop->type == AOP_DPTR && useDP2)
1120           || (op->aop->type == AOP_DPTR2 && !useDP2))
1121         op->aop = NULL;
1122       else
1123         {
1124           op->aop->allocated++;
1125           return;
1126         }
1127     }
1128
1129   /* if the underlying symbol has a aop */
1130   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1131     {
1132       op->aop = OP_SYMBOL (op)->aop;
1133       if ((op->aop->type == AOP_DPTR && useDP2)
1134           || (op->aop->type == AOP_DPTR2 && !useDP2))
1135         op->aop = NULL;
1136       else
1137         {
1138           op->aop->allocated++;
1139           return;
1140         }
1141     }
1142
1143   /* if this is a true symbol */
1144   if (IS_TRUE_SYMOP (op))
1145     {
1146       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1147       return;
1148     }
1149
1150   /* this is a temporary : this has
1151      only five choices :
1152      a) register
1153      b) spillocation
1154      c) rematerialize
1155      d) conditional
1156      e) can be a return use only */
1157
1158   sym = OP_SYMBOL (op);
1159
1160   /* if the type is a conditional */
1161   if (sym->regType == REG_CND)
1162     {
1163       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1164       aop->size = 0;
1165       return;
1166     }
1167
1168   /* if it is spilt then two situations
1169      a) is rematerialize
1170      b) has a spill location */
1171   if (sym->isspilt || sym->nRegs == 0)
1172     {
1173
1174       /* rematerialize it NOW */
1175       if (sym->remat)
1176         {
1177           sym->aop = op->aop = aop =
1178             aopForRemat (sym);
1179           aop->size = getSize (sym->type);
1180           return;
1181         }
1182
1183       if (sym->accuse)
1184         {
1185           int i;
1186           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1187           aop->size = getSize (sym->type);
1188           for (i = 0; i < 2; i++)
1189             aop->aopu.aop_str[i] = accUse[i];
1190           return;
1191         }
1192
1193       if (sym->ruonly)
1194         {
1195           unsigned i;
1196
1197           if (useDP2)
1198             {
1199               /* a AOP_STR uses DPTR, but DPTR is already in use;
1200                * we're just hosed.
1201                */
1202                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1203             }
1204
1205           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1206           aop->size = getSize (sym->type);
1207           for (i = 0; i < fReturnSizeDS390; i++)
1208             aop->aopu.aop_str[i] = fReturn[i];
1209           return;
1210         }
1211
1212       if (sym->dptr) { /* has been allocated to a DPTRn */
1213           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1214           aop->size = getSize (sym->type);
1215           aop->aopu.dptr = sym->dptr;
1216           return ;
1217       }
1218
1219       if (sym->usl.spillLoc)
1220         {
1221           asmop *oldAsmOp = NULL;
1222
1223           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1224             {
1225               /* force a new aop if sizes differ */
1226               oldAsmOp = sym->usl.spillLoc->aop;
1227               sym->usl.spillLoc->aop = NULL;
1228             }
1229           sym->aop = op->aop = aop =
1230                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1231           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1232             {
1233               /* Don't reuse the new aop, go with the last one */
1234               sym->usl.spillLoc->aop = oldAsmOp;
1235             }
1236           aop->size = getSize (sym->type);
1237           return;
1238         }
1239
1240       /* else must be a dummy iTemp */
1241       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1242       aop->size = getSize (sym->type);
1243       return;
1244     }
1245
1246   /* if the type is a bit register */
1247   if (sym->regType == REG_BIT)
1248     {
1249       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1250       aop->size = sym->nRegs;//1???
1251       aop->aopu.aop_reg[0] = sym->regs[0];
1252       aop->aopu.aop_dir = sym->regs[0]->name;
1253       return;
1254     }
1255
1256   /* must be in a register */
1257   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1258   aop->size = sym->nRegs;
1259   for (i = 0; i < sym->nRegs; i++)
1260     aop->aopu.aop_reg[i] = sym->regs[i];
1261 }
1262
1263 /*-----------------------------------------------------------------*/
1264 /* freeAsmop - free up the asmop given to an operand               */
1265 /*----------------------------------------------------------------*/
1266 static void
1267 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1268 {
1269   asmop *aop;
1270
1271   if (!op)
1272     aop = aaop;
1273   else
1274     aop = op->aop;
1275
1276   if (!aop)
1277     return;
1278
1279   aop->allocated--;
1280
1281   if (aop->allocated)
1282     goto dealloc;
1283
1284   /* depending on the asmop type only three cases need work
1285      AOP_R0, AOP_R1 & AOP_STK */
1286   switch (aop->type)
1287     {
1288     case AOP_R0:
1289       if (_G.r0Pushed)
1290         {
1291           if (pop)
1292             {
1293               emitcode ("pop", "ar0");
1294               _G.r0Pushed--;
1295             }
1296         }
1297       bitVectUnSetBit (ic->rUsed, R0_IDX);
1298       break;
1299
1300     case AOP_R1:
1301       if (_G.r1Pushed)
1302         {
1303           if (pop)
1304             {
1305               emitcode ("pop", "ar1");
1306               _G.r1Pushed--;
1307             }
1308         }
1309       bitVectUnSetBit (ic->rUsed, R1_IDX);
1310       break;
1311
1312     case AOP_STK:
1313       {
1314         int sz = aop->size;
1315         int stk = aop->aopu.aop_stk + aop->size;
1316         bitVectUnSetBit (ic->rUsed, R0_IDX);
1317         bitVectUnSetBit (ic->rUsed, R1_IDX);
1318
1319         getFreePtr (ic, &aop, FALSE);
1320
1321         if (options.stack10bit)
1322           {
1323             /* I'm not sure what to do here yet... */
1324             /* #STUB */
1325             fprintf (stderr,
1326                      "*** Warning: probably generating bad code for "
1327                      "10 bit stack mode.\n");
1328           }
1329
1330         if (stk)
1331           {
1332             emitcode ("mov", "a,_bp");
1333             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1334             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1335           }
1336         else
1337           {
1338             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1339           }
1340
1341         while (sz--)
1342           {
1343             emitcode ("pop", "acc");
1344             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1345             if (!sz)
1346               break;
1347             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1348           }
1349         op->aop = aop;
1350         freeAsmop (op, NULL, ic, TRUE);
1351         if (_G.r1Pushed)
1352           {
1353             emitcode ("pop", "ar1");
1354             _G.r1Pushed--;
1355           }
1356         if (_G.r0Pushed)
1357           {
1358             emitcode ("pop", "ar0");
1359             _G.r0Pushed--;
1360           }
1361       }
1362     case AOP_DPTR2:
1363         if (_G.dptr1InUse) {
1364             emitcode ("pop","dpx1");
1365             emitcode ("pop","dph1");
1366             emitcode ("pop","dpl1");
1367         }
1368         break;
1369     case AOP_DPTR:
1370         if (_G.dptrInUse) {
1371             emitcode ("pop","dpx");
1372             emitcode ("pop","dph");
1373             emitcode ("pop","dpl");
1374         }
1375         break;
1376     }
1377
1378 dealloc:
1379   /* all other cases just dealloc */
1380   if (op)
1381     {
1382       op->aop = NULL;
1383       if (IS_SYMOP (op))
1384         {
1385           OP_SYMBOL (op)->aop = NULL;
1386           /* if the symbol has a spill */
1387           if (SPIL_LOC (op))
1388             SPIL_LOC (op)->aop = NULL;
1389         }
1390     }
1391 }
1392
1393 #define DEFAULT_ACC_WARNING 0
1394 static int saveAccWarn = DEFAULT_ACC_WARNING;
1395
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1399 /*                 clobber the accumulator                         */
1400 /*-----------------------------------------------------------------*/
1401 static bool
1402 aopGetUsesAcc (operand * oper, int offset)
1403 {
1404   asmop * aop = AOP (oper);
1405
1406   if (offset > (aop->size - 1))
1407     return FALSE;
1408
1409   switch (aop->type)
1410     {
1411
1412     case AOP_R0:
1413     case AOP_R1:
1414       if (aop->paged)
1415         return TRUE;
1416       return FALSE;
1417     case AOP_DPTR:
1418     case AOP_DPTR2:
1419     case AOP_DPTRn:
1420       return TRUE;
1421     case AOP_IMMD:
1422       return FALSE;
1423     case AOP_DIR:
1424       return FALSE;
1425     case AOP_REG:
1426       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1427       return FALSE;
1428     case AOP_CRY:
1429       return TRUE;
1430     case AOP_ACC:
1431       if (offset)
1432         return FALSE;
1433       return TRUE;
1434     case AOP_LIT:
1435       return FALSE;
1436     case AOP_STR:
1437       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1438         return TRUE;
1439       return FALSE;
1440     case AOP_DUMMY:
1441       return FALSE;
1442     default:
1443       /* Error case --- will have been caught already */
1444       wassert(0);
1445       return FALSE;
1446     }
1447 }
1448
1449 /*-------------------------------------------------------------------*/
1450 /* aopGet - for fetching value of the aop                            */
1451 /*                                                                   */
1452 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1453 /* in the accumulator. Set it to the name of a free register         */
1454 /* if acc must be preserved; the register will be used to preserve   */
1455 /* acc temporarily and to return the result byte.                    */
1456 /*-------------------------------------------------------------------*/
1457 static char *
1458 aopGet (operand * oper,
1459         int   offset,
1460         bool  bit16,
1461         bool  dname,
1462         char  *saveAcc)
1463 {
1464   asmop * aop = AOP (oper);
1465
1466   /* offset is greater than
1467      size then zero */
1468   if (offset > (aop->size - 1) &&
1469       aop->type != AOP_LIT)
1470     return zero;
1471
1472   /* depending on type */
1473   switch (aop->type)
1474     {
1475     case AOP_DUMMY:
1476       return zero;
1477
1478     case AOP_R0:
1479     case AOP_R1:
1480       /* if we need to increment it */
1481       while (offset > aop->coff)
1482         {
1483           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1484           aop->coff++;
1485         }
1486
1487       while (offset < aop->coff)
1488         {
1489           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1490           aop->coff--;
1491         }
1492
1493       aop->coff = offset;
1494       if (aop->paged)
1495         {
1496           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1497           return (dname ? "acc" : "a");
1498         }
1499       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1500       return Safe_strdup(buffer);
1501
1502     case AOP_DPTRn:
1503         assert(offset <= 3);
1504         return dptrn[aop->aopu.dptr][offset];
1505
1506     case AOP_DPTR:
1507     case AOP_DPTR2:
1508
1509       if (aop->type == AOP_DPTR2)
1510         {
1511           genSetDPTR (1);
1512         }
1513
1514       if (saveAcc)
1515         {
1516             TR_AP("#1");
1517 //          if (aop->type != AOP_DPTR2)
1518 //          {
1519 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1520 //              emitcode(";", "spanky: saveAcc for DPTR");
1521 //          }
1522
1523             emitcode ("xch", "a, %s", saveAcc);
1524         }
1525
1526       _flushLazyDPS ();
1527
1528       while (offset > aop->coff)
1529         {
1530           emitcode ("inc", "dptr");
1531           aop->coff++;
1532         }
1533
1534       while (offset < aop->coff)
1535         {
1536           emitcode ("lcall", "__decdptr");
1537           aop->coff--;
1538         }
1539
1540       aop->coff = offset;
1541       if (aop->code)
1542         {
1543           emitcode ("clr", "a");
1544           emitcode ("movc", "a,@a+dptr");
1545         }
1546       else
1547         {
1548           emitcode ("movx", "a,@dptr");
1549         }
1550
1551       if (aop->type == AOP_DPTR2)
1552         {
1553           genSetDPTR (0);
1554         }
1555
1556       if (saveAcc)
1557         {
1558           TR_AP("#2");
1559           emitcode ("xch", "a, %s", saveAcc);
1560 //        if (strcmp(saveAcc, "_ap"))
1561 //          {
1562 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1563 //          }
1564
1565           return saveAcc;
1566         }
1567       return (dname ? "acc" : "a");
1568
1569     case AOP_IMMD:
1570       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1571         {
1572           SNPRINTF(buffer, sizeof(buffer),
1573                    "%s",aop->aopu.aop_immd.aop_immd2);
1574         }
1575       else if (bit16)
1576         {
1577           SNPRINTF(buffer, sizeof(buffer),
1578                    "#%s", aop->aopu.aop_immd.aop_immd1);
1579         }
1580       else if (offset)
1581         {
1582           switch (offset) {
1583           case 1:
1584               tsprintf(buffer, sizeof(buffer),
1585                        "#!his",aop->aopu.aop_immd.aop_immd1);
1586               break;
1587           case 2:
1588               tsprintf(buffer, sizeof(buffer),
1589                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1590               break;
1591           case 3:
1592               tsprintf(buffer, sizeof(buffer),
1593                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1594               break;
1595           default: /* should not need this (just in case) */
1596               SNPRINTF (buffer, sizeof(buffer),
1597                         "#(%s >> %d)",
1598                        aop->aopu.aop_immd.aop_immd1,
1599                        offset * 8);
1600           }
1601         }
1602       else
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "#%s",
1606                     aop->aopu.aop_immd.aop_immd1);
1607         }
1608       return Safe_strdup(buffer);
1609
1610     case AOP_DIR:
1611       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1612         {
1613           SNPRINTF (buffer, sizeof(buffer),
1614                     "(%s >> %d)",
1615                     aop->aopu.aop_dir, offset * 8);
1616         }
1617       else if (offset)
1618         {
1619           SNPRINTF (buffer, sizeof(buffer),
1620                     "(%s + %d)",
1621                    aop->aopu.aop_dir,
1622                    offset);
1623         }
1624       else
1625         {
1626           SNPRINTF (buffer, sizeof(buffer),
1627                     "%s",
1628                     aop->aopu.aop_dir);
1629         }
1630
1631       return Safe_strdup(buffer);
1632
1633     case AOP_REG:
1634       if (dname)
1635         return aop->aopu.aop_reg[offset]->dname;
1636       else
1637         return aop->aopu.aop_reg[offset]->name;
1638
1639     case AOP_CRY:
1640       emitcode ("clr", "a");
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("rlc", "a");
1643       return (dname ? "acc" : "a");
1644
1645     case AOP_ACC:
1646       if (!offset && dname)
1647         return "acc";
1648       return aop->aopu.aop_str[offset];
1649
1650     case AOP_LIT:
1651       return aopLiteral (aop->aopu.aop_lit, offset);
1652
1653     case AOP_STR:
1654       aop->coff = offset;
1655       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1656           dname)
1657         return "acc";
1658
1659       return aop->aopu.aop_str[offset];
1660
1661     }
1662
1663   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1664           "aopget got unsupported aop->type");
1665   exit (1);
1666
1667   return NULL;  // not reached, but makes compiler happy.
1668 }
1669
1670 /*-----------------------------------------------------------------*/
1671 /* aopPut - puts a string for a aop and indicates if acc is in use */
1672 /*-----------------------------------------------------------------*/
1673 static bool
1674 aopPut (operand * result, const char *s, int offset)
1675 {
1676   bool bvolatile = isOperandVolatile (result, FALSE);
1677   bool accuse = FALSE;
1678   asmop * aop = AOP (result);
1679
1680   if (aop->size && offset > (aop->size - 1))
1681     {
1682       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1683               "aopPut got offset > aop->size");
1684       exit (1);
1685     }
1686
1687   /* will assign value to value */
1688   /* depending on where it is ofcourse */
1689   switch (aop->type)
1690     {
1691     case AOP_DUMMY:
1692       MOVA (s);         /* read s in case it was volatile */
1693       accuse = TRUE;
1694       break;
1695
1696     case AOP_DIR:
1697       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1698         {
1699           SNPRINTF (buffer, sizeof(buffer),
1700                     "(%s >> %d)",
1701                     aop->aopu.aop_dir, offset * 8);
1702         }
1703       else if (offset)
1704         {
1705           SNPRINTF (buffer, sizeof(buffer),
1706                     "(%s + %d)",
1707                     aop->aopu.aop_dir, offset);
1708         }
1709       else
1710         {
1711           SNPRINTF (buffer, sizeof(buffer),
1712                     "%s",
1713                     aop->aopu.aop_dir);
1714         }
1715
1716       if (strcmp (buffer, s) || bvolatile)
1717         {
1718           emitcode ("mov", "%s,%s", buffer, s);
1719         }
1720       if (!strcmp (buffer, "acc"))
1721         {
1722           accuse = TRUE;
1723         }
1724       break;
1725
1726     case AOP_REG:
1727       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1728           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1729         {
1730           if (*s == '@' ||
1731               strcmp (s, "r0") == 0 ||
1732               strcmp (s, "r1") == 0 ||
1733               strcmp (s, "r2") == 0 ||
1734               strcmp (s, "r3") == 0 ||
1735               strcmp (s, "r4") == 0 ||
1736               strcmp (s, "r5") == 0 ||
1737               strcmp (s, "r6") == 0 ||
1738               strcmp (s, "r7") == 0)
1739             {
1740               emitcode ("mov", "%s,%s",
1741                         aop->aopu.aop_reg[offset]->dname, s);
1742             }
1743             else
1744             {
1745               emitcode ("mov", "%s,%s",
1746                         aop->aopu.aop_reg[offset]->name, s);
1747             }
1748         }
1749       break;
1750
1751     case AOP_DPTRn:
1752         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1753         break;
1754
1755     case AOP_DPTR:
1756     case AOP_DPTR2:
1757
1758       if (aop->type == AOP_DPTR2)
1759         {
1760           genSetDPTR (1);
1761         }
1762       _flushLazyDPS ();
1763
1764       if (aop->code)
1765         {
1766           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1767                   "aopPut writing to code space");
1768           exit (1);
1769         }
1770
1771       while (offset > aop->coff)
1772         {
1773           aop->coff++;
1774           emitcode ("inc", "dptr");
1775         }
1776
1777       while (offset < aop->coff)
1778         {
1779           aop->coff--;
1780           emitcode ("lcall", "__decdptr");
1781         }
1782
1783       aop->coff = offset;
1784
1785       /* if not in accumulator */
1786       MOVA (s);
1787
1788       emitcode ("movx", "@dptr,a");
1789
1790       if (aop->type == AOP_DPTR2)
1791         {
1792           genSetDPTR (0);
1793         }
1794       break;
1795
1796     case AOP_R0:
1797     case AOP_R1:
1798       while (offset > aop->coff)
1799         {
1800           aop->coff++;
1801           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1802         }
1803       while (offset < aop->coff)
1804         {
1805           aop->coff--;
1806           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1807         }
1808       aop->coff = offset;
1809
1810       if (aop->paged)
1811         {
1812           MOVA (s);
1813           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1814         }
1815       else if (*s == '@')
1816         {
1817           MOVA (s);
1818           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1819         }
1820       else if (strcmp (s, "r0") == 0 ||
1821                strcmp (s, "r1") == 0 ||
1822                strcmp (s, "r2") == 0 ||
1823                strcmp (s, "r3") == 0 ||
1824                strcmp (s, "r4") == 0 ||
1825                strcmp (s, "r5") == 0 ||
1826                strcmp (s, "r6") == 0 ||
1827                strcmp (s, "r7") == 0)
1828         {
1829           char buffer[10];
1830           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1831           emitcode ("mov", "@%s,%s",
1832                     aop->aopu.aop_ptr->name, buffer);
1833         }
1834         else
1835         {
1836             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1837         }
1838       break;
1839
1840     case AOP_STK:
1841       if (strcmp (s, "a") == 0)
1842         emitcode ("push", "acc");
1843       else
1844         if (*s=='@') {
1845           MOVA(s);
1846           emitcode ("push", "acc");
1847         } else {
1848           emitcode ("push", s);
1849         }
1850
1851       break;
1852
1853     case AOP_CRY:
1854       /* if not bit variable */
1855       if (!aop->aopu.aop_dir)
1856         {
1857           /* inefficient: move carry into A and use jz/jnz */
1858           emitcode ("clr", "a");
1859           emitcode ("rlc", "a");
1860           accuse = TRUE;
1861         }
1862       else
1863         {
1864           if (s == zero)
1865             emitcode ("clr", "%s", aop->aopu.aop_dir);
1866           else if (s == one)
1867             emitcode ("setb", "%s", aop->aopu.aop_dir);
1868           else if (!strcmp (s, "c"))
1869             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1870           else if (strcmp (s, aop->aopu.aop_dir))
1871             {
1872               MOVA (s);
1873               /* set C, if a >= 1 */
1874               emitcode ("add", "a,#!constbyte",0xff);
1875               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1876             }
1877         }
1878       break;
1879
1880     case AOP_STR:
1881       aop->coff = offset;
1882       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1883         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1884       break;
1885
1886     case AOP_ACC:
1887       accuse = TRUE;
1888       aop->coff = offset;
1889       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1890         break;
1891
1892       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1893         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1894       break;
1895
1896     default:
1897       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1898               "aopPut got unsupported aop->type");
1899       exit (1);
1900     }
1901
1902     return accuse;
1903 }
1904
1905
1906 /*--------------------------------------------------------------------*/
1907 /* reAdjustPreg - points a register back to where it should (coff==0) */
1908 /*--------------------------------------------------------------------*/
1909 static void
1910 reAdjustPreg (asmop * aop)
1911 {
1912   if ((aop->coff==0) || (aop->size <= 1))
1913     return;
1914
1915   switch (aop->type)
1916     {
1917     case AOP_R0:
1918     case AOP_R1:
1919       while (aop->coff--)
1920         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1921       break;
1922     case AOP_DPTR:
1923     case AOP_DPTR2:
1924       if (aop->type == AOP_DPTR2)
1925         {
1926           genSetDPTR (1);
1927           _flushLazyDPS ();
1928         }
1929       while (aop->coff--)
1930         {
1931           emitcode ("lcall", "__decdptr");
1932         }
1933
1934       if (aop->type == AOP_DPTR2)
1935         {
1936           genSetDPTR (0);
1937         }
1938       break;
1939     }
1940   aop->coff = 0;
1941 }
1942
1943 /*-----------------------------------------------------------------*/
1944 /* opIsGptr: returns non-zero if the passed operand is       */
1945 /* a generic pointer type.             */
1946 /*-----------------------------------------------------------------*/
1947 static int
1948 opIsGptr (operand * op)
1949 {
1950   sym_link *type = operandType (op);
1951
1952   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1953     {
1954       return 1;
1955     }
1956   return 0;
1957 }
1958
1959 /*-----------------------------------------------------------------*/
1960 /* getDataSize - get the operand data size                         */
1961 /*-----------------------------------------------------------------*/
1962 static int
1963 getDataSize (operand * op)
1964 {
1965   int size;
1966   size = AOP_SIZE (op);
1967   if (size == GPTRSIZE)
1968     {
1969       sym_link *type = operandType (op);
1970       if (IS_GENPTR (type))
1971         {
1972           /* generic pointer; arithmetic operations
1973            * should ignore the high byte (pointer type).
1974            */
1975           size--;
1976         }
1977     }
1978   return size;
1979 }
1980
1981 /*-----------------------------------------------------------------*/
1982 /* outAcc - output Acc                                             */
1983 /*-----------------------------------------------------------------*/
1984 static void
1985 outAcc (operand * result)
1986 {
1987   int size, offset;
1988   size = getDataSize (result);
1989   if (size)
1990     {
1991       aopPut (result, "a", 0);
1992       size--;
1993       offset = 1;
1994       /* unsigned or positive */
1995       while (size--)
1996         {
1997           aopPut (result, zero, offset++);
1998         }
1999     }
2000 }
2001
2002 /*-----------------------------------------------------------------*/
2003 /* outBitC - output a bit C                                        */
2004 /*-----------------------------------------------------------------*/
2005 static void
2006 outBitC (operand * result)
2007 {
2008   /* if the result is bit */
2009   if (AOP_TYPE (result) == AOP_CRY)
2010     {
2011       aopPut (result, "c", 0);
2012     }
2013   else
2014     {
2015       emitcode ("clr", "a");
2016       emitcode ("rlc", "a");
2017       outAcc (result);
2018     }
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* toBoolean - emit code for orl a,operator(sizeop)                */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 toBoolean (operand * oper)
2026 {
2027   int  size = AOP_SIZE (oper) - 1;
2028   int  offset = 1;
2029   bool pushedB;
2030
2031   /* The generic part of a generic pointer should
2032    * not participate in it's truth value.
2033    *
2034    * i.e. 0x10000000 is zero.
2035    */
2036   if (opIsGptr (oper))
2037     {
2038       D (emitcode (";", "toBoolean: generic ptr special case."));
2039       size--;
2040     }
2041
2042   _startLazyDPSEvaluation ();
2043   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2044   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2045     {
2046       pushedB = pushB ();
2047       emitcode("mov", "b,a");
2048       while (--size)
2049         {
2050           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2051           emitcode ("orl", "b,a");
2052         }
2053       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2054       emitcode ("orl", "a,b");
2055       popB (pushedB);
2056     }
2057   else
2058     {
2059       while (size--)
2060         {
2061           emitcode ("orl", "a,%s",
2062                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2063         }
2064     }
2065   _endLazyDPSEvaluation ();
2066 }
2067
2068
2069 /*-----------------------------------------------------------------*/
2070 /* genNot - generate code for ! operation                          */
2071 /*-----------------------------------------------------------------*/
2072 static void
2073 genNot (iCode * ic)
2074 {
2075   symbol *tlbl;
2076
2077   D (emitcode (";", "genNot"));
2078
2079   /* assign asmOps to operand & result */
2080   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2081   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2082
2083   /* if in bit space then a special case */
2084   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2085     {
2086       /* if left==result then cpl bit */
2087       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2088         {
2089           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2090         }
2091       else
2092         {
2093           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2094           emitcode ("cpl", "c");
2095           outBitC (IC_RESULT (ic));
2096         }
2097       goto release;
2098     }
2099
2100   toBoolean (IC_LEFT (ic));
2101
2102   /* set C, if a == 0 */
2103   tlbl = newiTempLabel (NULL);
2104   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2105   emitLabel (tlbl);
2106   outBitC (IC_RESULT (ic));
2107
2108 release:
2109   /* release the aops */
2110   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2111   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2112 }
2113
2114
2115 /*-----------------------------------------------------------------*/
2116 /* genCpl - generate code for complement                           */
2117 /*-----------------------------------------------------------------*/
2118 static void
2119 genCpl (iCode * ic)
2120 {
2121   int offset = 0;
2122   int size;
2123   symbol *tlbl;
2124   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2125
2126   D(emitcode (";", "genCpl"));
2127
2128   /* assign asmOps to operand & result */
2129   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2130   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2131
2132   /* special case if in bit space */
2133   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2134     {
2135       char *l;
2136
2137       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2138           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2139         {
2140           /* promotion rules are responsible for this strange result:
2141              bit -> int -> ~int -> bit
2142              uchar -> int -> ~int -> bit
2143           */
2144           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2145           goto release;
2146         }
2147
2148       tlbl=newiTempLabel(NULL);
2149       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2150       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2151           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2152           IS_AOP_PREG (IC_LEFT (ic)))
2153         {
2154           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2155         }
2156       else
2157         {
2158           MOVA (l);
2159           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2160         }
2161       emitLabel (tlbl);
2162       outBitC (IC_RESULT(ic));
2163       goto release;
2164     }
2165
2166   size = AOP_SIZE (IC_RESULT (ic));
2167   _startLazyDPSEvaluation ();
2168   while (size--)
2169     {
2170       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2171       MOVA (l);
2172       emitcode ("cpl", "a");
2173       aopPut (IC_RESULT (ic), "a", offset++);
2174     }
2175   _endLazyDPSEvaluation ();
2176
2177
2178 release:
2179   /* release the aops */
2180   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2181   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2182 }
2183
2184 /*-----------------------------------------------------------------*/
2185 /* genUminusFloat - unary minus for floating points                */
2186 /*-----------------------------------------------------------------*/
2187 static void
2188 genUminusFloat (operand * op, operand * result)
2189 {
2190   int size, offset = 0;
2191   char *l;
2192
2193   D (emitcode (";", "genUminusFloat"));
2194
2195   /* for this we just copy and then flip the bit */
2196
2197   _startLazyDPSEvaluation ();
2198   size = AOP_SIZE (op) - 1;
2199
2200   while (size--)
2201     {
2202       aopPut (result,
2203               aopGet (op, offset, FALSE, FALSE, NULL),
2204               offset);
2205       offset++;
2206     }
2207
2208   l = aopGet (op, offset, FALSE, FALSE, NULL);
2209   MOVA (l);
2210
2211   emitcode ("cpl", "acc.7");
2212   aopPut (result, "a", offset);
2213   _endLazyDPSEvaluation ();
2214 }
2215
2216 /*-----------------------------------------------------------------*/
2217 /* genUminus - unary minus code generation                         */
2218 /*-----------------------------------------------------------------*/
2219 static void
2220 genUminus (iCode * ic)
2221 {
2222   int offset, size;
2223   sym_link *optype;
2224
2225   D (emitcode (";", "genUminus"));
2226
2227   /* assign asmops */
2228   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2229   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2230
2231   /* if both in bit space then special
2232      case */
2233   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2234       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2235     {
2236
2237       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2238       emitcode ("cpl", "c");
2239       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2240       goto release;
2241     }
2242
2243   optype = operandType (IC_LEFT (ic));
2244
2245   /* if float then do float stuff */
2246   if (IS_FLOAT (optype))
2247     {
2248       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2249       goto release;
2250     }
2251
2252   /* otherwise subtract from zero */
2253   size = AOP_SIZE (IC_LEFT (ic));
2254   offset = 0;
2255   _startLazyDPSEvaluation ();
2256   while (size--)
2257     {
2258       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2259       if (!strcmp (l, "a"))
2260         {
2261           if (offset == 0)
2262             SETC;
2263           emitcode ("cpl", "a");
2264           emitcode ("addc", "a,#0");
2265         }
2266       else
2267         {
2268           if (offset == 0)
2269             CLRC;
2270           emitcode ("clr", "a");
2271           emitcode ("subb", "a,%s", l);
2272         }
2273       aopPut (IC_RESULT (ic), "a", offset++);
2274     }
2275   _endLazyDPSEvaluation ();
2276
2277   /* if any remaining bytes in the result */
2278   /* we just need to propagate the sign   */
2279   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2280     {
2281       emitcode ("rlc", "a");
2282       emitcode ("subb", "a,acc");
2283       while (size--)
2284         aopPut (IC_RESULT (ic), "a", offset++);
2285     }
2286
2287 release:
2288   /* release the aops */
2289   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2290   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2291 }
2292
2293 /*-----------------------------------------------------------------*/
2294 /* savermask - saves registers in the mask                         */
2295 /*-----------------------------------------------------------------*/
2296 static void savermask(bitVect *rs_mask)
2297 {
2298   int i;
2299
2300   if (options.useXstack)
2301     {
2302       if (bitVectBitValue (rs_mask, R0_IDX))
2303           emitcode ("mov", "b,r0");
2304       emitcode ("mov", "r0,%s", spname);
2305       for (i = 0; i < ds390_nRegs; i++)
2306         {
2307           if (bitVectBitValue (rs_mask, i))
2308             {
2309               if (i == R0_IDX)
2310                   emitcode ("mov", "a,b");
2311               else
2312                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2313               emitcode ("movx", "@r0,a");
2314               emitcode ("inc", "r0");
2315             }
2316         }
2317       emitcode ("mov", "%s,r0", spname);
2318       if (bitVectBitValue (rs_mask, R0_IDX))
2319           emitcode ("mov", "r0,b");
2320     }
2321   else
2322     {
2323       bool bits_pushed = FALSE;
2324       for (i = 0; i < ds390_nRegs; i++)
2325         {
2326           if (bitVectBitValue (rs_mask, i))
2327             {
2328               bits_pushed = pushReg (i, bits_pushed);
2329             }
2330         }
2331     }
2332 }
2333
2334 /*-----------------------------------------------------------------*/
2335 /* saveRegisters - will look for a call and save the registers     */
2336 /*-----------------------------------------------------------------*/
2337 static void
2338 saveRegisters (iCode * lic)
2339 {
2340   iCode *ic;
2341   bitVect *rsave;
2342
2343   /* look for call */
2344   for (ic = lic; ic; ic = ic->next)
2345     if (ic->op == CALL || ic->op == PCALL)
2346       break;
2347
2348   if (!ic)
2349     {
2350       fprintf (stderr, "found parameter push with no function call\n");
2351       return;
2352     }
2353
2354   /* if the registers have been saved already or don't need to be then
2355      do nothing */
2356   if (ic->regsSaved
2357       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2358     return;
2359
2360   /* special case if DPTR alive across a function call then must save it
2361      even though callee saves */
2362   if (IS_SYMOP(IC_LEFT(ic)) &&
2363       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2364     {
2365       int i;
2366       rsave = newBitVect(ic->rMask->size);
2367       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2368           if (bitVectBitValue(ic->rMask,i))
2369               rsave = bitVectSetBit(rsave,i);
2370       }
2371       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2372     }
2373   else
2374     {
2375       /* save the registers in use at this time but skip the
2376          ones for the result */
2377       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2378                              ds390_rUmaskForOp (IC_RESULT(ic)));
2379     }
2380   ic->regsSaved = 1;
2381   savermask(rsave);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* usavermask - restore registers with mask                        */
2386 /*-----------------------------------------------------------------*/
2387 static void unsavermask(bitVect *rs_mask)
2388 {
2389   int i;
2390
2391   if (options.useXstack)
2392     {
2393       emitcode ("mov", "r0,%s", spname);
2394       for (i = ds390_nRegs; i >= 0; i--)
2395         {
2396           if (bitVectBitValue (rs_mask, i))
2397             {
2398               regs * reg = REG_WITH_INDEX (i);
2399               emitcode ("dec", "r0");
2400               emitcode ("movx", "a,@r0");
2401               if (i == R0_IDX)
2402                 {
2403                   emitcode ("push", "acc");
2404                 }
2405               else
2406                 {
2407                   emitcode ("mov", "%s,a", reg->name);
2408                 }
2409             }
2410         }
2411       emitcode ("mov", "%s,r0", spname);
2412       if (bitVectBitValue (rs_mask, R0_IDX))
2413         {
2414           emitcode ("pop", "ar0");
2415         }
2416     }
2417   else
2418     {
2419       bool bits_popped = FALSE;
2420       for (i = ds390_nRegs; i >= 0; i--)
2421         {
2422           if (bitVectBitValue (rs_mask, i))
2423             {
2424               bits_popped = popReg (i, bits_popped);
2425             }
2426         }
2427     }
2428 }
2429
2430 /*-----------------------------------------------------------------*/
2431 /* unsaveRegisters - pop the pushed registers                      */
2432 /*-----------------------------------------------------------------*/
2433 static void
2434 unsaveRegisters (iCode * ic)
2435 {
2436   bitVect *rsave;
2437
2438   if (IS_SYMOP(IC_LEFT (ic)) &&
2439       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2440       int i;
2441       rsave = newBitVect(ic->rMask->size);
2442       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2443           if (bitVectBitValue(ic->rMask,i))
2444               rsave = bitVectSetBit(rsave,i);
2445       }
2446       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2447   } else {
2448     /* restore the registers in use at this time but skip the
2449        ones for the result */
2450     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2451                            ds390_rUmaskForOp (IC_RESULT(ic)));
2452   }
2453   unsavermask(rsave);
2454 }
2455
2456
2457 /*-----------------------------------------------------------------*/
2458 /* pushSide -                */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 pushSide (operand * oper, int size)
2462 {
2463   int offset = 0;
2464   _startLazyDPSEvaluation ();
2465   while (size--)
2466     {
2467       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2468       if (AOP_TYPE (oper) != AOP_REG &&
2469           AOP_TYPE (oper) != AOP_DIR &&
2470           strcmp (l, "a"))
2471         {
2472           MOVA (l);
2473           emitcode ("push", "acc");
2474         }
2475       else
2476         {
2477           emitcode ("push", "%s", l);
2478         }
2479     }
2480   _endLazyDPSEvaluation ();
2481 }
2482
2483 /*-----------------------------------------------------------------*/
2484 /* assignResultValue - also indicates if acc is in use afterwards  */
2485 /*-----------------------------------------------------------------*/
2486 static bool
2487 assignResultValue (operand * oper, operand * func)
2488 {
2489   int offset = 0;
2490   unsigned size = AOP_SIZE (oper);
2491   bool accuse = FALSE;
2492   bool pushedA = FALSE;
2493
2494   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2495     {
2496       outBitC (oper);
2497       return FALSE;
2498     }
2499
2500   if (size == fReturnSizeDS390)
2501   {
2502       /* I don't think this case can ever happen... */
2503       /* ACC is the last part of this. If writing the result
2504        * uses ACC, we must preserve it.
2505        */
2506       if (AOP_NEEDSACC(oper))
2507       {
2508           emitcode(";", "assignResultValue special case for ACC.");
2509           emitcode("push", "acc");
2510           pushedA = TRUE;
2511           size--;
2512       }
2513   }
2514
2515   _startLazyDPSEvaluation ();
2516   while (size--)
2517     {
2518       accuse |= aopPut (oper, fReturn[offset], offset);
2519       offset++;
2520     }
2521   _endLazyDPSEvaluation ();
2522
2523   if (pushedA)
2524     {
2525         emitcode ("pop", "acc");
2526         accuse |= aopPut (oper, "a", offset);
2527     }
2528   return accuse;
2529 }
2530
2531
2532 /*-----------------------------------------------------------------*/
2533 /* genXpush - pushes onto the external stack                       */
2534 /*-----------------------------------------------------------------*/
2535 static void
2536 genXpush (iCode * ic)
2537 {
2538   asmop *aop = newAsmop (0);
2539   regs *r;
2540   int size, offset = 0;
2541
2542   D (emitcode (";", "genXpush"));
2543
2544   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2545   r = getFreePtr (ic, &aop, FALSE);
2546
2547   size = AOP_SIZE (IC_LEFT (ic));
2548
2549   if (size == 1)
2550     {
2551       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2552       emitcode ("mov", "%s,_spx", r->name);
2553       emitcode ("inc", "_spx"); // allocate space first
2554       emitcode ("movx", "@%s,a", r->name);
2555     }
2556   else
2557     {
2558       // allocate space first
2559       emitcode ("mov", "%s,_spx", r->name);
2560       MOVA (r->name);
2561       emitcode ("add", "a,#%d", size);
2562       emitcode ("mov", "_spx,a");
2563
2564       _startLazyDPSEvaluation ();
2565       while (size--)
2566         {
2567           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2568           emitcode ("movx", "@%s,a", r->name);
2569           emitcode ("inc", "%s", r->name);
2570         }
2571       _endLazyDPSEvaluation ();
2572     }
2573
2574   freeAsmop (NULL, aop, ic, TRUE);
2575   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2576 }
2577
2578 /*-----------------------------------------------------------------*/
2579 /* genIpush - generate code for pushing this gets a little complex  */
2580 /*-----------------------------------------------------------------*/
2581 static void
2582 genIpush (iCode * ic)
2583 {
2584   int size, offset = 0;
2585   char *l;
2586   char *prev = "";
2587
2588   D (emitcode (";", "genIpush"));
2589
2590   /* if this is not a parm push : ie. it is spill push
2591      and spill push is always done on the local stack */
2592   if (!ic->parmPush)
2593     {
2594
2595       /* and the item is spilt then do nothing */
2596       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2597         return;
2598
2599       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2600       size = AOP_SIZE (IC_LEFT (ic));
2601       /* push it on the stack */
2602       _startLazyDPSEvaluation ();
2603       while (size--)
2604         {
2605           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2606           if (*l == '#')
2607             {
2608               MOVA (l);
2609               l = "acc";
2610             }
2611           emitcode ("push", "%s", l);
2612         }
2613       _endLazyDPSEvaluation ();
2614       return;
2615     }
2616
2617   /* this is a parameter push: in this case we call
2618      the routine to find the call and save those
2619      registers that need to be saved */
2620   saveRegisters (ic);
2621
2622   /* if use external stack then call the external
2623      stack pushing routine */
2624   if (options.useXstack)
2625     {
2626       genXpush (ic);
2627       return;
2628     }
2629
2630   /* then do the push */
2631   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2632
2633   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2634   size = AOP_SIZE (IC_LEFT (ic));
2635
2636   _startLazyDPSEvaluation ();
2637   while (size--)
2638     {
2639       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2640       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2641           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2642           strcmp (l, "acc"))
2643         {
2644           if (strcmp (l, prev) || *l == '@')
2645             MOVA (l);
2646           emitcode ("push", "acc");
2647         }
2648       else
2649         {
2650             emitcode ("push", "%s", l);
2651         }
2652       prev = l;
2653     }
2654   _endLazyDPSEvaluation ();
2655
2656   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2657 }
2658
2659 /*-----------------------------------------------------------------*/
2660 /* genIpop - recover the registers: can happen only for spilling   */
2661 /*-----------------------------------------------------------------*/
2662 static void
2663 genIpop (iCode * ic)
2664 {
2665   int size, offset;
2666
2667   D (emitcode (";", "genIpop"));
2668
2669   /* if the temp was not pushed then */
2670   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2671     return;
2672
2673   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2674   size = AOP_SIZE (IC_LEFT (ic));
2675   offset = (size - 1);
2676   _startLazyDPSEvaluation ();
2677   while (size--)
2678     {
2679       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2680                                      FALSE, TRUE, NULL));
2681     }
2682   _endLazyDPSEvaluation ();
2683
2684   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2685 }
2686
2687 /*-----------------------------------------------------------------*/
2688 /* saveRBank - saves an entire register bank on the stack          */
2689 /*-----------------------------------------------------------------*/
2690 static void
2691 saveRBank (int bank, iCode * ic, bool pushPsw)
2692 {
2693   int i;
2694   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2695   asmop *aop = NULL;
2696   regs *r = NULL;
2697
2698   if (options.useXstack)
2699     {
2700       if (!ic)
2701         {
2702           /* Assume r0 is available for use. */
2703           r = REG_WITH_INDEX (R0_IDX);;
2704         }
2705       else
2706         {
2707           aop = newAsmop (0);
2708           r = getFreePtr (ic, &aop, FALSE);
2709         }
2710       // allocate space first
2711       emitcode ("mov", "%s,_spx", r->name);
2712       MOVA (r->name);
2713       emitcode ("add", "a,#%d", count);
2714       emitcode ("mov", "_spx,a");
2715     }
2716
2717   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2718     {
2719       if (options.useXstack)
2720         {
2721           emitcode ("mov", "a,(%s+%d)",
2722                     regs390[i].base, 8 * bank + regs390[i].offset);
2723           emitcode ("movx", "@%s,a", r->name);
2724           if (--count)
2725             emitcode ("inc", "%s", r->name);
2726         }
2727       else
2728         emitcode ("push", "(%s+%d)",
2729                   regs390[i].base, 8 * bank + regs390[i].offset);
2730     }
2731
2732   if (ds390_nBitRegs > 0)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("mov", "a,bits");
2737           emitcode ("movx", "@%s,a", r->name);
2738           if (--count)
2739             emitcode ("inc", "%s", r->name);
2740         }
2741       else
2742         {
2743           emitcode ("push", "bits");
2744         }
2745       BitBankUsed = 1;
2746     }
2747
2748   if (pushPsw)
2749     {
2750       if (options.useXstack)
2751         {
2752           emitcode ("mov", "a,psw");
2753           emitcode ("movx", "@%s,a", r->name);
2754         }
2755       else
2756       {
2757         emitcode ("push", "psw");
2758       }
2759
2760       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2761     }
2762
2763   if (aop)
2764     {
2765       freeAsmop (NULL, aop, ic, TRUE);
2766     }
2767
2768   if (ic)
2769   {
2770     ic->bankSaved = 1;
2771   }
2772 }
2773
2774 /*-----------------------------------------------------------------*/
2775 /* unsaveRBank - restores the register bank from stack             */
2776 /*-----------------------------------------------------------------*/
2777 static void
2778 unsaveRBank (int bank, iCode * ic, bool popPsw)
2779 {
2780   int i;
2781   asmop *aop = NULL;
2782   regs *r = NULL;
2783
2784   if (options.useXstack)
2785     {
2786       if (!ic)
2787         {
2788           /* Assume r0 is available for use. */
2789           r = REG_WITH_INDEX (R0_IDX);;
2790         }
2791       else
2792         {
2793           aop = newAsmop (0);
2794           r = getFreePtr (ic, &aop, FALSE);
2795         }
2796       emitcode ("mov", "%s,_spx", r->name);
2797     }
2798
2799   if (popPsw)
2800     {
2801       if (options.useXstack)
2802         {
2803           emitcode ("dec", "%s", r->name);
2804           emitcode ("movx", "a,@%s", r->name);
2805           emitcode ("mov", "psw,a");
2806         }
2807       else
2808       {
2809         emitcode ("pop", "psw");
2810       }
2811     }
2812
2813   if (ds390_nBitRegs > 0)
2814     {
2815       if (options.useXstack)
2816         {
2817           emitcode ("dec", "%s", r->name);
2818           emitcode ("movx", "a,@%s", r->name);
2819           emitcode ("mov", "bits,a");
2820         }
2821       else
2822         {
2823           emitcode ("pop", "bits");
2824         }
2825     }
2826
2827   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2828     {
2829       if (options.useXstack)
2830         {
2831           emitcode ("dec", "%s", r->name);
2832           emitcode ("movx", "a,@%s", r->name);
2833           emitcode ("mov", "(%s+%d),a",
2834                     regs390[i].base, 8 * bank + regs390[i].offset);
2835         }
2836       else
2837         {
2838           emitcode ("pop", "(%s+%d)",
2839                     regs390[i].base, 8 * bank + regs390[i].offset);
2840         }
2841     }
2842
2843   if (options.useXstack)
2844     {
2845       emitcode ("mov", "_spx,%s", r->name);
2846     }
2847
2848   if (aop)
2849     {
2850       freeAsmop (NULL, aop, ic, TRUE);
2851     }
2852 }
2853
2854 /*-----------------------------------------------------------------*/
2855 /* genSend - gen code for SEND                                     */
2856 /*-----------------------------------------------------------------*/
2857 static void genSend(set *sendSet)
2858 {
2859   iCode *sic;
2860   int bit_count = 0;
2861   int sendCount = 0 ;
2862   static int rb1_count = 0;
2863
2864   /* first we do all bit parameters */
2865   for (sic = setFirstItem (sendSet); sic;
2866        sic = setNextItem (sendSet))
2867     {
2868       if (sic->argreg > 12)
2869         {
2870           int bit = sic->argreg-13;
2871
2872           aopOp (IC_LEFT (sic), sic, FALSE,
2873                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2874
2875           /* if left is a literal then
2876              we know what the value is */
2877           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2878             {
2879               if (((int) operandLitValue (IC_LEFT (sic))))
2880                   emitcode ("setb", "b[%d]", bit);
2881               else
2882                   emitcode ("clr", "b[%d]", bit);
2883             }
2884           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2885             {
2886               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2887                 if (strcmp (l, "c"))
2888                     emitcode ("mov", "c,%s", l);
2889                 emitcode ("mov", "b[%d],c", bit);
2890             }
2891           else
2892             {
2893               /* we need to or */
2894               toBoolean (IC_LEFT (sic));
2895               /* set C, if a >= 1 */
2896               emitcode ("add", "a,#0xff");
2897               emitcode ("mov", "b[%d],c", bit);
2898             }
2899           bit_count++;
2900           BitBankUsed = 1;
2901
2902           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2903         }
2904     }
2905
2906   if (bit_count)
2907     {
2908       saveRegisters (setFirstItem (sendSet));
2909       emitcode ("mov", "bits,b");
2910     }
2911
2912   /* then we do all other parameters */
2913   for (sic = setFirstItem (sendSet); sic;
2914        sic = setNextItem (sendSet))
2915     {
2916       if (sic->argreg <= 12)
2917       {
2918         int size, offset = 0;
2919
2920         size = getSize (operandType (IC_LEFT (sic)));
2921         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2922         if (sendCount == 0) { /* first parameter */
2923             // we know that dpl(hxb) is the result, so
2924             rb1_count = 0 ;
2925             _startLazyDPSEvaluation ();
2926             if (size>1) {
2927                 aopOp (IC_LEFT (sic), sic, FALSE,
2928                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2929             } else {
2930                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2931             }
2932             while (size--)
2933               {
2934                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2935                 if (strcmp (l, fReturn[offset]))
2936                   {
2937                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2938                   }
2939                 offset++;
2940               }
2941             _endLazyDPSEvaluation ();
2942             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2943             rb1_count =0;
2944         } else { /* if more parameter in registers */
2945             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2946             while (size--) {
2947                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2948                                                                 FALSE, FALSE, NULL));
2949             }
2950             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2951         }
2952         sendCount++;
2953       }
2954     }
2955 }
2956
2957 static void
2958 adjustEsp(const char *reg)
2959 {
2960     emitcode ("anl","%s,#3", reg);
2961     if (TARGET_IS_DS400)
2962     {
2963         emitcode ("orl","%s,#!constbyte",
2964                   reg,
2965                   (options.stack_loc >> 8) & 0xff);
2966     }
2967 }
2968
2969 /*-----------------------------------------------------------------*/
2970 /* selectRegBank - emit code to select the register bank           */
2971 /*-----------------------------------------------------------------*/
2972 static void
2973 selectRegBank (short bank, bool keepFlags)
2974 {
2975   /* if f.e. result is in carry */
2976   if (keepFlags)
2977     {
2978       emitcode ("anl", "psw,#0xE7");
2979       if (bank)
2980         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2981     }
2982   else
2983     {
2984       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2985     }
2986 }
2987
2988 /*-----------------------------------------------------------------*/
2989 /* genCall - generates a call statement                            */
2990 /*-----------------------------------------------------------------*/
2991 static void
2992 genCall (iCode * ic)
2993 {
2994   sym_link *dtype;
2995   sym_link *etype;
2996   bool restoreBank = FALSE;
2997   bool swapBanks = FALSE;
2998   bool accuse = FALSE;
2999   bool accPushed = FALSE;
3000   bool resultInF0 = FALSE;
3001   bool assignResultGenerated = FALSE;
3002
3003   D (emitcode (";", "genCall"));
3004
3005   /* if we are calling a not _naked function that is not using
3006      the same register bank then we need to save the
3007      destination registers on the stack */
3008   dtype = operandType (IC_LEFT (ic));
3009   etype = getSpec(dtype);
3010   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3011       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3012       IFFUNC_ISISR (currFunc->type))
3013   {
3014       if (!ic->bankSaved)
3015       {
3016            /* This is unexpected; the bank should have been saved in
3017             * genFunction.
3018             */
3019            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3020            restoreBank = TRUE;
3021       }
3022       swapBanks = TRUE;
3023   }
3024
3025   /* if caller saves & we have not saved then */
3026   if (!ic->regsSaved)
3027       saveRegisters (ic);
3028
3029   /* if send set is not empty then assign */
3030   /* We've saved all the registers we care about;
3031   * therefore, we may clobber any register not used
3032   * in the calling convention (i.e. anything not in
3033   * fReturn.
3034   */
3035   if (_G.sendSet)
3036     {
3037         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3038             genSend(reverseSet(_G.sendSet));
3039         } else {
3040             genSend(_G.sendSet);
3041         }
3042       _G.sendSet = NULL;
3043     }
3044
3045   if (swapBanks)
3046     {
3047       emitcode ("mov", "psw,#!constbyte",
3048          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3049     }
3050
3051   /* make the call */
3052   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3053                             OP_SYMBOL (IC_LEFT (ic))->rname :
3054                             OP_SYMBOL (IC_LEFT (ic))->name));
3055
3056   if (swapBanks)
3057     {
3058       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3059     }
3060
3061   /* if we need assign a result value */
3062   if ((IS_ITEMP (IC_RESULT (ic)) &&
3063        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3064        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3065         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3066         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3067       IS_TRUE_SYMOP (IC_RESULT (ic)))
3068     {
3069       if (isOperandInFarSpace (IC_RESULT (ic))
3070           && getSize (operandType (IC_RESULT (ic))) <= 2)
3071         {
3072           int size = getSize (operandType (IC_RESULT (ic)));
3073           bool pushedB = FALSE;
3074
3075           /* Special case for 1 or 2 byte return in far space. */
3076           MOVA (fReturn[0]);
3077           if (size > 1)
3078             {
3079               pushedB = pushB ();
3080               emitcode ("mov", "b,%s", fReturn[1]);
3081             }
3082
3083           _G.accInUse++;
3084           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3085           _G.accInUse--;
3086
3087           popB (pushedB);
3088
3089           aopPut (IC_RESULT (ic), "a", 0);
3090
3091           if (size > 1)
3092             {
3093               aopPut (IC_RESULT (ic), "b", 1);
3094             }
3095           assignResultGenerated = TRUE;
3096           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3097         }
3098       else
3099         {
3100           bool pushedB = pushB ();
3101           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3102           popB (pushedB);
3103
3104           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3105           assignResultGenerated = TRUE;
3106           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3107         }
3108     }
3109
3110   /* adjust the stack for parameters if required */
3111   if (ic->parmBytes)
3112     {
3113       int i;
3114       if (options.stack10bit) {
3115           if (ic->parmBytes <= 10) {
3116               emitcode(";","stack adjustment for parms");
3117               for (i=0; i < ic->parmBytes ; i++) {
3118                   emitcode("pop","acc");
3119               }
3120           } else {
3121               PROTECT_SP;
3122               emitcode ("clr","c");
3123               emitcode ("mov","a,sp");
3124               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3125               emitcode ("mov","sp,a");
3126               emitcode ("mov","a,esp");
3127               adjustEsp("a");
3128               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3129               emitcode ("mov","esp,a");
3130               UNPROTECT_SP;
3131           }
3132       } else {
3133           if (ic->parmBytes > 3)
3134             {
3135               if (accuse)
3136                 {
3137                   emitcode ("push", "acc");
3138                   accPushed = TRUE;
3139                 }
3140               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3141                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3142                   !assignResultGenerated)
3143                 {
3144                   emitcode ("mov", "F0,c");
3145                   resultInF0 = TRUE;
3146                 }
3147
3148               emitcode ("mov", "a,%s", spname);
3149               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3150               emitcode ("mov", "%s,a", spname);
3151
3152               /* unsaveRegisters from xstack needs acc, but */
3153               /* unsaveRegisters from stack needs this popped */
3154               if (accPushed && !options.useXstack)
3155                 {
3156                   emitcode ("pop", "acc");
3157                   accPushed = FALSE;
3158                 }
3159             }
3160           else
3161               for (i = 0; i < ic->parmBytes; i++)
3162                   emitcode ("dec", "%s", spname);
3163       }
3164   }
3165
3166   /* if we had saved some registers then unsave them */
3167   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3168     {
3169       if (accuse && !accPushed && options.useXstack)
3170         {
3171           /* xstack needs acc, but doesn't touch normal stack */
3172           emitcode ("push", "acc");
3173           accPushed = TRUE;
3174         }
3175       unsaveRegisters (ic);
3176     }
3177
3178   /* if register bank was saved then pop them */
3179   if (restoreBank)
3180     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3181
3182   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3183     {
3184       if (resultInF0)
3185           emitcode ("mov", "c,F0");
3186
3187       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3188       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3189       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3190     }
3191
3192   if (accPushed)
3193     emitcode ("pop", "acc");
3194 }
3195
3196 /*-----------------------------------------------------------------*/
3197 /* genPcall - generates a call by pointer statement                */
3198 /*-----------------------------------------------------------------*/
3199 static void
3200 genPcall (iCode * ic)
3201 {
3202   sym_link *dtype;
3203   sym_link *etype;
3204   symbol *rlbl = newiTempLabel (NULL);
3205   bool restoreBank=FALSE;
3206   bool resultInF0 = FALSE;
3207
3208   D (emitcode (";", "genPcall"));
3209
3210   dtype = operandType (IC_LEFT (ic))->next;
3211   etype = getSpec(dtype);
3212   /* if caller saves & we have not saved then */
3213   if (!ic->regsSaved)
3214     saveRegisters (ic);
3215
3216   /* if we are calling a not _naked function that is not using
3217      the same register bank then we need to save the
3218      destination registers on the stack */
3219   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3220       IFFUNC_ISISR (currFunc->type) &&
3221       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3222     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3223     restoreBank=TRUE;
3224   }
3225
3226   /* push the return address on to the stack */
3227   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3228   emitcode ("push", "acc");
3229   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3230   emitcode ("push", "acc");
3231
3232   if (options.model == MODEL_FLAT24)
3233     {
3234       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3235       emitcode ("push", "acc");
3236     }
3237
3238   /* now push the calling address */
3239   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3240
3241   pushSide (IC_LEFT (ic), FPTRSIZE);
3242
3243   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3244
3245   /* if send set is not empty the assign */
3246   if (_G.sendSet)
3247     {
3248         genSend(reverseSet(_G.sendSet));
3249         _G.sendSet = NULL;
3250     }
3251
3252   /* make the call */
3253   emitcode ("ret", "");
3254   emitLabel (rlbl);
3255
3256
3257   /* if we need assign a result value */
3258   if ((IS_ITEMP (IC_RESULT (ic)) &&
3259        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3260        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3261         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3262       IS_TRUE_SYMOP (IC_RESULT (ic)))
3263     {
3264
3265       _G.accInUse++;
3266       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3267       _G.accInUse--;
3268
3269       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3270
3271       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3272     }
3273
3274   /* adjust the stack for parameters if required */
3275   if (ic->parmBytes)
3276     {
3277       int i;
3278       if (options.stack10bit) {
3279           if (ic->parmBytes <= 10) {
3280               emitcode(";","stack adjustment for parms");
3281               for (i=0; i < ic->parmBytes ; i++) {
3282                   emitcode("pop","acc");
3283               }
3284           } else {
3285               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3286                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3287                 {
3288                   emitcode ("mov", "F0,c");
3289                   resultInF0 = TRUE;
3290                 }
3291
3292               PROTECT_SP;
3293               emitcode ("clr","c");
3294               emitcode ("mov","a,sp");
3295               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3296               emitcode ("mov","sp,a");
3297               emitcode ("mov","a,esp");
3298               adjustEsp("a");
3299               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3300               emitcode ("mov","esp,a");
3301               UNPROTECT_SP;
3302           }
3303       } else {
3304           if (ic->parmBytes > 3) {
3305               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3306                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3307                 {
3308                   emitcode ("mov", "F0,c");
3309                   resultInF0 = TRUE;
3310                 }
3311
3312               emitcode ("mov", "a,%s", spname);
3313               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3314               emitcode ("mov", "%s,a", spname);
3315           }
3316           else
3317               for (i = 0; i < ic->parmBytes; i++)
3318                   emitcode ("dec", "%s", spname);
3319       }
3320     }
3321   /* if register bank was saved then unsave them */
3322   if (restoreBank)
3323     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3324
3325   /* if we had saved some registers then unsave them */
3326   if (ic->regsSaved)
3327     unsaveRegisters (ic);
3328
3329   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3330     {
3331       if (resultInF0)
3332           emitcode ("mov", "c,F0");
3333
3334       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3335       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3336       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3337     }
3338 }
3339
3340 /*-----------------------------------------------------------------*/
3341 /* resultRemat - result  is rematerializable                       */
3342 /*-----------------------------------------------------------------*/
3343 static int
3344 resultRemat (iCode * ic)
3345 {
3346   if (SKIP_IC (ic) || ic->op == IFX)
3347     return 0;
3348
3349   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3350     {
3351       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3352       if (sym->remat && !POINTER_SET (ic))
3353         return 1;
3354     }
3355
3356   return 0;
3357 }
3358
3359 /*-----------------------------------------------------------------*/
3360 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3361 /*-----------------------------------------------------------------*/
3362 static int
3363 regsCmp(void *p1, void *p2)
3364 {
3365   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3366 }
3367
3368 static bool
3369 inExcludeList (char *s)
3370 {
3371   const char *p = setFirstItem(options.excludeRegsSet);
3372
3373   if (p == NULL || STRCASECMP(p, "none") == 0)
3374     return FALSE;
3375
3376
3377   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3378 }
3379
3380 /*-----------------------------------------------------------------*/
3381 /* genFunction - generated code for function entry                 */
3382 /*-----------------------------------------------------------------*/
3383 static void
3384 genFunction (iCode * ic)
3385 {
3386   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3387   sym_link *ftype;
3388   bool     switchedPSW = FALSE;
3389   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3390
3391   D (emitcode (";", "genFunction"));
3392
3393   _G.nRegsSaved = 0;
3394   /* create the function header */
3395   emitcode (";", "-----------------------------------------");
3396   emitcode (";", " function %s", sym->name);
3397   emitcode (";", "-----------------------------------------");
3398
3399   emitcode ("", "%s:", sym->rname);
3400   lineCurr->isLabel = 1;
3401   ftype = operandType (IC_LEFT (ic));
3402   _G.currentFunc = sym;
3403
3404   if (IFFUNC_ISNAKED(ftype))
3405   {
3406       emitcode(";", "naked function: no prologue.");
3407       return;
3408   }
3409
3410   if (options.stack_probe)
3411       emitcode ("lcall","__stack_probe");
3412
3413   /* here we need to generate the equates for the
3414      register bank if required */
3415   if (FUNC_REGBANK (ftype) != rbank)
3416     {
3417       int i;
3418
3419       rbank = FUNC_REGBANK (ftype);
3420       for (i = 0; i < ds390_nRegs; i++)
3421         {
3422           if (regs390[i].print) {
3423               if (strcmp (regs390[i].base, "0") == 0)
3424                   emitcode ("", "%s !equ !constbyte",
3425                             regs390[i].dname,
3426                             8 * rbank + regs390[i].offset);
3427               else
3428                   emitcode ("", "%s !equ %s + !constbyte",
3429                             regs390[i].dname,
3430                             regs390[i].base,
3431                             8 * rbank + regs390[i].offset);
3432           }
3433         }
3434     }
3435
3436   /* if this is an interrupt service routine then
3437      save acc, b, dpl, dph  */
3438   if (IFFUNC_ISISR (sym->type))
3439       { /* is ISR */
3440       if (!inExcludeList ("acc"))
3441         emitcode ("push", "acc");
3442       if (!inExcludeList ("b"))
3443         emitcode ("push", "b");
3444       if (!inExcludeList ("dpl"))
3445         emitcode ("push", "dpl");
3446       if (!inExcludeList ("dph"))
3447         emitcode ("push", "dph");
3448       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3449         {
3450           emitcode ("push", "dpx");
3451           /* Make sure we're using standard DPTR */
3452           emitcode ("push", "dps");
3453           emitcode ("mov", "dps,#0");
3454           if (options.stack10bit)
3455             {
3456               /* This ISR could conceivably use DPTR2. Better save it. */
3457               emitcode ("push", "dpl1");
3458               emitcode ("push", "dph1");
3459               emitcode ("push", "dpx1");
3460               emitcode ("push",  DP2_RESULT_REG);
3461             }
3462         }
3463       /* if this isr has no bank i.e. is going to
3464          run with bank 0 , then we need to save more
3465          registers :-) */
3466       if (!FUNC_REGBANK (sym->type))
3467         {
3468             int i;
3469
3470           /* if this function does not call any other
3471              function then we can be economical and
3472              save only those registers that are used */
3473           if (!IFFUNC_HASFCALL(sym->type))
3474             {
3475               /* if any registers used */
3476               if (sym->regsUsed)
3477                 {
3478                   bool bits_pushed = FALSE;
3479                   /* save the registers used */
3480                   for (i = 0; i < sym->regsUsed->size; i++)
3481                     {
3482                       if (bitVectBitValue (sym->regsUsed, i))
3483                         bits_pushed = pushReg (i, bits_pushed);
3484                     }
3485                 }
3486             }
3487           else
3488             {
3489               /* this function has a function call. We cannot
3490                  determine register usage so we will have to push the
3491                  entire bank */
3492               saveRBank (0, ic, FALSE);
3493               if (options.parms_in_bank1) {
3494                   for (i=0; i < 8 ; i++ ) {
3495                       emitcode ("push","%s",rb1regs[i]);
3496                   }
3497               }
3498             }
3499         }
3500         else
3501         {
3502             /* This ISR uses a non-zero bank.
3503              *
3504              * We assume that the bank is available for our
3505              * exclusive use.
3506              *
3507              * However, if this ISR calls a function which uses some
3508              * other bank, we must save that bank entirely.
3509              */
3510             unsigned long banksToSave = 0;
3511
3512             if (IFFUNC_HASFCALL(sym->type))
3513             {
3514
3515 #define MAX_REGISTER_BANKS 4
3516
3517                 iCode *i;
3518                 int ix;
3519
3520                 for (i = ic; i; i = i->next)
3521                 {
3522                     if (i->op == ENDFUNCTION)
3523                     {
3524                         /* we got to the end OK. */
3525                         break;
3526                     }
3527
3528                     if (i->op == CALL)
3529                     {
3530                         sym_link *dtype;
3531
3532                         dtype = operandType (IC_LEFT(i));
3533                         if (dtype
3534                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3535                         {
3536                              /* Mark this bank for saving. */
3537                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3538                              {
3539                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3540                              }
3541                              else
3542                              {
3543                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3544                              }
3545
3546                              /* And note that we don't need to do it in
3547                               * genCall.
3548                               */
3549                              i->bankSaved = 1;
3550                         }
3551                     }
3552                     if (i->op == PCALL)
3553                     {
3554                         /* This is a mess; we have no idea what
3555                          * register bank the called function might
3556                          * use.
3557                          *
3558                          * The only thing I can think of to do is
3559                          * throw a warning and hope.
3560                          */
3561                         werror(W_FUNCPTR_IN_USING_ISR);
3562                     }
3563                 }
3564
3565                 if (banksToSave && options.useXstack)
3566                 {
3567                     /* Since we aren't passing it an ic,
3568                      * saveRBank will assume r0 is available to abuse.
3569                      *
3570                      * So switch to our (trashable) bank now, so
3571                      * the caller's R0 isn't trashed.
3572                      */
3573                     emitcode ("push", "psw");
3574                     emitcode ("mov", "psw,#!constbyte",
3575                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3576                     switchedPSW = TRUE;
3577                 }
3578
3579                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3580                 {
3581                      if (banksToSave & (1 << ix))
3582                      {
3583                          saveRBank(ix, NULL, FALSE);
3584                      }
3585                 }
3586             }
3587             // TODO: this needs a closer look
3588             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3589         }
3590     }
3591   else
3592     {
3593       /* if callee-save to be used for this function
3594          then save the registers being used in this function */
3595       if (IFFUNC_CALLEESAVES(sym->type))
3596         {
3597           int i;
3598
3599           /* if any registers used */
3600           if (sym->regsUsed)
3601             {
3602               bool bits_pushed = FALSE;
3603               /* save the registers used */
3604               for (i = 0; i < sym->regsUsed->size; i++)
3605                 {
3606                   if (bitVectBitValue (sym->regsUsed, i))
3607                     {
3608                       bits_pushed = pushReg (i, bits_pushed);
3609                       _G.nRegsSaved++;
3610                     }
3611                 }
3612             }
3613         }
3614     }
3615
3616   /* set the register bank to the desired value */
3617   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3618    && !switchedPSW)
3619     {
3620       emitcode ("push", "psw");
3621       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3622     }
3623
3624   if (fReentrant &&
3625        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3626       if (options.stack10bit) {
3627           emitcode ("push","_bpx");
3628           emitcode ("push","_bpx+1");
3629           emitcode ("mov","_bpx,%s",spname);
3630           emitcode ("mov","_bpx+1,esp");
3631           adjustEsp("_bpx+1");
3632       } else {
3633           if (options.useXstack)
3634           {
3635               emitcode ("mov", "r0,%s", spname);
3636               emitcode ("mov", "a,_bp");
3637               emitcode ("movx", "@r0,a");
3638               emitcode ("inc", "%s", spname);
3639           } else {
3640               /* set up the stack */
3641               emitcode ("push", "_bp"); /* save the callers stack  */
3642           }
3643           emitcode ("mov", "_bp,%s", spname);
3644       }
3645   }
3646
3647   /* adjust the stack for the function */
3648   if (sym->stack) {
3649       int i = sym->stack;
3650       if (options.stack10bit) {
3651           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3652           assert (sym->recvSize <= 4);
3653           if (sym->stack <= 8) {
3654               while (i--) emitcode ("push","acc");
3655           } else {
3656               PROTECT_SP;
3657               emitcode ("mov","a,sp");
3658               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3659               emitcode ("mov","sp,a");
3660               emitcode ("mov","a,esp");
3661               adjustEsp("a");
3662               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3663               emitcode ("mov","esp,a");
3664               UNPROTECT_SP;
3665           }
3666       } else {
3667           if (i > 256)
3668               werror (W_STACK_OVERFLOW, sym->name);
3669
3670           if (i > 3 && sym->recvSize < 4) {
3671
3672               emitcode ("mov", "a,sp");
3673               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3674               emitcode ("mov", "sp,a");
3675
3676           } else
3677               while (i--)
3678                   emitcode ("inc", "sp");
3679       }
3680   }
3681
3682   if (sym->xstack)
3683     {
3684
3685       emitcode ("mov", "a,_spx");
3686       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3687       emitcode ("mov", "_spx,a");
3688     }
3689
3690   /* if critical function then turn interrupts off */
3691   if (IFFUNC_ISCRITICAL (ftype))
3692     {
3693       symbol *tlbl = newiTempLabel (NULL);
3694       emitcode ("setb", "c");
3695       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3696       emitcode ("clr", "c");
3697       emitLabel (tlbl);
3698       emitcode ("push", "psw"); /* save old ea via c in psw */
3699     }
3700 }
3701
3702 /*-----------------------------------------------------------------*/
3703 /* genEndFunction - generates epilogue for functions               */
3704 /*-----------------------------------------------------------------*/
3705 static void
3706 genEndFunction (iCode * ic)
3707 {
3708   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3709   lineNode *lnp = lineCurr;
3710   bitVect *regsUsed;
3711   bitVect *regsUsedPrologue;
3712   bitVect *regsUnneeded;
3713   int idx;
3714
3715   D (emitcode (";", "genEndFunction"));
3716
3717   _G.currentFunc = NULL;
3718   if (IFFUNC_ISNAKED(sym->type))
3719   {
3720       emitcode(";", "naked function: no epilogue.");
3721       if (options.debug && currFunc)
3722         debugFile->writeEndFunction (currFunc, ic, 0);
3723       return;
3724   }
3725
3726   if (IFFUNC_ISCRITICAL (sym->type))
3727     {
3728       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3729         {
3730           emitcode ("rlc", "a");   /* save c in a */
3731           emitcode ("pop", "psw"); /* restore ea via c in psw */
3732           emitcode ("mov", "ea,c");
3733           emitcode ("rrc", "a");   /* restore c from a */
3734         }
3735       else
3736         {
3737           emitcode ("pop", "psw"); /* restore ea via c in psw */
3738           emitcode ("mov", "ea,c");
3739         }
3740     }
3741
3742   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3743        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3744
3745       if (options.stack10bit) {
3746           PROTECT_SP;
3747           emitcode ("mov", "sp,_bpx", spname);
3748           emitcode ("mov", "esp,_bpx+1", spname);
3749           UNPROTECT_SP;
3750       } else {
3751           emitcode ("mov", "%s,_bp", spname);
3752       }
3753   }
3754
3755   /* if use external stack but some variables were
3756      added to the local stack then decrement the
3757      local stack */
3758   if (options.useXstack && sym->stack) {
3759       emitcode ("mov", "a,sp");
3760       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3761       emitcode ("mov", "sp,a");
3762   }
3763
3764
3765   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3766        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3767
3768       if (options.useXstack) {
3769           emitcode ("mov", "r0,%s", spname);
3770           emitcode ("movx", "a,@r0");
3771           emitcode ("mov", "_bp,a");
3772           emitcode ("dec", "%s", spname);
3773       } else {
3774           if (options.stack10bit) {
3775               emitcode ("pop", "_bpx+1");
3776               emitcode ("pop", "_bpx");
3777           } else {
3778               emitcode ("pop", "_bp");
3779           }
3780       }
3781   }
3782
3783   /* restore the register bank  */
3784   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3785   {
3786     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3787      || !options.useXstack)
3788     {
3789         /* Special case of ISR using non-zero bank with useXstack
3790          * is handled below.
3791          */
3792         emitcode ("pop", "psw");
3793     }
3794   }
3795
3796   if (IFFUNC_ISISR (sym->type))
3797     { /* is ISR */
3798
3799       /* now we need to restore the registers */
3800       /* if this isr has no bank i.e. is going to
3801          run with bank 0 , then we need to save more
3802          registers :-) */
3803       if (!FUNC_REGBANK (sym->type))
3804         {
3805           int i;
3806           /* if this function does not call any other
3807              function then we can be economical and
3808              save only those registers that are used */
3809           if (!IFFUNC_HASFCALL(sym->type))
3810             {
3811               /* if any registers used */
3812               if (sym->regsUsed)
3813                 {
3814                   bool bits_popped = FALSE;
3815                   /* save the registers used */
3816                   for (i = sym->regsUsed->size; i >= 0; i--)
3817                     {
3818                       if (bitVectBitValue (sym->regsUsed, i))
3819                         bits_popped = popReg (i, bits_popped);
3820                     }
3821                 }
3822             }
3823           else
3824             {
3825               /* this function has a function call. We cannot
3826                  determine register usage so we will have to pop the
3827                  entire bank */
3828               if (options.parms_in_bank1) {
3829                   for (i = 7 ; i >= 0 ; i-- ) {
3830                       emitcode ("pop","%s",rb1regs[i]);
3831                   }
3832               }
3833               unsaveRBank (0, ic, FALSE);
3834             }
3835         }
3836       else
3837         {
3838             /* This ISR uses a non-zero bank.
3839              *
3840              * Restore any register banks saved by genFunction
3841              * in reverse order.
3842              */
3843             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3844             int ix;
3845
3846             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3847             {
3848                 if (savedBanks & (1 << ix))
3849                 {
3850                     unsaveRBank(ix, NULL, FALSE);
3851                 }
3852             }
3853
3854             if (options.useXstack)
3855             {
3856                 /* Restore bank AFTER calling unsaveRBank,
3857                  * since it can trash r0.
3858                  */
3859                 emitcode ("pop", "psw");
3860             }
3861         }
3862
3863       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3864         {
3865           if (options.stack10bit)
3866             {
3867               emitcode ("pop", DP2_RESULT_REG);
3868               emitcode ("pop", "dpx1");
3869               emitcode ("pop", "dph1");
3870               emitcode ("pop", "dpl1");
3871             }
3872           emitcode ("pop", "dps");
3873           emitcode ("pop", "dpx");
3874         }
3875       if (!inExcludeList ("dph"))
3876         emitcode ("pop", "dph");
3877       if (!inExcludeList ("dpl"))
3878         emitcode ("pop", "dpl");
3879       if (!inExcludeList ("b"))
3880         emitcode ("pop", "b");
3881       if (!inExcludeList ("acc"))
3882         emitcode ("pop", "acc");
3883
3884       /* if debug then send end of function */
3885       if (options.debug && currFunc)
3886         {
3887           debugFile->writeEndFunction (currFunc, ic, 1);
3888         }
3889
3890       emitcode ("reti", "");
3891     }
3892   else
3893     {
3894       if (IFFUNC_CALLEESAVES(sym->type))
3895         {
3896           int i;
3897
3898           /* if any registers used */
3899           if (sym->regsUsed)
3900             {
3901               /* save the registers used */
3902               for (i = sym->regsUsed->size; i >= 0; i--)
3903                 {
3904                   if (bitVectBitValue (sym->regsUsed, i))
3905                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3906                 }
3907             }
3908         }
3909
3910       /* if debug then send end of function */
3911       if (options.debug && currFunc)
3912         {
3913           debugFile->writeEndFunction (currFunc, ic, 1);
3914         }
3915
3916       emitcode ("ret", "");
3917     }
3918
3919   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3920     return;
3921
3922   /* If this was an interrupt handler using bank 0 that called another */
3923   /* function, then all registers must be saved; nothing to optimized. */
3924   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3925       && !FUNC_REGBANK(sym->type))
3926     return;
3927
3928   /* There are no push/pops to optimize if not callee-saves or ISR */
3929   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3930     return;
3931
3932   /* If there were stack parameters, we cannot optimize without also    */
3933   /* fixing all of the stack offsets; this is too dificult to consider. */
3934   if (FUNC_HASSTACKPARM(sym->type))
3935     return;
3936
3937   /* Compute the registers actually used */
3938   regsUsed = newBitVect (ds390_nRegs);
3939   regsUsedPrologue = newBitVect (ds390_nRegs);
3940   while (lnp)
3941     {
3942       if (lnp->ic && lnp->ic->op == FUNCTION)
3943         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3944       else
3945         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3946
3947       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3948           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3949         break;
3950       if (!lnp->prev)
3951         break;
3952       lnp = lnp->prev;
3953     }
3954
3955   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3956       && !bitVectBitValue (regsUsed, DPS_IDX))
3957     {
3958       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3959     }
3960
3961   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3962       && !bitVectBitValue (regsUsed, CND_IDX))
3963     {
3964       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3965       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3966           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3967         bitVectUnSetBit (regsUsed, CND_IDX);
3968     }
3969   else
3970     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3971
3972   /* If this was an interrupt handler that called another function */
3973   /* function, then assume working registers may be modified by it. */
3974   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3975     {
3976       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3986       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3987     }
3988
3989   /* Remove the unneeded push/pops */
3990   regsUnneeded = newBitVect (ds390_nRegs);
3991   while (lnp)
3992     {
3993       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3994         {
3995           if (!strncmp(lnp->line, "push", 4))
3996             {
3997               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3998               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3999                 {
4000                   connectLine (lnp->prev, lnp->next);
4001                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4002                 }
4003             }
4004           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4005             {
4006               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4007               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4008                 {
4009                   connectLine (lnp->prev, lnp->next);
4010                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4011                 }
4012             }
4013         }
4014       lnp = lnp->next;
4015     }
4016
4017   for (idx = 0; idx < regsUnneeded->size; idx++)
4018     if (bitVectBitValue (regsUnneeded, idx))
4019       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4020
4021   freeBitVect (regsUnneeded);
4022   freeBitVect (regsUsed);
4023   freeBitVect (regsUsedPrologue);
4024 }
4025
4026 /*-----------------------------------------------------------------*/
4027 /* genJavaNativeRet - generate code for return JavaNative          */
4028 /*-----------------------------------------------------------------*/
4029 static void genJavaNativeRet(iCode *ic)
4030 {
4031     int i, size;
4032
4033     aopOp (IC_LEFT (ic), ic, FALSE,
4034            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4035     size = AOP_SIZE (IC_LEFT (ic));
4036
4037     assert (size <= 4);
4038
4039     /* it is assigned to GPR0-R3 then push them */
4040     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4041         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4042         for (i = 0 ; i < size ; i++ ) {
4043             emitcode ("push","%s",
4044                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4045         }
4046         for (i = (size-1) ; i >= 0 ; i--) {
4047             emitcode ("pop","a%s",javaRet[i]);
4048         }
4049     } else {
4050         for (i = 0 ; i < size ; i++)
4051             emitcode ("mov","%s,%s",javaRet[i],
4052                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4053     }
4054     for (i = size ; i < 4 ; i++ )
4055             emitcode ("mov","%s,#0",javaRet[i]);
4056     return;
4057 }
4058
4059 /*-----------------------------------------------------------------*/
4060 /* genRet - generate code for return statement                     */
4061 /*-----------------------------------------------------------------*/
4062 static void
4063 genRet (iCode * ic)
4064 {
4065   int size, offset = 0, pushed = 0;
4066
4067   D (emitcode (";", "genRet"));
4068
4069   /* if we have no return value then
4070      just generate the "ret" */
4071   if (!IC_LEFT (ic))
4072     goto jumpret;
4073
4074   /* if this is a JavaNative function then return
4075      value in different register */
4076   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4077       genJavaNativeRet(ic);
4078       goto jumpret;
4079   }
4080   /* we have something to return then
4081      move the return value into place */
4082   aopOp (IC_LEFT (ic), ic, FALSE,
4083          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4084   size = AOP_SIZE (IC_LEFT (ic));
4085
4086   _startLazyDPSEvaluation ();
4087
4088   if (IS_BIT(_G.currentFunc->etype))
4089     {
4090       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4091       size = 0;
4092     }
4093
4094   while (size--)
4095     {
4096       char *l;
4097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4098         {
4099           l = aopGet (IC_LEFT (ic), offset++,
4100                       FALSE, TRUE, NULL);
4101           emitcode ("push", "%s", l);
4102           pushed++;
4103         }
4104       else
4105         {
4106           /* Since A is the last element of fReturn,
4107            * it is OK to clobber it in the aopGet.
4108            */
4109           l = aopGet (IC_LEFT (ic), offset,
4110                       FALSE, FALSE, NULL);
4111           if (strcmp (fReturn[offset], l))
4112             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4113         }
4114     }
4115   _endLazyDPSEvaluation ();
4116
4117   while (pushed)
4118     {
4119       pushed--;
4120       if (strcmp (fReturn[pushed], "a"))
4121         emitcode ("pop", fReturn[pushed]);
4122       else
4123         emitcode ("pop", "acc");
4124     }
4125   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4126
4127 jumpret:
4128   /* generate a jump to the return label
4129      if the next is not the return statement */
4130   if (!(ic->next && ic->next->op == LABEL &&
4131         IC_LABEL (ic->next) == returnLabel))
4132
4133     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4134
4135 }
4136
4137 /*-----------------------------------------------------------------*/
4138 /* genLabel - generates a label                                    */
4139 /*-----------------------------------------------------------------*/
4140 static void
4141 genLabel (iCode * ic)
4142 {
4143   /* special case never generate */
4144   if (IC_LABEL (ic) == entryLabel)
4145     return;
4146
4147   D (emitcode (";", "genLabel"));
4148
4149   emitLabel (IC_LABEL (ic));
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genGoto - generates a ljmp                                      */
4154 /*-----------------------------------------------------------------*/
4155 static void
4156 genGoto (iCode * ic)
4157 {
4158   D (emitcode (";", "genGoto"));
4159
4160   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4161 }
4162
4163 /*-----------------------------------------------------------------*/
4164 /* findLabelBackwards: walks back through the iCode chain looking  */
4165 /* for the given label. Returns number of iCode instructions     */
4166 /* between that label and given ic.          */
4167 /* Returns zero if label not found.          */
4168 /*-----------------------------------------------------------------*/
4169 static int
4170 findLabelBackwards (iCode * ic, int key)
4171 {
4172   int count = 0;
4173
4174   while (ic->prev)
4175     {
4176       ic = ic->prev;
4177       count++;
4178
4179       /* If we have any pushes or pops, we cannot predict the distance.
4180          I don't like this at all, this should be dealt with in the
4181          back-end */
4182       if (ic->op == IPUSH || ic->op == IPOP) {
4183         return 0;
4184       }
4185
4186       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4187         {
4188           /* printf("findLabelBackwards = %d\n", count); */
4189           return count;
4190         }
4191     }
4192
4193   return 0;
4194 }
4195
4196 /*-----------------------------------------------------------------*/
4197 /* genPlusIncr :- does addition with increment if possible         */
4198 /*-----------------------------------------------------------------*/
4199 static bool
4200 genPlusIncr (iCode * ic)
4201 {
4202   unsigned int icount;
4203   unsigned int size = getDataSize (IC_RESULT (ic));
4204
4205   /* will try to generate an increment */
4206   /* if the right side is not a literal
4207      we cannot */
4208   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4209     return FALSE;
4210
4211   /* if the literal value of the right hand side
4212      is greater than 4 then it is not worth it */
4213   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4214     return FALSE;
4215
4216   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4217       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4218       while (icount--) {
4219           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4220       }
4221       return TRUE;
4222   }
4223   /* if increment 16 bits in register */
4224   if (
4225        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4226        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4227        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4228        (size > 1) &&
4229        (icount == 1))
4230     {
4231       symbol  *tlbl;
4232       int     emitTlbl;
4233       int     labelRange;
4234       char    *l;
4235
4236       /* If the next instruction is a goto and the goto target
4237        * is <= 5 instructions previous to this, we can generate
4238        * jumps straight to that target.
4239        */
4240       if (ic->next && ic->next->op == GOTO
4241           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4242           && labelRange <= 5)
4243         {
4244           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4245           tlbl = IC_LABEL (ic->next);
4246           emitTlbl = 0;
4247         }
4248       else
4249         {
4250           tlbl = newiTempLabel (NULL);
4251           emitTlbl = 1;
4252         }
4253       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4254       emitcode ("inc", "%s", l);
4255
4256       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4257           IS_AOP_PREG (IC_RESULT (ic)))
4258         {
4259           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4260         }
4261       else
4262         {
4263           emitcode ("clr", "a");
4264           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4265         }
4266
4267       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4268       emitcode ("inc", "%s", l);
4269       if (size > 2)
4270         {
4271           if (!strcmp(l, "acc"))
4272             {
4273                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4274             }
4275           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4276                    IS_AOP_PREG (IC_RESULT (ic)))
4277             {
4278                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4279             }
4280           else
4281             {
4282                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4283             }
4284
4285           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4286           emitcode ("inc", "%s", l);
4287         }
4288       if (size > 3)
4289         {
4290           if (!strcmp(l, "acc"))
4291             {
4292                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4293             }
4294           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4295                    IS_AOP_PREG (IC_RESULT (ic)))
4296             {
4297                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4298             }
4299           else
4300             {
4301                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4302             }
4303
4304           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4305           emitcode ("inc", "%s", l);
4306         }
4307
4308       if (emitTlbl)
4309         {
4310           emitLabel (tlbl);
4311         }
4312       return TRUE;
4313     }
4314
4315   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4316       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4317       options.model == MODEL_FLAT24 )
4318     {
4319       if (IC_RESULT(ic)->isGptr)
4320         {
4321           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4322         }
4323       switch (size) {
4324       case 3:
4325           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4326       case 2:
4327           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4328       case 1:
4329           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4330           break;
4331       }
4332       while (icount--)
4333         emitcode ("inc", "dptr");
4334       return TRUE;
4335   }
4336
4337   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4338       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4339       icount <= 5 ) {
4340       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4341       while (icount--)
4342         emitcode ("inc", "dptr");
4343       emitcode ("mov", "dps,#0");
4344       return TRUE;
4345   }
4346
4347   /* if the sizes are greater than 1 then we cannot */
4348   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4349       AOP_SIZE (IC_LEFT (ic)) > 1)
4350     return FALSE;
4351
4352   /* we can if the aops of the left & result match or
4353      if they are in registers and the registers are the
4354      same */
4355   if (
4356        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4357        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4358        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4359     {
4360       if (icount > 3)
4361         {
4362           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4363           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4364           aopPut (IC_RESULT (ic), "a", 0);
4365         }
4366       else
4367         {
4368           _startLazyDPSEvaluation ();
4369           while (icount--)
4370             {
4371               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4372             }
4373           _endLazyDPSEvaluation ();
4374         }
4375
4376       return TRUE;
4377     }
4378
4379   return FALSE;
4380 }
4381
4382 /*-----------------------------------------------------------------*/
4383 /* outBitAcc - output a bit in acc                                 */
4384 /*-----------------------------------------------------------------*/
4385 static void
4386 outBitAcc (operand * result)
4387 {
4388   symbol *tlbl = newiTempLabel (NULL);
4389   /* if the result is a bit */
4390   if (AOP_TYPE (result) == AOP_CRY)
4391     {
4392       aopPut (result, "a", 0);
4393     }
4394   else
4395     {
4396       emitcode ("jz", "!tlabel", tlbl->key + 100);
4397       emitcode ("mov", "a,%s", one);
4398       emitLabel (tlbl);
4399       outAcc (result);
4400     }
4401 }
4402
4403 /*-----------------------------------------------------------------*/
4404 /* genPlusBits - generates code for addition of two bits           */
4405 /*-----------------------------------------------------------------*/
4406 static void
4407 genPlusBits (iCode * ic)
4408 {
4409   D (emitcode (";", "genPlusBits"));
4410
4411   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4412     {
4413       symbol *lbl = newiTempLabel (NULL);
4414       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4415       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4416       emitcode ("cpl", "c");
4417       emitLabel (lbl);
4418       outBitC (IC_RESULT (ic));
4419     }
4420   else
4421     {
4422       emitcode ("clr", "a");
4423       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4424       emitcode ("rlc", "a");
4425       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4426       emitcode ("addc", "a,%s", zero);
4427       outAcc (IC_RESULT (ic));
4428     }
4429 }
4430
4431 static void
4432 adjustArithmeticResult (iCode * ic)
4433 {
4434   if (opIsGptr (IC_RESULT (ic)) &&
4435       opIsGptr (IC_LEFT (ic)) &&
4436       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4437     {
4438       aopPut (IC_RESULT (ic),
4439               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4440               GPTRSIZE - 1);
4441     }
4442
4443   if (opIsGptr (IC_RESULT (ic)) &&
4444       opIsGptr (IC_RIGHT (ic)) &&
4445       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4446     {
4447       aopPut (IC_RESULT (ic),
4448               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4449               GPTRSIZE - 1);
4450     }
4451
4452   if (opIsGptr (IC_RESULT (ic)) &&
4453       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4454       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4455       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4456       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4457     {
4458       char buffer[5];
4459       SNPRINTF (buffer, sizeof(buffer),
4460                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4461       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4462     }
4463 }
4464
4465 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4466 // generates the result if possible. If result is generated, returns TRUE; otherwise
4467 // returns false and caller must deal with fact that result isn't aopOp'd.
4468 bool aopOp3(iCode * ic)
4469 {
4470     bool dp1InUse, dp2InUse;
4471     bool useDp2;
4472
4473     // First, generate the right opcode. DPTR may be used if neither left nor result are
4474     // of type AOP_STR.
4475
4476 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4477 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4478 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4479 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4480 //      );
4481 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4482 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4483 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4484 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4485 //      );
4486
4487     // Right uses DPTR unless left or result is an AOP_STR; however,
4488     // if right is an AOP_STR, it must use DPTR regardless.
4489     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4490      && !AOP_IS_STR (IC_RIGHT (ic)))
4491     {
4492         useDp2 = TRUE;
4493     }
4494     else
4495     {
4496         useDp2 = FALSE;
4497     }
4498
4499     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4500
4501     // if the right used DPTR, left MUST use DPTR2.
4502     // if the right used DPTR2, left MUST use DPTR.
4503     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4504     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4505     // enabling us to assign DPTR to result.
4506
4507     if (AOP_USESDPTR (IC_RIGHT (ic)))
4508     {
4509         useDp2 = TRUE;
4510     }
4511     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4512     {
4513         useDp2 = FALSE;
4514     }
4515     else
4516     {
4517         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4518         {
4519             useDp2 = TRUE;
4520         }
4521         else
4522         {
4523             useDp2 = FALSE;
4524         }
4525     }
4526
4527     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4528
4529
4530     // We've op'd the left & right. So, if left or right are the same operand as result,
4531     // we know aopOp will succeed, and we can just do it & bail.
4532     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4533       {
4534         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4535         return TRUE;
4536       }
4537     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4538       {
4539 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4540         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4541         return TRUE;
4542       }
4543
4544     // Operands may be equivalent (but not equal) if they share a spill location. If
4545     // so, use the same DPTR or DPTR2.
4546     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4547       {
4548         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4549         return TRUE;
4550       }
4551     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4552       {
4553         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4554         return TRUE;
4555       }
4556
4557     // Note which dptrs are currently in use.
4558     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4559     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4560
4561     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4562     // generate it.
4563     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4564     {
4565         return FALSE;
4566     }
4567
4568     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4569     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4570     {
4571         return FALSE;
4572     }
4573
4574     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4575     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4576     {
4577         return FALSE;
4578     }
4579
4580     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4581
4582     // Some sanity checking...
4583     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4584     {
4585         fprintf(stderr,
4586                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4587                 __FILE__, __LINE__, ic->filename, ic->lineno);
4588         emitcode(";", ">>> unexpected DPTR here.");
4589     }
4590
4591     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4592     {
4593         fprintf(stderr,
4594                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4595                 __FILE__, __LINE__, ic->filename, ic->lineno);
4596         emitcode(";", ">>> unexpected DPTR2 here.");
4597     }
4598
4599     return TRUE;
4600 }
4601
4602 // Macro to aopOp all three operands of an ic. If this cannot be done,
4603 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4604 // will be set TRUE. The caller must then handle the case specially, noting
4605 // that the IC_RESULT operand is not aopOp'd.
4606 //
4607 #define AOP_OP_3_NOFATAL(ic, rc) \
4608             do { rc = !aopOp3(ic); } while (0)
4609
4610 // aopOp the left & right operands of an ic.
4611 #define AOP_OP_2(ic) \
4612     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4613     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4614
4615 // convienience macro.
4616 #define AOP_SET_LOCALS(ic) \
4617     left = IC_LEFT(ic); \
4618     right = IC_RIGHT(ic); \
4619     result = IC_RESULT(ic);
4620
4621
4622 // Given an integer value of pushedSize bytes on the stack,
4623 // adjust it to be resultSize bytes, either by discarding
4624 // the most significant bytes or by zero-padding.
4625 //
4626 // On exit from this macro, pushedSize will have been adjusted to
4627 // equal resultSize, and ACC may be trashed.
4628 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4629       /* If the pushed data is bigger than the result,          \
4630        * simply discard unused bytes. Icky, but works.          \
4631        */                                                       \
4632       while (pushedSize > resultSize)                           \
4633       {                                                         \
4634           D (emitcode (";", "discarding unused result byte.")); \
4635           emitcode ("pop", "acc");                              \
4636           pushedSize--;                                         \
4637       }                                                         \
4638       if (pushedSize < resultSize)                              \
4639       {                                                         \
4640           emitcode ("clr", "a");                                \
4641           /* Conversly, we haven't pushed enough here.          \
4642            * just zero-pad, and all is well.                    \
4643            */                                                   \
4644           while (pushedSize < resultSize)                       \
4645           {                                                     \
4646               emitcode("push", "acc");                          \
4647               pushedSize++;                                     \
4648           }                                                     \
4649       }                                                         \
4650       assert(pushedSize == resultSize);
4651
4652 /*-----------------------------------------------------------------*/
4653 /* genPlus - generates code for addition                           */
4654 /*-----------------------------------------------------------------*/
4655 static void
4656 genPlus (iCode * ic)
4657 {
4658   int size, offset = 0;
4659   bool pushResult;
4660   int rSize;
4661   bool swappedLR = FALSE;
4662
4663   D (emitcode (";", "genPlus"));
4664
4665   /* special cases :- */
4666   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4667       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4668       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4669       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4670       if (size <= 9) {
4671           while (size--) emitcode ("inc","dptr");
4672       } else {
4673           emitcode ("mov", "a,dpl");
4674           emitcode ("add", "a,#!constbyte", size & 0xff);
4675           emitcode ("mov", "dpl,a");
4676           emitcode ("mov", "a,dph");
4677           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4678           emitcode ("mov", "dph,a");
4679           emitcode ("mov", "a,dpx");
4680           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4681           emitcode ("mov", "dpx,a");
4682       }
4683       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4684       return ;
4685   }
4686   if ( IS_SYMOP (IC_LEFT (ic)) &&
4687        OP_SYMBOL (IC_LEFT (ic))->remat &&
4688        isOperandInFarSpace (IC_RIGHT (ic))) {
4689       operand *op = IC_RIGHT(ic);
4690       IC_RIGHT(ic) = IC_LEFT(ic);
4691       IC_LEFT(ic) = op;
4692   }
4693
4694   AOP_OP_3_NOFATAL (ic, pushResult);
4695
4696   if (pushResult)
4697     {
4698       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4699     }
4700
4701   if (!pushResult)
4702     {
4703       /* if literal, literal on the right or
4704          if left requires ACC or right is already
4705          in ACC */
4706       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4707           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4708           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4709         {
4710           operand *t = IC_RIGHT (ic);
4711           IC_RIGHT (ic) = IC_LEFT (ic);
4712           IC_LEFT (ic) = t;
4713           swappedLR = TRUE;
4714           D (emitcode (";", "Swapped plus args."));
4715         }
4716
4717       /* if both left & right are in bit
4718          space */
4719       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4720           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4721         {
4722           genPlusBits (ic);
4723           goto release;
4724         }
4725
4726       /* if left in bit space & right literal */
4727       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4728           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4729         {
4730           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4731           /* if result in bit space */
4732           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4733             {
4734               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4735                 emitcode ("cpl", "c");
4736               outBitC (IC_RESULT (ic));
4737             }
4738           else
4739             {
4740               size = getDataSize (IC_RESULT (ic));
4741               _startLazyDPSEvaluation ();
4742               while (size--)
4743                 {
4744                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4745                   emitcode ("addc", "a,%s", zero);
4746                   aopPut (IC_RESULT (ic), "a", offset++);
4747                 }
4748               _endLazyDPSEvaluation ();
4749             }
4750           goto release;
4751         }
4752
4753       /* if I can do an increment instead
4754          of add then GOOD for ME */
4755       if (genPlusIncr (ic) == TRUE)
4756         {
4757           D (emitcode (";", "did genPlusIncr"));
4758           goto release;
4759         }
4760
4761     }
4762   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4763
4764   _startLazyDPSEvaluation ();
4765   while (size--)
4766     {
4767       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4768         {
4769           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4770           if (offset == 0)
4771             emitcode ("add", "a,%s",
4772                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4773           else
4774             emitcode ("addc", "a,%s",
4775                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4776         }
4777       else
4778         {
4779           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4780           {
4781               /* right is going to use ACC or we would have taken the
4782                * above branch.
4783                */
4784               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4785               TR_AP("#3");
4786               D(emitcode(";", "+ AOP_ACC special case."););
4787               emitcode("xch", "a, %s", DP2_RESULT_REG);
4788           }
4789           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4790           if (offset == 0)
4791           {
4792             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4793             {
4794                 TR_AP("#4");
4795                 emitcode("add", "a, %s", DP2_RESULT_REG);
4796             }
4797             else
4798             {
4799                 emitcode ("add", "a,%s",
4800                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4801                                   DP2_RESULT_REG));
4802             }
4803           }
4804           else
4805           {
4806             emitcode ("addc", "a,%s",
4807                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4808                           DP2_RESULT_REG));
4809           }
4810         }
4811       if (!pushResult)
4812         {
4813           aopPut (IC_RESULT (ic), "a", offset);
4814         }
4815       else
4816         {
4817           emitcode ("push", "acc");
4818         }
4819       offset++;
4820     }
4821   _endLazyDPSEvaluation ();
4822
4823   if (pushResult)
4824     {
4825       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4826
4827       size = getDataSize (IC_LEFT (ic));
4828       rSize = getDataSize (IC_RESULT (ic));
4829
4830       ADJUST_PUSHED_RESULT(size, rSize);
4831
4832       _startLazyDPSEvaluation ();
4833       while (size--)
4834         {
4835           emitcode ("pop", "acc");
4836           aopPut (IC_RESULT (ic), "a", size);
4837         }
4838       _endLazyDPSEvaluation ();
4839     }
4840
4841   adjustArithmeticResult (ic);
4842
4843 release:
4844   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4845   if (!swappedLR)
4846     {
4847       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4848       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4849     }
4850   else
4851     {
4852       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4853       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4854     }
4855 }
4856
4857 /*-----------------------------------------------------------------*/
4858 /* genMinusDec :- does subtraction with decrement if possible      */
4859 /*-----------------------------------------------------------------*/
4860 static bool
4861 genMinusDec (iCode * ic)
4862 {
4863   unsigned int icount;
4864   unsigned int size = getDataSize (IC_RESULT (ic));
4865
4866   /* will try to generate an increment */
4867   /* if the right side is not a literal
4868      we cannot */
4869   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4870     return FALSE;
4871
4872   /* if the literal value of the right hand side
4873      is greater than 4 then it is not worth it */
4874   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4875     return FALSE;
4876
4877   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4878       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4879       while (icount--) {
4880           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4881       }
4882       return TRUE;
4883   }
4884   /* if decrement 16 bits in register */
4885   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4886       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4887       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4888       (size > 1) &&
4889       (icount == 1))
4890     {
4891       symbol *tlbl;
4892       int    emitTlbl;
4893       int    labelRange;
4894       char   *l;
4895
4896       /* If the next instruction is a goto and the goto target
4897          * is <= 5 instructions previous to this, we can generate
4898          * jumps straight to that target.
4899        */
4900       if (ic->next && ic->next->op == GOTO
4901           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4902           && labelRange <= 5)
4903         {
4904           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4905           tlbl = IC_LABEL (ic->next);
4906           emitTlbl = 0;
4907         }
4908       else
4909         {
4910           tlbl = newiTempLabel (NULL);
4911           emitTlbl = 1;
4912         }
4913
4914       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4915       emitcode ("dec", "%s", l);
4916
4917       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4918           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4919           IS_AOP_PREG (IC_RESULT (ic)))
4920       {
4921           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4922       }
4923       else
4924       {
4925           emitcode ("mov", "a,#!constbyte",0xff);
4926           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4927       }
4928       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4929       emitcode ("dec", "%s", l);
4930       if (size > 2)
4931         {
4932             if (!strcmp(l, "acc"))
4933             {
4934                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4935             }
4936             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4937                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4938                      IS_AOP_PREG (IC_RESULT (ic)))
4939             {
4940                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4941             }
4942             else
4943             {
4944                 emitcode ("mov", "a,#!constbyte",0xff);
4945                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4946             }
4947             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4948             emitcode ("dec", "%s", l);
4949         }
4950       if (size > 3)
4951         {
4952             if (!strcmp(l, "acc"))
4953             {
4954                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4955             }
4956             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4957                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4958                      IS_AOP_PREG (IC_RESULT (ic)))
4959             {
4960                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4961             }
4962             else
4963             {
4964                 emitcode ("mov", "a,#!constbyte",0xff);
4965                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4966             }
4967             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4968             emitcode ("dec", "%s", l);
4969         }
4970       if (emitTlbl)
4971         {
4972           emitLabel (tlbl);
4973         }
4974       return TRUE;
4975     }
4976
4977   /* if the sizes are greater than 1 then we cannot */
4978   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4979       AOP_SIZE (IC_LEFT (ic)) > 1)
4980     return FALSE;
4981
4982   /* we can if the aops of the left & result match or
4983      if they are in registers and the registers are the
4984      same */
4985   if (
4986        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4987        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4988        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4989     {
4990       char *l;
4991
4992       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4993         {
4994           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4995           l = "a";
4996         }
4997       else
4998         {
4999           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5000         }
5001
5002       _startLazyDPSEvaluation ();
5003       while (icount--)
5004         {
5005           emitcode ("dec", "%s", l);
5006         }
5007       _endLazyDPSEvaluation ();
5008
5009       if (AOP_NEEDSACC (IC_RESULT (ic)))
5010         aopPut (IC_RESULT (ic), "a", 0);
5011
5012       return TRUE;
5013     }
5014
5015   return FALSE;
5016 }
5017
5018 /*-----------------------------------------------------------------*/
5019 /* addSign - complete with sign                                    */
5020 /*-----------------------------------------------------------------*/
5021 static void
5022 addSign (operand * result, int offset, int sign)
5023 {
5024   int size = (getDataSize (result) - offset);
5025   if (size > 0)
5026     {
5027       _startLazyDPSEvaluation();
5028       if (sign)
5029         {
5030           emitcode ("rlc", "a");
5031           emitcode ("subb", "a,acc");
5032           while (size--)
5033             {
5034               aopPut (result, "a", offset++);
5035             }
5036         }
5037       else
5038       {
5039         while (size--)
5040         {
5041           aopPut (result, zero, offset++);
5042         }
5043       }
5044       _endLazyDPSEvaluation();
5045     }
5046 }
5047
5048 /*-----------------------------------------------------------------*/
5049 /* genMinusBits - generates code for subtraction  of two bits      */
5050 /*-----------------------------------------------------------------*/
5051 static void
5052 genMinusBits (iCode * ic)
5053 {
5054   symbol *lbl = newiTempLabel (NULL);
5055
5056   D (emitcode (";", "genMinusBits"));
5057
5058   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5059     {
5060       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5061       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5062       emitcode ("cpl", "c");
5063       emitLabel (lbl);
5064       outBitC (IC_RESULT (ic));
5065     }
5066   else
5067     {
5068       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5069       emitcode ("subb", "a,acc");
5070       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5071       emitcode ("inc", "a");
5072       emitLabel (lbl);
5073       aopPut (IC_RESULT (ic), "a", 0);
5074       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5075     }
5076 }
5077
5078 /*-----------------------------------------------------------------*/
5079 /* genMinus - generates code for subtraction                       */
5080 /*-----------------------------------------------------------------*/
5081 static void
5082 genMinus (iCode * ic)
5083 {
5084     int size, offset = 0;
5085     int rSize;
5086     long lit = 0L;
5087     bool pushResult;
5088
5089     D (emitcode (";", "genMinus"));
5090
5091     AOP_OP_3_NOFATAL(ic, pushResult);
5092
5093     if (!pushResult)
5094     {
5095       /* special cases :- */
5096       /* if both left & right are in bit space */
5097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5098           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5099         {
5100           genMinusBits (ic);
5101           goto release;
5102         }
5103
5104       /* if I can do an decrement instead
5105          of subtract then GOOD for ME */
5106       if (genMinusDec (ic) == TRUE)
5107         goto release;
5108
5109     }
5110
5111   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5112
5113   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5114     {
5115       CLRC;
5116     }
5117   else
5118     {
5119       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5120       lit = -lit;
5121     }
5122
5123
5124   /* if literal, add a,#-lit, else normal subb */
5125   _startLazyDPSEvaluation ();
5126   while (size--) {
5127       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5128           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5129               emitcode ("mov","b,%s",
5130                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5131               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5132               emitcode ("subb","a,b");
5133           } else {
5134               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5135               emitcode ("subb", "a,%s",
5136                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5137                                 DP2_RESULT_REG));
5138           }
5139       } else {
5140           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5141           /* first add without previous c */
5142           if (!offset) {
5143               if (!size && lit==-1) {
5144                   emitcode ("dec", "a");
5145               } else {
5146                   emitcode ("add", "a,#!constbyte",
5147                             (unsigned int) (lit & 0x0FFL));
5148               }
5149           } else {
5150               emitcode ("addc", "a,#!constbyte",
5151                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5152           }
5153       }
5154
5155       if (pushResult) {
5156           emitcode ("push", "acc");
5157       } else {
5158           aopPut (IC_RESULT (ic), "a", offset);
5159       }
5160       offset++;
5161   }
5162   _endLazyDPSEvaluation ();
5163
5164   if (pushResult)
5165     {
5166       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5167
5168       size = getDataSize (IC_LEFT (ic));
5169       rSize = getDataSize (IC_RESULT (ic));
5170
5171       ADJUST_PUSHED_RESULT(size, rSize);
5172
5173       _startLazyDPSEvaluation ();
5174       while (size--)
5175         {
5176           emitcode ("pop", "acc");
5177           aopPut (IC_RESULT (ic), "a", size);
5178         }
5179       _endLazyDPSEvaluation ();
5180     }
5181
5182   adjustArithmeticResult (ic);
5183
5184 release:
5185   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5186   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5187   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5188 }
5189
5190
5191 /*-----------------------------------------------------------------*/
5192 /* genMultbits :- multiplication of bits                           */
5193 /*-----------------------------------------------------------------*/
5194 static void
5195 genMultbits (operand * left,
5196              operand * right,
5197              operand * result,
5198              iCode   * ic)
5199 {
5200   D (emitcode (";", "genMultbits"));
5201
5202   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5203   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5204   aopOp(result, ic, TRUE, FALSE);
5205   outBitC (result);
5206 }
5207
5208 /*-----------------------------------------------------------------*/
5209 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5210 /*-----------------------------------------------------------------*/
5211 static void
5212 genMultOneByte (operand * left,
5213                 operand * right,
5214                 operand * result,
5215                 iCode   * ic)
5216 {
5217   symbol *lbl;
5218   int size;
5219   bool runtimeSign, compiletimeSign;
5220   bool lUnsigned, rUnsigned, pushedB;
5221
5222   /* (if two literals: the value is computed before) */
5223   /* if one literal, literal on the right */
5224   if (AOP_TYPE (left) == AOP_LIT)
5225     {
5226       operand *t = right;
5227       right = left;
5228       left = t;
5229       /* emitcode (";", "swapped left and right"); */
5230     }
5231   /* if no literal, unsigned on the right: shorter code */
5232   if (   AOP_TYPE (right) != AOP_LIT
5233       && SPEC_USIGN (getSpec (operandType (left))))
5234     {
5235       operand *t = right;
5236       right = left;
5237       left = t;
5238     }
5239
5240   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5241   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5242
5243   pushedB = pushB ();
5244
5245   if ((lUnsigned && rUnsigned)
5246 /* sorry, I don't know how to get size
5247    without calling aopOp (result,...);
5248    see Feature Request  */
5249       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5250                    no need to take care about the signedness! */
5251     {
5252       /* just an unsigned 8 * 8 = 8 multiply
5253          or 8u * 8u = 16u */
5254       /* emitcode (";","unsigned"); */
5255       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5256       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5257       emitcode ("mul", "ab");
5258
5259       _G.accInUse++;
5260       aopOp (result, ic, TRUE, FALSE);
5261       size = AOP_SIZE (result);
5262
5263       if (size < 1 || size > 2)
5264         {
5265           /* this should never happen */
5266           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5267                    size, __FILE__, lineno);
5268           exit (1);
5269         }
5270
5271       aopPut (result, "a", 0);
5272       _G.accInUse--;
5273       if (size == 2)
5274         aopPut (result, "b", 1);
5275
5276       popB (pushedB);
5277       return;
5278     }
5279
5280   /* we have to do a signed multiply */
5281   /* emitcode (";", "signed"); */
5282
5283   /* now sign adjust for both left & right */
5284
5285   /* let's see what's needed: */
5286   /* apply negative sign during runtime */
5287   runtimeSign = FALSE;
5288   /* negative sign from literals */
5289   compiletimeSign = FALSE;
5290
5291   if (!lUnsigned)
5292     {
5293       if (AOP_TYPE(left) == AOP_LIT)
5294         {
5295           /* signed literal */
5296           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5297           if (val < 0)
5298             compiletimeSign = TRUE;
5299         }
5300       else
5301         /* signed but not literal */
5302         runtimeSign = TRUE;
5303     }
5304
5305   if (!rUnsigned)
5306     {
5307       if (AOP_TYPE(right) == AOP_LIT)
5308         {
5309           /* signed literal */
5310           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5311           if (val < 0)
5312             compiletimeSign ^= TRUE;
5313         }
5314       else
5315         /* signed but not literal */
5316         runtimeSign = TRUE;
5317     }
5318
5319   /* initialize F0, which stores the runtime sign */
5320   if (runtimeSign)
5321     {
5322       if (compiletimeSign)
5323         emitcode ("setb", "F0"); /* set sign flag */
5324       else
5325         emitcode ("clr", "F0"); /* reset sign flag */
5326     }
5327
5328   /* save the signs of the operands */
5329   if (AOP_TYPE(right) == AOP_LIT)
5330     {
5331       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5332
5333       if (!rUnsigned && val < 0)
5334         emitcode ("mov", "b,#!constbyte", -val);
5335       else
5336         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5337     }
5338   else /* ! literal */
5339     {
5340       if (rUnsigned)  /* emitcode (";", "signed"); */
5341         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5342       else
5343         {
5344           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5345           lbl = newiTempLabel (NULL);
5346           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5347           emitcode ("cpl", "F0"); /* complement sign flag */
5348           emitcode ("cpl", "a");  /* 2's complement */
5349           emitcode ("inc", "a");
5350           emitLabel (lbl);
5351           emitcode ("mov", "b,a");
5352         }
5353     }
5354
5355   if (AOP_TYPE(left) == AOP_LIT)
5356     {
5357       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5358
5359       if (!lUnsigned && val < 0)
5360         emitcode ("mov", "a,#!constbyte", -val);
5361       else
5362         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5363     }
5364   else /* ! literal */
5365     {
5366       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5367
5368       if (!lUnsigned)  /* emitcode (";", "signed"); */
5369         {
5370           lbl = newiTempLabel (NULL);
5371           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5372           emitcode ("cpl", "F0"); /* complement sign flag */
5373           emitcode ("cpl", "a");  /* 2's complement */
5374           emitcode ("inc", "a");
5375           emitLabel (lbl);
5376         }
5377     }
5378
5379   /* now the multiplication */
5380   emitcode ("mul", "ab");
5381   _G.accInUse++;
5382   aopOp(result, ic, TRUE, FALSE);
5383   size = AOP_SIZE (result);
5384
5385   if (size < 1 || size > 2)
5386     {
5387       /* this should never happen */
5388       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5389                size, __FILE__, lineno);
5390       exit (1);
5391     }
5392
5393   if (runtimeSign || compiletimeSign)
5394     {
5395       lbl = newiTempLabel (NULL);
5396       if (runtimeSign)
5397         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5398       emitcode ("cpl", "a"); /* lsb 2's complement */
5399       if (size != 2)
5400         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5401       else
5402         {
5403           emitcode ("add", "a,#1"); /* this sets carry flag */
5404           emitcode ("xch", "a,b");
5405           emitcode ("cpl", "a"); /* msb 2's complement */
5406           emitcode ("addc", "a,#0");
5407           emitcode ("xch", "a,b");
5408         }
5409       emitLabel (lbl);
5410     }
5411   aopPut (result, "a", 0);
5412   _G.accInUse--;
5413   if (size == 2)
5414     aopPut (result, "b", 1);
5415
5416   popB (pushedB);
5417 }
5418
5419 /*-----------------------------------------------------------------*/
5420 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5421 /*-----------------------------------------------------------------*/
5422 static void genMultTwoByte (operand *left, operand *right,
5423                             operand *result, iCode *ic)
5424 {
5425         sym_link *retype = getSpec(operandType(right));
5426         sym_link *letype = getSpec(operandType(left));
5427         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5428         symbol *lbl;
5429
5430         if (AOP_TYPE (left) == AOP_LIT) {
5431                 operand *t = right;
5432                 right = left;
5433                 left = t;
5434         }
5435         /* save EA bit in F1 */
5436         lbl = newiTempLabel(NULL);
5437         emitcode ("setb","F1");
5438         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5439         emitcode ("clr","F1");
5440         emitLabel (lbl);
5441
5442         /* load up MB with right */
5443         if (!umult) {
5444                 emitcode("clr","F0");
5445                 if (AOP_TYPE(right) == AOP_LIT) {
5446                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5447                         if (val < 0) {
5448                                 emitcode("setb","F0");
5449                                 val = -val;
5450                         }
5451                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5452                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5453                 } else {
5454                         lbl = newiTempLabel(NULL);
5455                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5456                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5457                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5458                         emitcode ("xch", "a,b");
5459                         emitcode ("cpl","a");
5460                         emitcode ("add", "a,#1");
5461                         emitcode ("xch", "a,b");
5462                         emitcode ("cpl", "a"); // msb
5463                         emitcode ("addc", "a,#0");
5464                         emitcode ("setb","F0");
5465                         emitLabel (lbl);
5466                         emitcode ("mov","mb,b");
5467                         emitcode ("mov","mb,a");
5468                 }
5469         } else {
5470                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5471                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5472         }
5473         /* load up MA with left */
5474         if (!umult) {
5475                 lbl = newiTempLabel(NULL);
5476                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5477                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5478                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5479                 emitcode ("xch", "a,b");
5480                 emitcode ("cpl","a");
5481                 emitcode ("add", "a,#1");
5482                 emitcode ("xch", "a,b");
5483                 emitcode ("cpl", "a"); // msb
5484                 emitcode ("addc","a,#0");
5485                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5486                 emitcode ("setb","F0");
5487                 emitLabel (lbl);
5488                 emitcode ("mov","ma,b");
5489                 emitcode ("mov","ma,a");
5490         } else {
5491                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5492                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5493         }
5494         /* wait for multiplication to finish */
5495         lbl = newiTempLabel(NULL);
5496         emitLabel (lbl);
5497         emitcode("mov","a,mcnt1");
5498         emitcode("anl","a,#!constbyte",0x80);
5499         emitcode("jnz","!tlabel",lbl->key+100);
5500
5501         freeAsmop (left, NULL, ic, TRUE);
5502         freeAsmop (right, NULL, ic,TRUE);
5503         aopOp(result, ic, TRUE, FALSE);
5504
5505         /* if unsigned then simple */
5506         if (umult) {
5507                 emitcode ("mov","a,ma");
5508                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5509                 emitcode ("mov","a,ma");
5510                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5511                 aopPut(result,"ma",1);
5512                 aopPut(result,"ma",0);
5513         } else {
5514                 emitcode("push","ma");
5515                 emitcode("push","ma");
5516                 emitcode("push","ma");
5517                 MOVA("ma");
5518                 /* negate result if needed */
5519                 lbl = newiTempLabel(NULL);
5520                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5521                 emitcode("cpl","a");
5522                 emitcode("add","a,#1");
5523                 emitLabel (lbl);
5524                 if (AOP_TYPE(result) == AOP_ACC)
5525                 {
5526                     D (emitcode(";", "ACC special case."));
5527                     /* We know result is the only live aop, and
5528                      * it's obviously not a DPTR2, so AP is available.
5529                      */
5530                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5531                 }
5532                 else
5533                 {
5534                     aopPut(result,"a",0);
5535                 }
5536
5537                 emitcode("pop","acc");
5538                 lbl = newiTempLabel(NULL);
5539                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5540                 emitcode("cpl","a");
5541                 emitcode("addc","a,#0");
5542                 emitLabel (lbl);
5543                 aopPut(result,"a",1);
5544                 emitcode("pop","acc");
5545                 if (AOP_SIZE(result) >= 3) {
5546                         lbl = newiTempLabel(NULL);
5547                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5548                         emitcode("cpl","a");
5549                         emitcode("addc","a,#0");
5550                         emitLabel (lbl);
5551                         aopPut(result,"a",2);
5552                 }
5553                 emitcode("pop","acc");
5554                 if (AOP_SIZE(result) >= 4) {
5555                         lbl = newiTempLabel(NULL);
5556                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                         emitcode("cpl","a");
5558                         emitcode("addc","a,#0");
5559                         emitLabel (lbl);
5560                         aopPut(result,"a",3);
5561                 }
5562                 if (AOP_TYPE(result) == AOP_ACC)
5563                 {
5564                     /* We stashed the result away above. */
5565                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5566                 }
5567
5568         }
5569         freeAsmop (result, NULL, ic, TRUE);
5570
5571         /* restore EA bit in F1 */
5572         lbl = newiTempLabel(NULL);
5573         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5574         emitcode ("setb","EA");
5575         emitLabel (lbl);
5576         return ;
5577 }
5578
5579 /*-----------------------------------------------------------------*/
5580 /* genMult - generates code for multiplication                     */
5581 /*-----------------------------------------------------------------*/
5582 static void
5583 genMult (iCode * ic)
5584 {
5585   operand *left = IC_LEFT (ic);
5586   operand *right = IC_RIGHT (ic);
5587   operand *result = IC_RESULT (ic);
5588
5589   D (emitcode (";", "genMult"));
5590
5591   /* assign the asmops */
5592   AOP_OP_2 (ic);
5593
5594   /* special cases first */
5595   /* both are bits */
5596   if (AOP_TYPE (left) == AOP_CRY &&
5597       AOP_TYPE (right) == AOP_CRY)
5598     {
5599       genMultbits (left, right, result, ic);
5600       goto release;
5601     }
5602
5603   /* if both are of size == 1 */
5604   if (AOP_SIZE (left) == 1 &&
5605       AOP_SIZE (right) == 1)
5606     {
5607       genMultOneByte (left, right, result, ic);
5608       goto release;
5609     }
5610
5611   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5612           /* use the ds390 ARITHMETIC accel UNIT */
5613           genMultTwoByte (left, right, result, ic);
5614           return ;
5615   }
5616   /* should have been converted to function call */
5617   assert (0);
5618
5619 release:
5620   freeAsmop (result, NULL, ic, TRUE);
5621   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5622   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5623 }
5624
5625 /*-----------------------------------------------------------------*/
5626 /* genDivbits :- division of bits                                  */
5627 /*-----------------------------------------------------------------*/
5628 static void
5629 genDivbits (operand * left,
5630             operand * right,
5631             operand * result,
5632             iCode   * ic)
5633 {
5634   char *l;
5635   bool pushedB;
5636
5637   D(emitcode (";", "genDivbits"));
5638
5639   pushedB = pushB ();
5640
5641   /* the result must be bit */
5642   LOAD_AB_FOR_DIV (left, right, l);
5643   emitcode ("div", "ab");
5644   emitcode ("rrc", "a");
5645   aopOp(result, ic, TRUE, FALSE);
5646
5647   popB (pushedB);
5648
5649   aopPut (result, "c", 0);
5650 }
5651
5652 /*-----------------------------------------------------------------*/
5653 /* genDivOneByte : 8 bit division                                  */
5654 /*-----------------------------------------------------------------*/
5655 static void
5656 genDivOneByte (operand * left,
5657                operand * right,
5658                operand * result,
5659                iCode   * ic)
5660 {
5661   bool lUnsigned, rUnsigned, pushedB;
5662   bool runtimeSign, compiletimeSign;
5663   char *l;
5664   symbol *lbl;
5665   int size, offset;
5666
5667   D(emitcode (";", "genDivOneByte"));
5668
5669   offset = 1;
5670   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5671   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5672
5673   pushedB = pushB ();
5674
5675   /* signed or unsigned */
5676   if (lUnsigned && rUnsigned)
5677     {
5678       /* unsigned is easy */
5679       LOAD_AB_FOR_DIV (left, right, l);
5680       emitcode ("div", "ab");
5681
5682       _G.accInUse++;
5683       aopOp (result, ic, TRUE, FALSE);
5684       aopPut (result, "a", 0);
5685       _G.accInUse--;
5686
5687       size = AOP_SIZE (result) - 1;
5688
5689       while (size--)
5690         aopPut (result, zero, offset++);
5691
5692       popB (pushedB);
5693       return;
5694     }
5695
5696   /* signed is a little bit more difficult */
5697
5698   /* now sign adjust for both left & right */
5699
5700   /* let's see what's needed: */
5701   /* apply negative sign during runtime */
5702   runtimeSign = FALSE;
5703   /* negative sign from literals */
5704   compiletimeSign = FALSE;
5705
5706   if (!lUnsigned)
5707     {
5708       if (AOP_TYPE(left) == AOP_LIT)
5709         {
5710           /* signed literal */
5711           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5712           if (val < 0)
5713             compiletimeSign = TRUE;
5714         }
5715       else
5716         /* signed but not literal */
5717         runtimeSign = TRUE;
5718     }
5719
5720   if (!rUnsigned)
5721     {
5722       if (AOP_TYPE(right) == AOP_LIT)
5723         {
5724           /* signed literal */
5725           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5726           if (val < 0)
5727             compiletimeSign ^= TRUE;
5728         }
5729       else
5730         /* signed but not literal */
5731         runtimeSign = TRUE;
5732     }
5733
5734   /* initialize F0, which stores the runtime sign */
5735   if (runtimeSign)
5736     {
5737       if (compiletimeSign)
5738         emitcode ("setb", "F0"); /* set sign flag */
5739       else
5740         emitcode ("clr", "F0"); /* reset sign flag */
5741     }
5742
5743   /* save the signs of the operands */
5744   if (AOP_TYPE(right) == AOP_LIT)
5745     {
5746       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5747
5748       if (!rUnsigned && val < 0)
5749         emitcode ("mov", "b,#0x%02x", -val);
5750       else
5751         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5752     }
5753   else /* ! literal */
5754     {
5755       if (rUnsigned)
5756         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5757       else
5758         {
5759           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5760           lbl = newiTempLabel (NULL);
5761           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5762           emitcode ("cpl", "F0"); /* complement sign flag */
5763           emitcode ("cpl", "a");  /* 2's complement */
5764           emitcode ("inc", "a");
5765           emitLabel (lbl);
5766           emitcode ("mov", "b,a");
5767         }
5768     }
5769
5770   if (AOP_TYPE(left) == AOP_LIT)
5771     {
5772       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5773
5774       if (!lUnsigned && val < 0)
5775         emitcode ("mov", "a,#0x%02x", -val);
5776       else
5777         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5778     }
5779   else /* ! literal */
5780     {
5781       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5782
5783       if (!lUnsigned)
5784         {
5785           lbl = newiTempLabel (NULL);
5786           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5787           emitcode ("cpl", "F0"); /* complement sign flag */
5788           emitcode ("cpl", "a");  /* 2's complement */
5789           emitcode ("inc", "a");
5790           emitLabel (lbl);
5791         }
5792     }
5793
5794   /* now the division */
5795   emitcode ("nop", "; workaround for DS80C390 div bug.");
5796   emitcode ("div", "ab");
5797
5798   if (runtimeSign || compiletimeSign)
5799     {
5800       lbl = newiTempLabel (NULL);
5801       if (runtimeSign)
5802         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5803       emitcode ("cpl", "a"); /* lsb 2's complement */
5804       emitcode ("inc", "a");
5805       emitLabel (lbl);
5806
5807       _G.accInUse++;
5808       aopOp (result, ic, TRUE, FALSE);
5809       size = AOP_SIZE (result) - 1;
5810
5811       if (size > 0)
5812         {
5813           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5814              then the result will be in b, a */
5815           emitcode ("mov", "b,a"); /* 1 */
5816           /* msb is 0x00 or 0xff depending on the sign */
5817           if (runtimeSign)
5818             {
5819               emitcode ("mov",  "c,F0");
5820               emitcode ("subb", "a,acc");
5821               emitcode ("xch",  "a,b"); /* 2 */
5822               while (size--)
5823                 aopPut (result, "b", offset++); /* write msb's */
5824             }
5825           else /* compiletimeSign */
5826             while (size--)
5827               aopPut (result, "#0xff", offset++); /* write msb's */
5828         }
5829       aopPut (result, "a", 0); /* 3: write lsb */
5830     }
5831   else
5832     {
5833       _G.accInUse++;
5834       aopOp(result, ic, TRUE, FALSE);
5835       size = AOP_SIZE (result) - 1;
5836
5837       aopPut (result, "a", 0);
5838       while (size--)
5839         aopPut (result, zero, offset++);
5840     }
5841   _G.accInUse--;
5842   popB (pushedB);
5843 }
5844
5845 /*-----------------------------------------------------------------*/
5846 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5847 /*-----------------------------------------------------------------*/
5848 static void genDivTwoByte (operand *left, operand *right,
5849                             operand *result, iCode *ic)
5850 {
5851         sym_link *retype = getSpec(operandType(right));
5852         sym_link *letype = getSpec(operandType(left));
5853         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5854         symbol *lbl;
5855
5856         /* save EA bit in F1 */
5857         lbl = newiTempLabel(NULL);
5858         emitcode ("setb","F1");
5859         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5860         emitcode ("clr","F1");
5861         emitLabel (lbl);
5862
5863         /* load up MA with left */
5864         if (!umult) {
5865                 emitcode("clr","F0");
5866                 lbl = newiTempLabel(NULL);
5867                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5868                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5869                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5870                 emitcode ("xch", "a,b");
5871                 emitcode ("cpl","a");
5872                 emitcode ("add", "a,#1");
5873                 emitcode ("xch", "a,b");
5874                 emitcode ("cpl", "a"); // msb
5875                 emitcode ("addc","a,#0");
5876                 emitcode ("setb","F0");
5877                 emitLabel (lbl);
5878                 emitcode ("mov","ma,b");
5879                 emitcode ("mov","ma,a");
5880         } else {
5881                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5882                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5883         }
5884
5885         /* load up MB with right */
5886         if (!umult) {
5887                 if (AOP_TYPE(right) == AOP_LIT) {
5888                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5889                         if (val < 0) {
5890                                 lbl = newiTempLabel(NULL);
5891                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5892                                 emitcode("setb","F0");
5893                                 emitLabel (lbl);
5894                                 val = -val;
5895                         }
5896                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5897                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5898                 } else {
5899                         lbl = newiTempLabel(NULL);
5900                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5901                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5902                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5903                         emitcode ("xch", "a,b");
5904                         emitcode ("cpl","a");
5905                         emitcode ("add", "a,#1");
5906                         emitcode ("xch", "a,b");
5907                         emitcode ("cpl", "a"); // msb
5908                         emitcode ("addc", "a,#0");
5909                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5910                         emitcode ("setb","F0");
5911                         emitLabel (lbl);
5912                         emitcode ("mov","mb,b");
5913                         emitcode ("mov","mb,a");
5914                 }
5915         } else {
5916                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5917                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5918         }
5919
5920         /* wait for multiplication to finish */
5921         lbl = newiTempLabel(NULL);
5922         emitLabel (lbl);
5923         emitcode("mov","a,mcnt1");
5924         emitcode("anl","a,#!constbyte",0x80);
5925         emitcode("jnz","!tlabel",lbl->key+100);
5926
5927         freeAsmop (left, NULL, ic, TRUE);
5928         freeAsmop (right, NULL, ic,TRUE);
5929         aopOp(result, ic, TRUE, FALSE);
5930
5931         /* if unsigned then simple */
5932         if (umult) {
5933                 aopPut(result,"ma",1);
5934                 aopPut(result,"ma",0);
5935         } else {
5936                 emitcode("push","ma");
5937                 MOVA("ma");
5938                 /* negate result if needed */
5939                 lbl = newiTempLabel(NULL);
5940                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5941                 emitcode("cpl","a");
5942                 emitcode("add","a,#1");
5943                 emitLabel (lbl);
5944                 aopPut(result,"a",0);
5945                 emitcode("pop","acc");
5946                 lbl = newiTempLabel(NULL);
5947                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5948                 emitcode("cpl","a");
5949                 emitcode("addc","a,#0");
5950                 emitLabel (lbl);
5951                 aopPut(result,"a",1);
5952         }
5953         freeAsmop (result, NULL, ic, TRUE);
5954         /* restore EA bit in F1 */
5955         lbl = newiTempLabel(NULL);
5956         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5957         emitcode ("setb","EA");
5958         emitLabel (lbl);
5959         return ;
5960 }
5961
5962 /*-----------------------------------------------------------------*/
5963 /* genDiv - generates code for division                            */
5964 /*-----------------------------------------------------------------*/
5965 static void
5966 genDiv (iCode * ic)
5967 {
5968   operand *left = IC_LEFT (ic);
5969   operand *right = IC_RIGHT (ic);
5970   operand *result = IC_RESULT (ic);
5971
5972   D (emitcode (";", "genDiv"));
5973
5974   /* assign the amsops */
5975   AOP_OP_2 (ic);
5976
5977   /* special cases first */
5978   /* both are bits */
5979   if (AOP_TYPE (left) == AOP_CRY &&
5980       AOP_TYPE (right) == AOP_CRY)
5981     {
5982       genDivbits (left, right, result, ic);
5983       goto release;
5984     }
5985
5986   /* if both are of size == 1 */
5987   if (AOP_SIZE (left) == 1 &&
5988       AOP_SIZE (right) == 1)
5989     {
5990       genDivOneByte (left, right, result, ic);
5991       goto release;
5992     }
5993
5994   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5995           /* use the ds390 ARITHMETIC accel UNIT */
5996           genDivTwoByte (left, right, result, ic);
5997           return ;
5998   }
5999   /* should have been converted to function call */
6000   assert (0);
6001 release:
6002   freeAsmop (result, NULL, ic, TRUE);
6003   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6004   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genModbits :- modulus of bits                                   */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genModbits (operand * left,
6012             operand * right,
6013             operand * result,
6014             iCode   * ic)
6015 {
6016   char *l;
6017   bool pushedB;
6018
6019   D (emitcode (";", "genModbits"));
6020
6021   pushedB = pushB ();
6022
6023   /* the result must be bit */
6024   LOAD_AB_FOR_DIV (left, right, l);
6025   emitcode ("div", "ab");
6026   emitcode ("mov", "a,b");
6027   emitcode ("rrc", "a");
6028   aopOp(result, ic, TRUE, FALSE);
6029
6030   popB (pushedB);
6031
6032   aopPut (result, "c", 0);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* genModOneByte : 8 bit modulus                                   */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 genModOneByte (operand * left,
6040                operand * right,
6041                operand * result,
6042                iCode   * ic)
6043 {
6044   bool lUnsigned, rUnsigned, pushedB;
6045   bool runtimeSign, compiletimeSign;
6046   char *l;
6047   symbol *lbl;
6048   int size, offset;
6049
6050   D (emitcode (";", "genModOneByte"));
6051
6052   offset = 1;
6053   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6054   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6055
6056   pushedB = pushB ();
6057
6058   /* signed or unsigned */
6059   if (lUnsigned && rUnsigned)
6060     {
6061       /* unsigned is easy */
6062       LOAD_AB_FOR_DIV (left, right, l);
6063       emitcode ("div", "ab");
6064       aopOp (result, ic, TRUE, FALSE);
6065       aopPut (result, "b", 0);
6066
6067       for (size = AOP_SIZE (result) - 1; size--;)
6068         aopPut (result, zero, offset++);
6069
6070       popB (pushedB);
6071       return;
6072     }
6073
6074   /* signed is a little bit more difficult */
6075
6076   /* now sign adjust for both left & right */
6077
6078   /* modulus: sign of the right operand has no influence on the result! */
6079   if (AOP_TYPE(right) == AOP_LIT)
6080     {
6081       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6082
6083       if (!rUnsigned && val < 0)
6084         emitcode ("mov", "b,#0x%02x", -val);
6085       else
6086         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6087     }
6088   else /* not literal */
6089     {
6090       if (rUnsigned)
6091         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6092       else
6093         {
6094           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6095           lbl = newiTempLabel (NULL);
6096           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6097           emitcode ("cpl", "a");  /* 2's complement */
6098           emitcode ("inc", "a");
6099           emitLabel (lbl);
6100           emitcode ("mov", "b,a");
6101         }
6102     }
6103
6104   /* let's see what's needed: */
6105   /* apply negative sign during runtime */
6106   runtimeSign = FALSE;
6107   /* negative sign from literals */
6108   compiletimeSign = FALSE;
6109
6110   /* sign adjust left side */
6111   if (AOP_TYPE(left) == AOP_LIT)
6112     {
6113       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6114
6115       if (!lUnsigned && val < 0)
6116         {
6117           compiletimeSign = TRUE; /* set sign flag */
6118           emitcode ("mov", "a,#0x%02x", -val);
6119         }
6120       else
6121         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6122     }
6123   else /* ! literal */
6124     {
6125       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6126
6127       if (!lUnsigned)
6128         {
6129           runtimeSign = TRUE;
6130           emitcode ("clr", "F0"); /* clear sign flag */
6131
6132           lbl = newiTempLabel (NULL);
6133           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6134           emitcode ("setb", "F0"); /* set sign flag */
6135           emitcode ("cpl", "a");   /* 2's complement */
6136           emitcode ("inc", "a");
6137           emitLabel (lbl);
6138         }
6139     }
6140
6141   /* now the modulus */
6142   emitcode ("nop", "; workaround for DS80C390 div bug.");
6143   emitcode ("div", "ab");
6144
6145   if (runtimeSign || compiletimeSign)
6146     {
6147       emitcode ("mov", "a,b");
6148       lbl = newiTempLabel (NULL);
6149       if (runtimeSign)
6150         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6151       emitcode ("cpl", "a"); /* lsb 2's complement */
6152       emitcode ("inc", "a");
6153       emitLabel (lbl);
6154
6155       _G.accInUse++;
6156       aopOp (result, ic, TRUE, FALSE);
6157       size = AOP_SIZE (result) - 1;
6158
6159       if (size > 0)
6160         {
6161           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6162              then the result will be in b, a */
6163           emitcode ("mov", "b,a"); /* 1 */
6164           /* msb is 0x00 or 0xff depending on the sign */
6165           if (runtimeSign)
6166             {
6167               emitcode ("mov",  "c,F0");
6168               emitcode ("subb", "a,acc");
6169               emitcode ("xch",  "a,b"); /* 2 */
6170               while (size--)
6171                 aopPut (result, "b", offset++); /* write msb's */
6172             }
6173           else /* compiletimeSign */
6174             while (size--)
6175               aopPut (result, "#0xff", offset++); /* write msb's */
6176         }
6177       aopPut (result, "a", 0); /* 3: write lsb */
6178     }
6179   else
6180     {
6181       _G.accInUse++;
6182       aopOp(result, ic, TRUE, FALSE);
6183       size = AOP_SIZE (result) - 1;
6184
6185       aopPut (result, "b", 0);
6186       while (size--)
6187         aopPut (result, zero, offset++);
6188     }
6189   _G.accInUse--;
6190   popB (pushedB);
6191 }
6192
6193 /*-----------------------------------------------------------------*/
6194 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6195 /*-----------------------------------------------------------------*/
6196 static void genModTwoByte (operand *left, operand *right,
6197                             operand *result, iCode *ic)
6198 {
6199         sym_link *retype = getSpec(operandType(right));
6200         sym_link *letype = getSpec(operandType(left));
6201         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6202         symbol *lbl;
6203
6204         /* load up MA with left */
6205         /* save EA bit in F1 */
6206         lbl = newiTempLabel(NULL);
6207         emitcode ("setb","F1");
6208         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6209         emitcode ("clr","F1");
6210         emitLabel (lbl);
6211
6212         if (!umult) {
6213                 lbl = newiTempLabel(NULL);
6214                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6215                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6216                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6217                 emitcode ("xch", "a,b");
6218                 emitcode ("cpl","a");
6219                 emitcode ("add", "a,#1");
6220                 emitcode ("xch", "a,b");
6221                 emitcode ("cpl", "a"); // msb
6222                 emitcode ("addc","a,#0");
6223                 emitLabel (lbl);
6224                 emitcode ("mov","ma,b");
6225                 emitcode ("mov","ma,a");
6226         } else {
6227                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6228                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6229         }
6230
6231         /* load up MB with right */
6232         if (!umult) {
6233                 if (AOP_TYPE(right) == AOP_LIT) {
6234                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6235                         if (val < 0) {
6236                                 val = -val;
6237                         }
6238                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6239                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6240                 } else {
6241                         lbl = newiTempLabel(NULL);
6242                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6243                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6244                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6245                         emitcode ("xch", "a,b");
6246                         emitcode ("cpl","a");
6247                         emitcode ("add", "a,#1");
6248                         emitcode ("xch", "a,b");
6249                         emitcode ("cpl", "a"); // msb
6250                         emitcode ("addc", "a,#0");
6251                         emitLabel (lbl);
6252                         emitcode ("mov","mb,b");
6253                         emitcode ("mov","mb,a");
6254                 }
6255         } else {
6256                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6257                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6258         }
6259
6260         /* wait for multiplication to finish */
6261         lbl = newiTempLabel(NULL);
6262         emitLabel (lbl);
6263         emitcode("mov","a,mcnt1");
6264         emitcode("anl","a,#!constbyte",0x80);
6265         emitcode("jnz","!tlabel",lbl->key+100);
6266
6267         freeAsmop (left, NULL, ic, TRUE);
6268         freeAsmop (right, NULL, ic,TRUE);
6269         aopOp(result, ic, TRUE, FALSE);
6270
6271         aopPut(result,"mb",1);
6272         aopPut(result,"mb",0);
6273         freeAsmop (result, NULL, ic, TRUE);
6274
6275         /* restore EA bit in F1 */
6276         lbl = newiTempLabel(NULL);
6277         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6278         emitcode ("setb","EA");
6279         emitLabel (lbl);
6280 }
6281
6282 /*-----------------------------------------------------------------*/
6283 /* genMod - generates code for division                            */
6284 /*-----------------------------------------------------------------*/
6285 static void
6286 genMod (iCode * ic)
6287 {
6288   operand *left = IC_LEFT (ic);
6289   operand *right = IC_RIGHT (ic);
6290   operand *result = IC_RESULT (ic);
6291
6292   D (emitcode (";", "genMod"));
6293
6294   /* assign the asmops */
6295   AOP_OP_2 (ic);
6296
6297   /* special cases first */
6298   /* both are bits */
6299   if (AOP_TYPE (left) == AOP_CRY &&
6300       AOP_TYPE (right) == AOP_CRY)
6301     {
6302       genModbits (left, right, result, ic);
6303       goto release;
6304     }
6305
6306   /* if both are of size == 1 */
6307   if (AOP_SIZE (left) == 1 &&
6308       AOP_SIZE (right) == 1)
6309     {
6310       genModOneByte (left, right, result, ic);
6311       goto release;
6312     }
6313
6314   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6315           /* use the ds390 ARITHMETIC accel UNIT */
6316           genModTwoByte (left, right, result, ic);
6317           return ;
6318   }
6319
6320   /* should have been converted to function call */
6321   assert (0);
6322
6323 release:
6324   freeAsmop (result, NULL, ic, TRUE);
6325   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327 }
6328
6329 /*-----------------------------------------------------------------*/
6330 /* genIfxJump :- will create a jump depending on the ifx           */
6331 /*-----------------------------------------------------------------*/
6332 static void
6333 genIfxJump (iCode * ic, char *jval)
6334 {
6335   symbol *jlbl;
6336   symbol *tlbl = newiTempLabel (NULL);
6337   char *inst;
6338
6339   D (emitcode (";", "genIfxJump"));
6340
6341   /* if true label then we jump if condition
6342      supplied is true */
6343   if (IC_TRUE (ic))
6344     {
6345       jlbl = IC_TRUE (ic);
6346       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6347                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6348     }
6349   else
6350     {
6351       /* false label is present */
6352       jlbl = IC_FALSE (ic);
6353       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6354                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6355     }
6356   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6357     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6358   else
6359     emitcode (inst, "!tlabel", tlbl->key + 100);
6360   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6361   emitLabel (tlbl);
6362
6363   /* mark the icode as generated */
6364   ic->generated = 1;
6365 }
6366
6367 /*-----------------------------------------------------------------*/
6368 /* genCmp :- greater or less than comparison                       */
6369 /*-----------------------------------------------------------------*/
6370 static void
6371 genCmp (operand * left, operand * right,
6372         iCode * ic, iCode * ifx, int sign)
6373 {
6374   int size, offset = 0;
6375   unsigned long lit = 0L;
6376   operand *result;
6377
6378   D (emitcode (";", "genCmp"));
6379
6380   result = IC_RESULT (ic);
6381
6382   /* if left & right are bit variables */
6383   if (AOP_TYPE (left) == AOP_CRY &&
6384       AOP_TYPE (right) == AOP_CRY)
6385     {
6386       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6387       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6388     }
6389   else
6390     {
6391       /* subtract right from left if at the
6392          end the carry flag is set then we know that
6393          left is greater than right */
6394       size = max (AOP_SIZE (left), AOP_SIZE (right));
6395
6396       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6397       if ((size == 1) && !sign &&
6398           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6399         {
6400           symbol *lbl = newiTempLabel (NULL);
6401           emitcode ("cjne", "%s,%s,!tlabel",
6402                     aopGet (left, offset, FALSE, FALSE, NULL),
6403                     aopGet (right, offset, FALSE, FALSE, NULL),
6404                     lbl->key + 100);
6405           emitLabel (lbl);
6406         }
6407       else
6408         {
6409           if (AOP_TYPE (right) == AOP_LIT)
6410             {
6411               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6412               /* optimize if(x < 0) or if(x >= 0) */
6413               if (lit == 0L)
6414                 {
6415                   if (!sign)
6416                     {
6417                       CLRC;
6418                     }
6419                   else
6420                     {
6421                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6422
6423                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6425
6426                       aopOp (result, ic, FALSE, FALSE);
6427
6428                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6429                         {
6430                           freeAsmop (result, NULL, ic, TRUE);
6431                           genIfxJump (ifx, "acc.7");
6432                           return;
6433                         }
6434                       else
6435                         {
6436                           emitcode ("rlc", "a");
6437                         }
6438                       goto release_freedLR;
6439                     }
6440                   goto release;
6441                 }
6442             }
6443           CLRC;
6444           while (size--)
6445             {
6446               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6447               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6448               // emitcode (";", "genCmp #2");
6449               if (sign && (size == 0))
6450                 {
6451                   // emitcode (";", "genCmp #3");
6452                   emitcode ("xrl", "a,#!constbyte",0x80);
6453                   if (AOP_TYPE (right) == AOP_LIT)
6454                     {
6455                       unsigned long lit = (unsigned long)
6456                       floatFromVal (AOP (right)->aopu.aop_lit);
6457                       // emitcode (";", "genCmp #3.1");
6458                       emitcode ("subb", "a,#!constbyte",
6459                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6460                     }
6461                   else
6462                     {
6463                       // emitcode (";", "genCmp #3.2");
6464                       saveAccWarn = 0;
6465                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6466                       saveAccWarn = DEFAULT_ACC_WARNING;
6467                       emitcode ("xrl", "b,#!constbyte",0x80);
6468                       emitcode ("subb", "a,b");
6469                     }
6470                 }
6471               else
6472                 {
6473                   const char *s;
6474
6475                   // emitcode (";", "genCmp #4");
6476                   saveAccWarn = 0;
6477                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6478                   saveAccWarn = DEFAULT_ACC_WARNING;
6479
6480                   emitcode ("subb", "a,%s", s);
6481                 }
6482             }
6483         }
6484     }
6485
6486 release:
6487 /* Don't need the left & right operands any more; do need the result. */
6488   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6490
6491   aopOp (result, ic, FALSE, FALSE);
6492
6493 release_freedLR:
6494
6495   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6496     {
6497       outBitC (result);
6498     }
6499   else
6500     {
6501       /* if the result is used in the next
6502          ifx conditional branch then generate
6503          code a little differently */
6504       if (ifx)
6505         {
6506           genIfxJump (ifx, "c");
6507         }
6508       else
6509         {
6510           outBitC (result);
6511         }
6512       /* leave the result in acc */
6513     }
6514   freeAsmop (result, NULL, ic, TRUE);
6515 }
6516
6517 /*-----------------------------------------------------------------*/
6518 /* genCmpGt :- greater than comparison                             */
6519 /*-----------------------------------------------------------------*/
6520 static void
6521 genCmpGt (iCode * ic, iCode * ifx)
6522 {
6523   operand *left, *right;
6524   sym_link *letype, *retype;
6525   int sign;
6526
6527   D (emitcode (";", "genCmpGt"));
6528
6529   left = IC_LEFT (ic);
6530   right = IC_RIGHT (ic);
6531
6532   letype = getSpec (operandType (left));
6533   retype = getSpec (operandType (right));
6534   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6535
6536   /* assign the left & right amsops */
6537   AOP_OP_2 (ic);
6538
6539   genCmp (right, left, ic, ifx, sign);
6540 }
6541
6542 /*-----------------------------------------------------------------*/
6543 /* genCmpLt - less than comparisons                                */
6544 /*-----------------------------------------------------------------*/
6545 static void
6546 genCmpLt (iCode * ic, iCode * ifx)
6547 {
6548   operand *left, *right;
6549   sym_link *letype, *retype;
6550   int sign;
6551
6552   D (emitcode (";", "genCmpLt"));
6553
6554   left = IC_LEFT (ic);
6555   right = IC_RIGHT (ic);
6556
6557   letype = getSpec (operandType (left));
6558   retype = getSpec (operandType (right));
6559   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6560
6561   /* assign the left & right amsops */
6562   AOP_OP_2 (ic);
6563
6564   genCmp (left, right, ic, ifx, sign);
6565 }
6566
6567 /*-----------------------------------------------------------------*/
6568 /* gencjneshort - compare and jump if not equal                    */
6569 /*-----------------------------------------------------------------*/
6570 static void
6571 gencjneshort (operand * left, operand * right, symbol * lbl)
6572 {
6573   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6574   int offset = 0;
6575   unsigned long lit = 0L;
6576
6577   D (emitcode (";", "gencjneshort"));
6578
6579   /* if the left side is a literal or
6580      if the right is in a pointer register and left
6581      is not */
6582   if ((AOP_TYPE (left) == AOP_LIT) ||
6583       (AOP_TYPE (left) == AOP_IMMD) ||
6584       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6585     {
6586       operand *t = right;
6587       right = left;
6588       left = t;
6589     }
6590
6591   if (AOP_TYPE (right) == AOP_LIT)
6592     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6593
6594   if (opIsGptr (left) || opIsGptr (right))
6595     {
6596       /* We are comparing a generic pointer to something.
6597        * Exclude the generic type byte from the comparison.
6598        */
6599       size--;
6600       D (emitcode (";", "cjneshort: generic ptr special case."););
6601     }
6602
6603
6604   /* if the right side is a literal then anything goes */
6605   if (AOP_TYPE (right) == AOP_LIT &&
6606       AOP_TYPE (left) != AOP_DIR)
6607     {
6608       while (size--)
6609         {
6610           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6611           emitcode ("cjne", "a,%s,!tlabel",
6612                     aopGet (right, offset, FALSE, FALSE, NULL),
6613                     lbl->key + 100);
6614           offset++;
6615         }
6616     }
6617
6618   /* if the right side is in a register or in direct space or
6619      if the left is a pointer register & right is not */
6620   else if (AOP_TYPE (right) == AOP_REG ||
6621            AOP_TYPE (right) == AOP_DIR ||
6622            AOP_TYPE (right) == AOP_LIT ||
6623            AOP_TYPE (right) == AOP_IMMD ||
6624            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6625            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6626     {
6627       while (size--)
6628         {
6629           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6630           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6631               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6632             emitcode ("jnz", "!tlabel", lbl->key + 100);
6633           else
6634             emitcode ("cjne", "a,%s,!tlabel",
6635                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6636                       lbl->key + 100);
6637           offset++;
6638         }
6639     }
6640   else
6641     {
6642       /* right is a pointer reg need both a & b */
6643       while (size--)
6644         {
6645           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6646           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6647           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6648           offset++;
6649         }
6650     }
6651 }
6652
6653 /*-----------------------------------------------------------------*/
6654 /* gencjne - compare and jump if not equal                         */
6655 /*-----------------------------------------------------------------*/
6656 static void
6657 gencjne (operand * left, operand * right, symbol * lbl)
6658 {
6659   symbol *tlbl = newiTempLabel (NULL);
6660
6661   D (emitcode (";", "gencjne"));
6662
6663   gencjneshort (left, right, lbl);
6664
6665   emitcode ("mov", "a,%s", one);
6666   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6667   emitLabel (lbl);
6668   emitcode ("clr", "a");
6669   emitLabel (tlbl);
6670 }
6671
6672 /*-----------------------------------------------------------------*/
6673 /* genCmpEq - generates code for equal to                          */
6674 /*-----------------------------------------------------------------*/
6675 static void
6676 genCmpEq (iCode * ic, iCode * ifx)
6677 {
6678   operand *left, *right, *result;
6679
6680   D (emitcode (";", "genCmpEq"));
6681
6682   AOP_OP_2 (ic);
6683   AOP_SET_LOCALS (ic);
6684
6685   /* if literal, literal on the right or
6686      if the right is in a pointer register and left
6687      is not */
6688   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6689       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6690     {
6691       operand *t = IC_RIGHT (ic);
6692       IC_RIGHT (ic) = IC_LEFT (ic);
6693       IC_LEFT (ic) = t;
6694     }
6695
6696   if (ifx &&                    /* !AOP_SIZE(result) */
6697       OP_SYMBOL (result) &&
6698       OP_SYMBOL (result)->regType == REG_CND)
6699     {
6700       symbol *tlbl;
6701       /* if they are both bit variables */
6702       if (AOP_TYPE (left) == AOP_CRY &&
6703           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6704         {
6705           if (AOP_TYPE (right) == AOP_LIT)
6706             {
6707               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6708               if (lit == 0L)
6709                 {
6710                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6711                   emitcode ("cpl", "c");
6712                 }
6713               else if (lit == 1L)
6714                 {
6715                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6716                 }
6717               else
6718                 {
6719                   emitcode ("clr", "c");
6720                 }
6721               /* AOP_TYPE(right) == AOP_CRY */
6722             }
6723           else
6724             {
6725               symbol *lbl = newiTempLabel (NULL);
6726               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6727               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6728               emitcode ("cpl", "c");
6729               emitLabel (lbl);
6730             }
6731           /* if true label then we jump if condition
6732              supplied is true */
6733           tlbl = newiTempLabel (NULL);
6734           if (IC_TRUE (ifx))
6735             {
6736               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6737               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6738             }
6739           else
6740             {
6741               emitcode ("jc", "!tlabel", tlbl->key + 100);
6742               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6743             }
6744           emitLabel (tlbl);
6745         }
6746       else
6747         {
6748           tlbl = newiTempLabel (NULL);
6749           gencjneshort (left, right, tlbl);
6750           if (IC_TRUE (ifx))
6751             {
6752               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6753               emitLabel (tlbl);
6754             }
6755           else
6756             {
6757               symbol *lbl = newiTempLabel (NULL);
6758               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6759               emitLabel (tlbl);
6760               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6761               emitLabel (lbl);
6762             }
6763         }
6764       /* mark the icode as generated */
6765       ifx->generated = 1;
6766
6767       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6768       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6769       return;
6770     }
6771
6772   /* if they are both bit variables */
6773   if (AOP_TYPE (left) == AOP_CRY &&
6774       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6775     {
6776       if (AOP_TYPE (right) == AOP_LIT)
6777         {
6778           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6779           if (lit == 0L)
6780             {
6781               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6782               emitcode ("cpl", "c");
6783             }
6784           else if (lit == 1L)
6785             {
6786               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6787             }
6788           else
6789             {
6790               emitcode ("clr", "c");
6791             }
6792           /* AOP_TYPE(right) == AOP_CRY */
6793         }
6794       else
6795         {
6796           symbol *lbl = newiTempLabel (NULL);
6797           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6798           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6799           emitcode ("cpl", "c");
6800           emitLabel (lbl);
6801         }
6802
6803       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6804       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6805
6806       aopOp (result, ic, TRUE, FALSE);
6807
6808       /* c = 1 if egal */
6809       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6810         {
6811           outBitC (result);
6812           goto release;
6813         }
6814       if (ifx)
6815         {
6816           genIfxJump (ifx, "c");
6817           goto release;
6818         }
6819       /* if the result is used in an arithmetic operation
6820          then put the result in place */
6821       outBitC (result);
6822     }
6823   else
6824     {
6825       gencjne (left, right, newiTempLabel (NULL));
6826
6827       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6829
6830       aopOp (result, ic, TRUE, FALSE);
6831
6832       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6833         {
6834           aopPut (result, "a", 0);
6835           goto release;
6836         }
6837       if (ifx)
6838         {
6839           genIfxJump (ifx, "a");
6840           goto release;
6841         }
6842       /* if the result is used in an arithmetic operation
6843          then put the result in place */
6844       if (AOP_TYPE (result) != AOP_CRY)
6845         outAcc (result);
6846       /* leave the result in acc */
6847     }
6848
6849 release:
6850   freeAsmop (result, NULL, ic, TRUE);
6851 }
6852
6853 /*-----------------------------------------------------------------*/
6854 /* ifxForOp - returns the icode containing the ifx for operand     */
6855 /*-----------------------------------------------------------------*/
6856 static iCode *
6857 ifxForOp (operand * op, iCode * ic)
6858 {
6859   /* if true symbol then needs to be assigned */
6860   if (IS_TRUE_SYMOP (op))
6861     return NULL;
6862
6863   /* if this has register type condition and
6864      the next instruction is ifx with the same operand
6865      and live to of the operand is upto the ifx only then */
6866   if (ic->next &&
6867       ic->next->op == IFX &&
6868       IC_COND (ic->next)->key == op->key &&
6869       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6870     return ic->next;
6871
6872   return NULL;
6873 }
6874
6875 /*-----------------------------------------------------------------*/
6876 /* hasInc - operand is incremented before any other use            */
6877 /*-----------------------------------------------------------------*/
6878 static iCode *
6879 hasInc (operand *op, iCode *ic, int osize)
6880 {
6881   sym_link *type = operandType(op);
6882   sym_link *retype = getSpec (type);
6883   iCode *lic = ic->next;
6884   int isize ;
6885
6886   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6887   if (!IS_SYMOP(op)) return NULL;
6888
6889   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6890   if (IS_AGGREGATE(type->next)) return NULL;
6891   if (osize != (isize = getSize(type->next))) return NULL;
6892
6893   while (lic) {
6894       /* if operand of the form op = op + <sizeof *op> */
6895       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6896           isOperandEqual(IC_RESULT(lic),op) &&
6897           isOperandLiteral(IC_RIGHT(lic)) &&
6898           operandLitValue(IC_RIGHT(lic)) == isize) {
6899           return lic;
6900       }
6901       /* if the operand used or deffed */
6902       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6903           return NULL;
6904       }
6905       /* if GOTO or IFX */
6906       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6907       lic = lic->next;
6908   }
6909   return NULL;
6910 }
6911
6912 /*-----------------------------------------------------------------*/
6913 /* genAndOp - for && operation                                     */
6914 /*-----------------------------------------------------------------*/
6915 static void
6916 genAndOp (iCode * ic)
6917 {
6918   operand *left, *right, *result;
6919   symbol *tlbl;
6920
6921   D (emitcode (";", "genAndOp"));
6922
6923   /* note here that && operations that are in an
6924      if statement are taken away by backPatchLabels
6925      only those used in arthmetic operations remain */
6926   AOP_OP_2 (ic);
6927   AOP_SET_LOCALS (ic);
6928
6929   /* if both are bit variables */
6930   if (AOP_TYPE (left) == AOP_CRY &&
6931       AOP_TYPE (right) == AOP_CRY)
6932     {
6933       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6934       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6935       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6936       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6937
6938       aopOp (result,ic,FALSE, FALSE);
6939       outBitC (result);
6940     }
6941   else
6942     {
6943       tlbl = newiTempLabel (NULL);
6944       toBoolean (left);
6945       emitcode ("jz", "!tlabel", tlbl->key + 100);
6946       toBoolean (right);
6947       emitLabel (tlbl);
6948       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6949       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6950
6951       aopOp (result,ic,FALSE, FALSE);
6952       outBitAcc (result);
6953     }
6954
6955     freeAsmop (result, NULL, ic, TRUE);
6956 }
6957
6958
6959 /*-----------------------------------------------------------------*/
6960 /* genOrOp - for || operation                                      */
6961 /*-----------------------------------------------------------------*/
6962 static void
6963 genOrOp (iCode * ic)
6964 {
6965   operand *left, *right, *result;
6966   symbol *tlbl;
6967
6968   D (emitcode (";", "genOrOp"));
6969
6970   /* note here that || operations that are in an
6971      if statement are taken away by backPatchLabels
6972      only those used in arthmetic operations remain */
6973   AOP_OP_2 (ic);
6974   AOP_SET_LOCALS (ic);
6975
6976   /* if both are bit variables */
6977   if (AOP_TYPE (left) == AOP_CRY &&
6978       AOP_TYPE (right) == AOP_CRY)
6979     {
6980       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6981       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6982       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6983       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6984
6985       aopOp (result,ic,FALSE, FALSE);
6986
6987       outBitC (result);
6988     }
6989   else
6990     {
6991       tlbl = newiTempLabel (NULL);
6992       toBoolean (left);
6993       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6994       toBoolean (right);
6995       emitLabel (tlbl);
6996       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6997       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6998
6999       aopOp (result,ic,FALSE, FALSE);
7000
7001       outBitAcc (result);
7002     }
7003
7004   freeAsmop (result, NULL, ic, TRUE);
7005 }
7006
7007 /*-----------------------------------------------------------------*/
7008 /* isLiteralBit - test if lit == 2^n                               */
7009 /*-----------------------------------------------------------------*/
7010 static int
7011 isLiteralBit (unsigned long lit)
7012 {
7013   unsigned long pw[32] =
7014   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7015    0x100L, 0x200L, 0x400L, 0x800L,
7016    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7017    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7018    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7019    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7020    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7021   int idx;
7022
7023   for (idx = 0; idx < 32; idx++)
7024     if (lit == pw[idx])
7025       return idx + 1;
7026   return 0;
7027 }
7028
7029 /*-----------------------------------------------------------------*/
7030 /* continueIfTrue -                                                */
7031 /*-----------------------------------------------------------------*/
7032 static void
7033 continueIfTrue (iCode * ic)
7034 {
7035   if (IC_TRUE (ic))
7036     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7037   ic->generated = 1;
7038 }
7039
7040 /*-----------------------------------------------------------------*/
7041 /* jmpIfTrue -                                                     */
7042 /*-----------------------------------------------------------------*/
7043 static void
7044 jumpIfTrue (iCode * ic)
7045 {
7046   if (!IC_TRUE (ic))
7047     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7048   ic->generated = 1;
7049 }
7050
7051 /*-----------------------------------------------------------------*/
7052 /* jmpTrueOrFalse -                                                */
7053 /*-----------------------------------------------------------------*/
7054 static void
7055 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7056 {
7057   // ugly but optimized by peephole
7058   if (IC_TRUE (ic))
7059     {
7060       symbol *nlbl = newiTempLabel (NULL);
7061       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7062       emitLabel (tlbl);
7063       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7064       emitLabel (nlbl);
7065     }
7066   else
7067     {
7068       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7069       emitLabel (tlbl);
7070     }
7071   ic->generated = 1;
7072 }
7073
7074 // Generate code to perform a bit-wise logic operation
7075 // on two operands in far space (assumed to already have been
7076 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7077 // in far space. This requires pushing the result on the stack
7078 // then popping it into the result.
7079 static void
7080 genFarFarLogicOp(iCode *ic, char *logicOp)
7081 {
7082       int size, resultSize, compSize;
7083       int offset = 0;
7084
7085       TR_AP("#5");
7086       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7087       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7088                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7089
7090       _startLazyDPSEvaluation();
7091       for (size = compSize; (size--); offset++)
7092       {
7093           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7094           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7095           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7096
7097           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7098           emitcode ("push", "acc");
7099       }
7100       _endLazyDPSEvaluation();
7101
7102       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7103       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7104       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7105
7106       resultSize = AOP_SIZE(IC_RESULT(ic));
7107
7108       ADJUST_PUSHED_RESULT(compSize, resultSize);
7109
7110       _startLazyDPSEvaluation();
7111       while (compSize--)
7112       {
7113           emitcode ("pop", "acc");
7114           aopPut (IC_RESULT (ic), "a", compSize);
7115       }
7116       _endLazyDPSEvaluation();
7117       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7118 }
7119
7120
7121 /*-----------------------------------------------------------------*/
7122 /* genAnd  - code for and                                          */
7123 /*-----------------------------------------------------------------*/
7124 static void
7125 genAnd (iCode * ic, iCode * ifx)
7126 {
7127   operand *left, *right, *result;
7128   int size, offset = 0;
7129   unsigned long lit = 0L;
7130   int bytelit = 0;
7131   char buffer[10];
7132   bool pushResult;
7133
7134   D (emitcode (";", "genAnd"));
7135
7136   AOP_OP_3_NOFATAL (ic, pushResult);
7137   AOP_SET_LOCALS (ic);
7138
7139   if (pushResult)
7140   {
7141       genFarFarLogicOp(ic, "anl");
7142       return;
7143   }
7144
7145 #ifdef DEBUG_TYPE
7146   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7147             AOP_TYPE (result),
7148             AOP_TYPE (left), AOP_TYPE (right));
7149   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7150             AOP_SIZE (result),
7151             AOP_SIZE (left), AOP_SIZE (right));
7152 #endif
7153
7154   /* if left is a literal & right is not then exchange them */
7155   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7156 #ifdef LOGIC_OPS_BROKEN
7157     ||  AOP_NEEDSACC (left)
7158 #endif
7159     )
7160     {
7161       operand *tmp = right;
7162       right = left;
7163       left = tmp;
7164     }
7165
7166   /* if result = right then exchange left and right */
7167   if (sameRegs (AOP (result), AOP (right)))
7168     {
7169       operand *tmp = right;
7170       right = left;
7171       left = tmp;
7172     }
7173
7174   /* if right is bit then exchange them */
7175   if (AOP_TYPE (right) == AOP_CRY &&
7176       AOP_TYPE (left) != AOP_CRY)
7177     {
7178       operand *tmp = right;
7179       right = left;
7180       left = tmp;
7181     }
7182   if (AOP_TYPE (right) == AOP_LIT)
7183     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7184
7185   size = AOP_SIZE (result);
7186
7187   // if(bit & yy)
7188   // result = bit & yy;
7189   if (AOP_TYPE (left) == AOP_CRY)
7190     {
7191       // c = bit & literal;
7192       if (AOP_TYPE (right) == AOP_LIT)
7193         {
7194           if (lit & 1)
7195             {
7196               if (size && sameRegs (AOP (result), AOP (left)))
7197                 // no change
7198                 goto release;
7199               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7200             }
7201           else
7202             {
7203               // bit(result) = 0;
7204               if (size && (AOP_TYPE (result) == AOP_CRY))
7205                 {
7206                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7207                   goto release;
7208                 }
7209               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7210                 {
7211                   jumpIfTrue (ifx);
7212                   goto release;
7213                 }
7214               emitcode ("clr", "c");
7215             }
7216         }
7217       else
7218         {
7219           if (AOP_TYPE (right) == AOP_CRY)
7220             {
7221               // c = bit & bit;
7222               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7223               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7224             }
7225           else
7226             {
7227               // c = bit & val;
7228               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7229               // c = lsb
7230               emitcode ("rrc", "a");
7231               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7232             }
7233         }
7234       // bit = c
7235       // val = c
7236       if (size)
7237         outBitC (result);
7238       // if(bit & ...)
7239       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7240         genIfxJump (ifx, "c");
7241       goto release;
7242     }
7243
7244   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7245   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7246   if ((AOP_TYPE (right) == AOP_LIT) &&
7247       (AOP_TYPE (result) == AOP_CRY) &&
7248       (AOP_TYPE (left) != AOP_CRY))
7249     {
7250       int posbit = isLiteralBit (lit);
7251       /* left &  2^n */
7252       if (posbit)
7253         {
7254           posbit--;
7255           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7256           // bit = left & 2^n
7257           if (size)
7258             {
7259               switch (posbit & 0x07)
7260                 {
7261                   case 0: emitcode ("rrc", "a");
7262                           break;
7263                   case 7: emitcode ("rlc", "a");
7264                           break;
7265                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7266                           break;
7267                 }
7268             }
7269           // if(left &  2^n)
7270           else
7271             {
7272               if (ifx)
7273                 {
7274                   SNPRINTF (buffer, sizeof(buffer),
7275                             "acc.%d", posbit & 0x07);
7276                   genIfxJump (ifx, buffer);
7277                 }
7278               else
7279                 {
7280                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7281                 }
7282               goto release;
7283             }
7284         }
7285       else
7286         {
7287           symbol *tlbl = newiTempLabel (NULL);
7288           int sizel = AOP_SIZE (left);
7289           if (size)
7290             emitcode ("setb", "c");
7291           while (sizel--)
7292             {
7293               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7294                 {
7295                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7296                   // byte ==  2^n ?
7297                   if ((posbit = isLiteralBit (bytelit)) != 0)
7298                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7299                   else
7300                     {
7301                       if (bytelit != 0x0FFL)
7302                         emitcode ("anl", "a,%s",
7303                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7304                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7305                     }
7306                 }
7307               offset++;
7308             }
7309           // bit = left & literal
7310           if (size)
7311             {
7312               emitcode ("clr", "c");
7313               emitLabel (tlbl);
7314             }
7315           // if(left & literal)
7316           else
7317             {
7318               if (ifx)
7319                 jmpTrueOrFalse (ifx, tlbl);
7320               else
7321                 emitLabel (tlbl);
7322               goto release;
7323             }
7324         }
7325       outBitC (result);
7326       goto release;
7327     }
7328
7329   /* if left is same as result */
7330   if (sameRegs (AOP (result), AOP (left)))
7331     {
7332       for (; size--; offset++)
7333         {
7334           if (AOP_TYPE (right) == AOP_LIT)
7335             {
7336               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7337               if (bytelit == 0x0FF)
7338                 {
7339                   /* dummy read of volatile operand */
7340                   if (isOperandVolatile (left, FALSE))
7341                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7342                   else
7343                     continue;
7344                 }
7345               else if (bytelit == 0)
7346                 {
7347                   aopPut (result, zero, offset);
7348                 }
7349               else if (IS_AOP_PREG (result))
7350                 {
7351                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7352                   emitcode ("anl", "a,%s",
7353                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7354                   aopPut (result, "a", offset);
7355                 }
7356               else
7357                 emitcode ("anl", "%s,%s",
7358                           aopGet (left, offset, FALSE, TRUE, NULL),
7359                           aopGet (right, offset, FALSE, FALSE, NULL));
7360             }
7361           else
7362             {
7363               if (AOP_TYPE (left) == AOP_ACC)
7364                 {
7365                   if (offset)
7366                     emitcode("mov", "a,b");
7367                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7368                 }
7369               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7370                 {
7371                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7372                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7373                   emitcode ("anl", "a,b");
7374                   aopPut (result, "a", offset);
7375                 }
7376               else if (aopGetUsesAcc (left, offset))
7377                 {
7378                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7379                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7380                   aopPut (result, "a", offset);
7381                 }
7382               else
7383                 {
7384                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7385                   if (IS_AOP_PREG (result))
7386                     {
7387                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7388                       aopPut (result, "a", offset);
7389                     }
7390                   else
7391                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7392                 }
7393             }
7394         }
7395     }
7396   else
7397     {
7398       // left & result in different registers
7399       if (AOP_TYPE (result) == AOP_CRY)
7400         {
7401           // result = bit
7402           // if(size), result in bit
7403           // if(!size && ifx), conditional oper: if(left & right)
7404           symbol *tlbl = newiTempLabel (NULL);
7405           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7406           if (size)
7407             emitcode ("setb", "c");
7408           while (sizer--)
7409             {
7410               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7411                   && AOP_TYPE(left)==AOP_ACC)
7412                 {
7413                   if (offset)
7414                     emitcode("mov", "a,b");
7415                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7416                 }
7417               else if (AOP_TYPE(left)==AOP_ACC)
7418                 {
7419                   if (!offset)
7420                     {
7421                       bool pushedB = pushB ();
7422                       emitcode("mov", "b,a");
7423                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7424                       emitcode("anl", "a,b");
7425                       popB (pushedB);
7426                     }
7427                   else
7428                     {
7429                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7430                       emitcode("anl", "a,b");
7431                     }
7432                 }
7433               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7434                 {
7435                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7436                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7437                   emitcode ("anl", "a,b");
7438                 }
7439               else if (aopGetUsesAcc (left, offset))
7440                 {
7441                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7442                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7443                 }
7444               else
7445                 {
7446                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7447                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7448                 }
7449
7450               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7451               offset++;
7452             }
7453           if (size)
7454             {
7455               CLRC;
7456               emitLabel (tlbl);
7457               outBitC (result);
7458             }
7459           else if (ifx)
7460             jmpTrueOrFalse (ifx, tlbl);
7461           else
7462             emitLabel (tlbl);
7463         }
7464       else
7465         {
7466           for (; (size--); offset++)
7467             {
7468               // normal case
7469               // result = left & right
7470               if (AOP_TYPE (right) == AOP_LIT)
7471                 {
7472                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7473                   if (bytelit == 0x0FF)
7474                     {
7475                       aopPut (result,
7476                               aopGet (left, offset, FALSE, FALSE, NULL),
7477                               offset);
7478                       continue;
7479                     }
7480                   else if (bytelit == 0)
7481                     {
7482                       /* dummy read of volatile operand */
7483                       if (isOperandVolatile (left, FALSE))
7484                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7485                       aopPut (result, zero, offset);
7486                       continue;
7487                     }
7488                   else if (AOP_TYPE (left) == AOP_ACC)
7489                     {
7490                       if (!offset)
7491                         {
7492                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7493                           aopPut (result, "a", offset);
7494                           continue;
7495                         }
7496                       else
7497                         {
7498                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7499                           aopPut (result, "b", offset);
7500                           continue;
7501                         }
7502                     }
7503                 }
7504               // faster than result <- left, anl result,right
7505               // and better if result is SFR
7506               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7507                   && AOP_TYPE(left)==AOP_ACC)
7508                 {
7509                   if (offset)
7510                     emitcode("mov", "a,b");
7511                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7512                 }
7513               else if (AOP_TYPE(left)==AOP_ACC)
7514                 {
7515                   if (!offset)
7516                     {
7517                       bool pushedB = pushB ();
7518                       emitcode("mov", "b,a");
7519                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7520                       emitcode("anl", "a,b");
7521                       popB (pushedB);
7522                     }
7523                   else
7524                     {
7525                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7526                       emitcode("anl", "a,b");
7527                     }
7528                 }
7529               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7530                 {
7531                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7532                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7533                   emitcode ("anl", "a,b");
7534                 }
7535               else if (aopGetUsesAcc (left, offset))
7536                 {
7537                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7538                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7539                 }
7540               else
7541                 {
7542                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7543                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7544                 }
7545               aopPut (result, "a", offset);
7546             }
7547         }
7548     }
7549
7550 release:
7551   freeAsmop (result, NULL, ic, TRUE);
7552   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7553   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7554 }
7555
7556 /*-----------------------------------------------------------------*/
7557 /* genOr  - code for or                                            */
7558 /*-----------------------------------------------------------------*/
7559 static void
7560 genOr (iCode * ic, iCode * ifx)
7561 {
7562   operand *left, *right, *result;
7563   int size, offset = 0;
7564   unsigned long lit = 0L;
7565   int bytelit = 0;
7566   bool     pushResult;
7567
7568   D (emitcode (";", "genOr"));
7569
7570   AOP_OP_3_NOFATAL (ic, pushResult);
7571   AOP_SET_LOCALS (ic);
7572
7573   if (pushResult)
7574   {
7575       genFarFarLogicOp(ic, "orl");
7576       return;
7577   }
7578
7579
7580 #ifdef DEBUG_TYPE
7581   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7582             AOP_TYPE (result),
7583             AOP_TYPE (left), AOP_TYPE (right));
7584   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7585             AOP_SIZE (result),
7586             AOP_SIZE (left), AOP_SIZE (right));
7587 #endif
7588
7589   /* if left is a literal & right is not then exchange them */
7590   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7591 #ifdef LOGIC_OPS_BROKEN
7592    || AOP_NEEDSACC (left) // I think this is a net loss now.
7593 #endif
7594       )
7595     {
7596       operand *tmp = right;
7597       right = left;
7598       left = tmp;
7599     }
7600
7601   /* if result = right then exchange them */
7602   if (sameRegs (AOP (result), AOP (right)))
7603     {
7604       operand *tmp = right;
7605       right = left;
7606       left = tmp;
7607     }
7608
7609   /* if right is bit then exchange them */
7610   if (AOP_TYPE (right) == AOP_CRY &&
7611       AOP_TYPE (left) != AOP_CRY)
7612     {
7613       operand *tmp = right;
7614       right = left;
7615       left = tmp;
7616     }
7617   if (AOP_TYPE (right) == AOP_LIT)
7618     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7619
7620   size = AOP_SIZE (result);
7621
7622   // if(bit | yy)
7623   // xx = bit | yy;
7624   if (AOP_TYPE (left) == AOP_CRY)
7625     {
7626       if (AOP_TYPE (right) == AOP_LIT)
7627         {
7628           // c = bit | literal;
7629           if (lit)
7630             {
7631               // lit != 0 => result = 1
7632               if (AOP_TYPE (result) == AOP_CRY)
7633                 {
7634                   if (size)
7635                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7636                   else if (ifx)
7637                     continueIfTrue (ifx);
7638                   goto release;
7639                 }
7640               emitcode ("setb", "c");
7641             }
7642           else
7643             {
7644               // lit == 0 => result = left
7645               if (size && sameRegs (AOP (result), AOP (left)))
7646                 goto release;
7647               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7648             }
7649         }
7650       else
7651         {
7652           if (AOP_TYPE (right) == AOP_CRY)
7653             {
7654               // c = bit | bit;
7655               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7656               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7657             }
7658           else
7659             {
7660               // c = bit | val;
7661               symbol *tlbl = newiTempLabel (NULL);
7662               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7663                 emitcode ("setb", "c");
7664               emitcode ("jb", "%s,!tlabel",
7665                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7666               toBoolean (right);
7667               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7668               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7669                 {
7670                   jmpTrueOrFalse (ifx, tlbl);
7671                   goto release;
7672                 }
7673               else
7674                 {
7675                   CLRC;
7676                   emitLabel (tlbl);
7677                 }
7678             }
7679         }
7680       // bit = c
7681       // val = c
7682       if (size)
7683         outBitC (result);
7684       // if(bit | ...)
7685       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7686            genIfxJump (ifx, "c");
7687       goto release;
7688     }
7689
7690   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7691   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7692   if ((AOP_TYPE (right) == AOP_LIT) &&
7693       (AOP_TYPE (result) == AOP_CRY) &&
7694       (AOP_TYPE (left) != AOP_CRY))
7695     {
7696       if (lit)
7697         {
7698           // result = 1
7699           if (size)
7700             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7701           else
7702             continueIfTrue (ifx);
7703           goto release;
7704         }
7705       else
7706         {
7707           // lit = 0, result = boolean(left)
7708           if (size)
7709             emitcode ("setb", "c");
7710           toBoolean (right);
7711           if (size)
7712             {
7713               symbol *tlbl = newiTempLabel (NULL);
7714               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7715               CLRC;
7716               emitLabel (tlbl);
7717             }
7718           else
7719             {
7720               genIfxJump (ifx, "a");
7721               goto release;
7722             }
7723         }
7724       outBitC (result);
7725       goto release;
7726     }
7727
7728   /* if left is same as result */
7729   if (sameRegs (AOP (result), AOP (left)))
7730     {
7731       for (; size--; offset++)
7732         {
7733           if (AOP_TYPE (right) == AOP_LIT)
7734             {
7735               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7736               if (bytelit == 0)
7737                 {
7738                   /* dummy read of volatile operand */
7739                   if (isOperandVolatile (left, FALSE))
7740                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7741                   else
7742                     continue;
7743                 }
7744               else if (bytelit == 0x0FF)
7745                 {
7746                   aopPut (result, "#0xFF", offset);
7747                 }
7748               else if (IS_AOP_PREG (left))
7749                 {
7750                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7751                   emitcode ("orl", "a,%s",
7752                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7753                   aopPut (result, "a", offset);
7754                 }
7755               else
7756                 {
7757                   emitcode ("orl", "%s,%s",
7758                             aopGet (left, offset, FALSE, TRUE, NULL),
7759                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7760                 }
7761             }
7762           else
7763             {
7764               if (AOP_TYPE (left) == AOP_ACC)
7765                 {
7766                   if (offset)
7767                     emitcode("mov", "a,b");
7768                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7769                 }
7770               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7771                 {
7772                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7773                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7774                   emitcode ("orl", "a,b");
7775                   aopPut (result, "a", offset);
7776                 }
7777               else if (aopGetUsesAcc (left, offset))
7778                 {
7779                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7780                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7781                   aopPut (result, "a", offset);
7782                 }
7783               else
7784                 {
7785                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7786                   if (IS_AOP_PREG (left))
7787                     {
7788                       emitcode ("orl", "a,%s",
7789                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7790                       aopPut (result, "a", offset);
7791                     }
7792                   else
7793                     {
7794                       emitcode ("orl", "%s,a",
7795                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7796                     }
7797                 }
7798             }
7799         }
7800     }
7801   else
7802     {
7803       // left & result in different registers
7804       if (AOP_TYPE (result) == AOP_CRY)
7805         {
7806           // result = bit
7807           // if(size), result in bit
7808           // if(!size && ifx), conditional oper: if(left | right)
7809           symbol *tlbl = newiTempLabel (NULL);
7810           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7811           if (size)
7812             emitcode ("setb", "c");
7813           while (sizer--)
7814             {
7815               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7816                   && AOP_TYPE(left)==AOP_ACC)
7817                 {
7818                   if (offset)
7819                     emitcode("mov", "a,b");
7820                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7821                 }
7822               else if (AOP_TYPE(left)==AOP_ACC)
7823                 {
7824                   if (!offset)
7825                     {
7826                       bool pushedB = pushB ();
7827                       emitcode("mov", "b,a");
7828                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7829                       emitcode("orl", "a,b");
7830                       popB (pushedB);
7831                     }
7832                   else
7833                     {
7834                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7835                       emitcode("orl", "a,b");
7836                     }
7837                 }
7838               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7839                 {
7840                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7841                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7842                   emitcode ("orl", "a,b");
7843                 }
7844               else if (aopGetUsesAcc (left, offset))
7845                 {
7846                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7847                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7848                 }
7849               else
7850                 {
7851                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7852                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7853               }
7854
7855               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7856               offset++;
7857             }
7858           if (size)
7859             {
7860               CLRC;
7861               emitLabel (tlbl);
7862               outBitC (result);
7863             }
7864           else if (ifx)
7865             jmpTrueOrFalse (ifx, tlbl);
7866           else
7867             emitLabel (tlbl);
7868         }
7869       else
7870         {
7871             _startLazyDPSEvaluation();
7872           for (; (size--); offset++)
7873             {
7874               // normal case
7875               // result = left | right
7876               if (AOP_TYPE (right) == AOP_LIT)
7877                 {
7878                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7879                   if (bytelit == 0)
7880                     {
7881                       aopPut (result,
7882                               aopGet (left, offset, FALSE, FALSE, NULL),
7883                               offset);
7884                       continue;
7885                     }
7886                   else if (bytelit == 0x0FF)
7887                     {
7888                       /* dummy read of volatile operand */
7889                       if (isOperandVolatile (left, FALSE))
7890                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7891                       aopPut (result, "#0xFF", offset);
7892                       continue;
7893                     }
7894                 }
7895               // faster than result <- left, orl result,right
7896               // and better if result is SFR
7897               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7898                   && AOP_TYPE(left)==AOP_ACC)
7899                 {
7900                   if (offset)
7901                     emitcode("mov", "a,b");
7902                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7903                 }
7904               else if (AOP_TYPE(left)==AOP_ACC)
7905                 {
7906                   if (!offset)
7907                     {
7908                       bool pushedB = pushB ();
7909                       emitcode("mov", "b,a");
7910                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7911                       emitcode("orl", "a,b");
7912                       popB (pushedB);
7913                     }
7914                   else
7915                     {
7916                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7917                       emitcode("orl", "a,b");
7918                     }
7919                 }
7920               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7921                 {
7922                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7923                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7924                   emitcode ("orl", "a,b");
7925                 }
7926               else if (aopGetUsesAcc (left, offset))
7927                 {
7928                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7929                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7930                 }
7931               else
7932                 {
7933                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7934                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7935                 }
7936               aopPut (result, "a", offset);
7937             }
7938             _endLazyDPSEvaluation();
7939         }
7940     }
7941
7942 release:
7943   freeAsmop (result, NULL, ic, TRUE);
7944   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7945   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7946 }
7947
7948 /*-----------------------------------------------------------------*/
7949 /* genXor - code for xclusive or                                   */
7950 /*-----------------------------------------------------------------*/
7951 static void
7952 genXor (iCode * ic, iCode * ifx)
7953 {
7954   operand *left, *right, *result;
7955   int size, offset = 0;
7956   unsigned long lit = 0L;
7957   int bytelit = 0;
7958   bool pushResult;
7959
7960   D (emitcode (";", "genXor"));
7961
7962   AOP_OP_3_NOFATAL (ic, pushResult);
7963   AOP_SET_LOCALS (ic);
7964
7965   if (pushResult)
7966   {
7967       genFarFarLogicOp(ic, "xrl");
7968       return;
7969   }
7970
7971 #ifdef DEBUG_TYPE
7972   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7973             AOP_TYPE (result),
7974             AOP_TYPE (left), AOP_TYPE (right));
7975   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7976             AOP_SIZE (result),
7977             AOP_SIZE (left), AOP_SIZE (right));
7978 #endif
7979
7980   /* if left is a literal & right is not ||
7981      if left needs acc & right does not */
7982   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7983 #ifdef LOGIC_OPS_BROKEN
7984       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7985 #endif
7986      )
7987     {
7988       operand *tmp = right;
7989       right = left;
7990       left = tmp;
7991     }
7992
7993   /* if result = right then exchange them */
7994   if (sameRegs (AOP (result), AOP (right)))
7995     {
7996       operand *tmp = right;
7997       right = left;
7998       left = tmp;
7999     }
8000
8001   /* if right is bit then exchange them */
8002   if (AOP_TYPE (right) == AOP_CRY &&
8003       AOP_TYPE (left) != AOP_CRY)
8004     {
8005       operand *tmp = right;
8006       right = left;
8007       left = tmp;
8008     }
8009   if (AOP_TYPE (right) == AOP_LIT)
8010     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8011
8012   size = AOP_SIZE (result);
8013
8014   // if(bit ^ yy)
8015   // xx = bit ^ yy;
8016   if (AOP_TYPE (left) == AOP_CRY)
8017     {
8018       if (AOP_TYPE (right) == AOP_LIT)
8019         {
8020           // c = bit & literal;
8021           if (lit >> 1)
8022             {
8023               // lit>>1  != 0 => result = 1
8024               if (AOP_TYPE (result) == AOP_CRY)
8025                 {
8026                   if (size)
8027                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8028                   else if (ifx)
8029                     continueIfTrue (ifx);
8030                   goto release;
8031                 }
8032               emitcode ("setb", "c");
8033             }
8034           else
8035             {
8036               // lit == (0 or 1)
8037               if (lit == 0)
8038                 {
8039                   // lit == 0, result = left
8040                   if (size && sameRegs (AOP (result), AOP (left)))
8041                     goto release;
8042                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8043                 }
8044               else
8045                 {
8046                   // lit == 1, result = not(left)
8047                   if (size && sameRegs (AOP (result), AOP (left)))
8048                     {
8049                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8050                       goto release;
8051                     }
8052                   else
8053                     {
8054                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8055                       emitcode ("cpl", "c");
8056                     }
8057                 }
8058             }
8059         }
8060       else
8061         {
8062           // right != literal
8063           symbol *tlbl = newiTempLabel (NULL);
8064           if (AOP_TYPE (right) == AOP_CRY)
8065             {
8066               // c = bit ^ bit;
8067               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8068             }
8069           else
8070             {
8071               int sizer = AOP_SIZE (right);
8072               // c = bit ^ val
8073               // if val>>1 != 0, result = 1
8074               emitcode ("setb", "c");
8075               while (sizer)
8076                 {
8077                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8078                   if (sizer == 1)
8079                     // test the msb of the lsb
8080                     emitcode ("anl", "a,#!constbyte",0xfe);
8081                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8082                   sizer--;
8083                 }
8084               // val = (0,1)
8085               emitcode ("rrc", "a");
8086             }
8087           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8088           emitcode ("cpl", "c");
8089           emitLabel (tlbl);
8090         }
8091       // bit = c
8092       // val = c
8093       if (size)
8094         outBitC (result);
8095       // if(bit | ...)
8096       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8097         genIfxJump (ifx, "c");
8098       goto release;
8099     }
8100
8101   /* if left is same as result */
8102   if (sameRegs (AOP (result), AOP (left)))
8103     {
8104       for (; size--; offset++)
8105         {
8106           if (AOP_TYPE (right) == AOP_LIT)
8107             {
8108               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8109               if (bytelit == 0)
8110                 {
8111                   /* dummy read of volatile operand */
8112                   if (isOperandVolatile (left, FALSE))
8113                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8114                   else
8115                     continue;
8116                 }
8117               else if (IS_AOP_PREG (left))
8118                 {
8119                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8120                   emitcode ("xrl", "a,%s",
8121                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8122                   aopPut (result, "a", offset);
8123                 }
8124               else
8125                 {
8126                   emitcode ("xrl", "%s,%s",
8127                             aopGet (left, offset, FALSE, TRUE, NULL),
8128                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8129                 }
8130             }
8131           else
8132             {
8133               if (AOP_TYPE (left) == AOP_ACC)
8134                 {
8135                   if (offset)
8136                     emitcode("mov", "a,b");
8137                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8138                 }
8139               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8140                 {
8141                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8142                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8143                   emitcode ("xrl", "a,b");
8144                   aopPut (result, "a", offset);
8145                 }
8146               else if (aopGetUsesAcc (left, offset))
8147                 {
8148                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8149                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8150                   aopPut (result, "a", offset);
8151                 }
8152               else
8153                 {
8154                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8155                   if (IS_AOP_PREG (left))
8156                     {
8157                       emitcode ("xrl", "a,%s",
8158                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8159                       aopPut (result, "a", offset);
8160                     }
8161                   else
8162                     emitcode ("xrl", "%s,a",
8163                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8164                 }
8165             }
8166         }
8167     }
8168   else
8169     {
8170       // left & result in different registers
8171       if (AOP_TYPE (result) == AOP_CRY)
8172         {
8173           // result = bit
8174           // if(size), result in bit
8175           // if(!size && ifx), conditional oper: if(left ^ right)
8176           symbol *tlbl = newiTempLabel (NULL);
8177           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8178
8179           if (size)
8180             emitcode ("setb", "c");
8181           while (sizer--)
8182             {
8183               if ((AOP_TYPE (right) == AOP_LIT) &&
8184                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8185                 {
8186                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8187                 }
8188               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8189                   && AOP_TYPE(left)==AOP_ACC)
8190                 {
8191                   if (offset)
8192                     emitcode("mov", "a,b");
8193                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8194                 }
8195               else if (AOP_TYPE(left)==AOP_ACC)
8196                 {
8197                   if (!offset)
8198                     {
8199                       bool pushedB = pushB ();
8200                       emitcode("mov", "b,a");
8201                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8202                       emitcode("xrl", "a,b");
8203                       popB (pushedB);
8204                     }
8205                   else
8206                     {
8207                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8208                       emitcode("xrl", "a,b");
8209                     }
8210                 }
8211               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8212                 {
8213                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8214                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8215                   emitcode ("xrl", "a,b");
8216                 }
8217               else if (aopGetUsesAcc (left, offset))
8218                 {
8219                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8220                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8221                 }
8222               else
8223                 {
8224                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8225                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8226                 }
8227
8228               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8229               offset++;
8230             }
8231           if (size)
8232             {
8233               CLRC;
8234               emitLabel (tlbl);
8235               outBitC (result);
8236             }
8237           else if (ifx)
8238             jmpTrueOrFalse (ifx, tlbl);
8239         }
8240       else
8241         {
8242         for (; (size--); offset++)
8243           {
8244             // normal case
8245             // result = left ^ right
8246             if (AOP_TYPE (right) == AOP_LIT)
8247               {
8248                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8249                 if (bytelit == 0)
8250                   {
8251                     aopPut (result,
8252                             aopGet (left, offset, FALSE, FALSE, NULL),
8253                             offset);
8254                     continue;
8255                   }
8256                 D (emitcode (";", "better literal XOR."));
8257                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8258                 emitcode ("xrl", "a, %s",
8259                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8260               }
8261             else
8262               {
8263                 // faster than result <- left, anl result,right
8264                 // and better if result is SFR
8265                 if (AOP_TYPE (left) == AOP_ACC)
8266                   {
8267                     emitcode ("xrl", "a,%s",
8268                               aopGet (right, offset,
8269                                       FALSE, FALSE, DP2_RESULT_REG));
8270                   }
8271                 else
8272                   {
8273                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8274                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8275                       {
8276                           emitcode("mov", "b,a");
8277                           rOp = "b";
8278                       }
8279
8280                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8281                       emitcode ("xrl", "a,%s", rOp);
8282                   }
8283               }
8284             aopPut (result, "a", offset);
8285           }
8286         }
8287     }
8288
8289 release:
8290   freeAsmop (result, NULL, ic, TRUE);
8291   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8292   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8293 }
8294
8295 /*-----------------------------------------------------------------*/
8296 /* genInline - write the inline code out                           */
8297 /*-----------------------------------------------------------------*/
8298 static void
8299 genInline (iCode * ic)
8300 {
8301   char *buffer, *bp, *bp1;
8302   bool inComment = FALSE;
8303
8304   D (emitcode (";", "genInline"));
8305
8306   _G.inLine += (!options.asmpeep);
8307
8308   buffer = bp = bp1 = Safe_strdup (IC_INLINE(ic));
8309
8310   /* emit each line as a code */
8311   while (*bp)
8312     {
8313       switch (*bp)
8314         {
8315         case ';':
8316           inComment = TRUE;
8317           ++bp;
8318           break;
8319
8320         case '\n':
8321           inComment = FALSE;
8322           *bp++ = '\0';
8323           emitcode (bp1, "");
8324           bp1 = bp;
8325           break;
8326
8327         default:
8328           /* Add \n for labels, not dirs such as c:\mydir */
8329           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8330             {
8331               ++bp;
8332               *bp = '\0';
8333               ++bp;
8334               emitcode (bp1, "");
8335               bp1 = bp;
8336             }
8337           else
8338             ++bp;
8339           break;
8340         }
8341     }
8342   if (bp1 != bp)
8343     emitcode (bp1, "");
8344
8345   Safe_free (buffer);
8346
8347   _G.inLine -= (!options.asmpeep);
8348 }
8349
8350 /*-----------------------------------------------------------------*/
8351 /* genRRC - rotate right with carry                                */
8352 /*-----------------------------------------------------------------*/
8353 static void
8354 genRRC (iCode * ic)
8355 {
8356   operand *left, *result;
8357   int     size, offset;
8358   char *l;
8359
8360   D (emitcode (";", "genRRC"));
8361
8362   /* rotate right with carry */
8363   left = IC_LEFT (ic);
8364   result = IC_RESULT (ic);
8365   aopOp (left, ic, FALSE, FALSE);
8366   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8367
8368   /* move it to the result */
8369   size = AOP_SIZE (result);
8370   offset = size - 1;
8371   CLRC;
8372
8373   _startLazyDPSEvaluation ();
8374   while (size--)
8375     {
8376       l = aopGet (left, offset, FALSE, FALSE, NULL);
8377       MOVA (l);
8378       emitcode ("rrc", "a");
8379       if (AOP_SIZE (result) > 1)
8380         aopPut (result, "a", offset--);
8381     }
8382   _endLazyDPSEvaluation ();
8383
8384   /* now we need to put the carry into the
8385      highest order byte of the result */
8386   if (AOP_SIZE (result) > 1)
8387     {
8388       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8389       MOVA (l);
8390     }
8391   emitcode ("mov", "acc.7,c");
8392   aopPut (result, "a", AOP_SIZE (result) - 1);
8393   freeAsmop (result, NULL, ic, TRUE);
8394   freeAsmop (left, NULL, ic, TRUE);
8395 }
8396
8397 /*-----------------------------------------------------------------*/
8398 /* genRLC - generate code for rotate left with carry               */
8399 /*-----------------------------------------------------------------*/
8400 static void
8401 genRLC (iCode * ic)
8402 {
8403   operand *left, *result;
8404   int size, offset;
8405   char *l;
8406
8407   D (emitcode (";", "genRLC"));
8408
8409   /* rotate right with carry */
8410   left = IC_LEFT (ic);
8411   result = IC_RESULT (ic);
8412   aopOp (left, ic, FALSE, FALSE);
8413   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8414
8415   /* move it to the result */
8416   size = AOP_SIZE (result);
8417   offset = 0;
8418   if (size--)
8419     {
8420       l = aopGet (left, offset, FALSE, FALSE, NULL);
8421       MOVA (l);
8422       emitcode ("add", "a,acc");
8423       if (AOP_SIZE (result) > 1)
8424         {
8425           aopPut (result, "a", offset++);
8426         }
8427
8428       _startLazyDPSEvaluation ();
8429       while (size--)
8430         {
8431           l = aopGet (left, offset, FALSE, FALSE, NULL);
8432           MOVA (l);
8433           emitcode ("rlc", "a");
8434           if (AOP_SIZE (result) > 1)
8435             aopPut (result, "a", offset++);
8436         }
8437       _endLazyDPSEvaluation ();
8438     }
8439   /* now we need to put the carry into the
8440      highest order byte of the result */
8441   if (AOP_SIZE (result) > 1)
8442     {
8443       l = aopGet (result, 0, FALSE, FALSE, NULL);
8444       MOVA (l);
8445     }
8446   emitcode ("mov", "acc.0,c");
8447   aopPut (result, "a", 0);
8448   freeAsmop (result, NULL, ic, TRUE);
8449   freeAsmop (left, NULL, ic, TRUE);
8450 }
8451
8452 /*-----------------------------------------------------------------*/
8453 /* genGetHbit - generates code get highest order bit               */
8454 /*-----------------------------------------------------------------*/
8455 static void
8456 genGetHbit (iCode * ic)
8457 {
8458   operand *left, *result;
8459
8460   D (emitcode (";", "genGetHbit"));
8461
8462   left = IC_LEFT (ic);
8463   result = IC_RESULT (ic);
8464   aopOp (left, ic, FALSE, FALSE);
8465   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8466
8467   /* get the highest order byte into a */
8468   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8469   if (AOP_TYPE (result) == AOP_CRY)
8470     {
8471       emitcode ("rlc", "a");
8472       outBitC (result);
8473     }
8474   else
8475     {
8476       emitcode ("rl", "a");
8477       emitcode ("anl", "a,#1");
8478       outAcc (result);
8479     }
8480
8481
8482   freeAsmop (result, NULL, ic, TRUE);
8483   freeAsmop (left, NULL, ic, TRUE);
8484 }
8485
8486 /*-----------------------------------------------------------------*/
8487 /* genSwap - generates code to swap nibbles or bytes               */
8488 /*-----------------------------------------------------------------*/
8489 static void
8490 genSwap (iCode * ic)
8491 {
8492   operand *left, *result;
8493
8494   D(emitcode (";", "genSwap"));
8495
8496   left = IC_LEFT (ic);
8497   result = IC_RESULT (ic);
8498   aopOp (left, ic, FALSE, FALSE);
8499   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8500
8501   _startLazyDPSEvaluation ();
8502   switch (AOP_SIZE (left))
8503     {
8504     case 1: /* swap nibbles in byte */
8505       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8506       emitcode ("swap", "a");
8507       aopPut (result, "a", 0);
8508       break;
8509     case 2: /* swap bytes in word */
8510       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8511         {
8512           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8513           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8514           aopPut (result, "a", 1);
8515         }
8516       else if (operandsEqu (left, result))
8517         {
8518           char * reg = "a";
8519           bool pushedB = FALSE, leftInB = FALSE;
8520
8521           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8522           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8523             {
8524               pushedB = pushB ();
8525               emitcode ("mov", "b,a");
8526               reg = "b";
8527               leftInB = TRUE;
8528             }
8529           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8530           aopPut (result, reg, 1);
8531
8532           if (leftInB)
8533             popB (pushedB);
8534         }
8535       else
8536         {
8537           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8538           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8539         }
8540       break;
8541     default:
8542       wassertl(FALSE, "unsupported SWAP operand size");
8543     }
8544   _endLazyDPSEvaluation ();
8545
8546   freeAsmop (result, NULL, ic, TRUE);
8547   freeAsmop (left, NULL, ic, TRUE);
8548 }
8549
8550 /*-----------------------------------------------------------------*/
8551 /* AccRol - rotate left accumulator by known count                 */
8552 /*-----------------------------------------------------------------*/
8553 static void
8554 AccRol (int shCount)
8555 {
8556   shCount &= 0x0007;            // shCount : 0..7
8557
8558   switch (shCount)
8559     {
8560     case 0:
8561       break;
8562     case 1:
8563       emitcode ("rl", "a");
8564       break;
8565     case 2:
8566       emitcode ("rl", "a");
8567       emitcode ("rl", "a");
8568       break;
8569     case 3:
8570       emitcode ("swap", "a");
8571       emitcode ("rr", "a");
8572       break;
8573     case 4:
8574       emitcode ("swap", "a");
8575       break;
8576     case 5:
8577       emitcode ("swap", "a");
8578       emitcode ("rl", "a");
8579       break;
8580     case 6:
8581       emitcode ("rr", "a");
8582       emitcode ("rr", "a");
8583       break;
8584     case 7:
8585       emitcode ("rr", "a");
8586       break;
8587     }
8588 }
8589
8590 /*-----------------------------------------------------------------*/
8591 /* AccLsh - left shift accumulator by known count                  */
8592 /*-----------------------------------------------------------------*/
8593 static void
8594 AccLsh (int shCount)
8595 {
8596   if (shCount != 0)
8597     {
8598       if (shCount == 1)
8599         emitcode ("add", "a,acc");
8600       else if (shCount == 2)
8601         {
8602           emitcode ("add", "a,acc");
8603           emitcode ("add", "a,acc");
8604         }
8605       else
8606         {
8607           /* rotate left accumulator */
8608           AccRol (shCount);
8609           /* and kill the lower order bits */
8610           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8611         }
8612     }
8613 }
8614
8615 /*-----------------------------------------------------------------*/
8616 /* AccRsh - right shift accumulator by known count                 */
8617 /*-----------------------------------------------------------------*/
8618 static void
8619 AccRsh (int shCount)
8620 {
8621   if (shCount != 0)
8622     {
8623       if (shCount == 1)
8624         {
8625           CLRC;
8626           emitcode ("rrc", "a");
8627         }
8628       else
8629         {
8630           /* rotate right accumulator */
8631           AccRol (8 - shCount);
8632           /* and kill the higher order bits */
8633           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8634         }
8635     }
8636 }
8637
8638 #ifdef BETTER_LITERAL_SHIFT
8639 /*-----------------------------------------------------------------*/
8640 /* AccSRsh - signed right shift accumulator by known count                 */
8641 /*-----------------------------------------------------------------*/
8642 static void
8643 AccSRsh (int shCount)
8644 {
8645   symbol *tlbl;
8646   if (shCount != 0)
8647     {
8648       if (shCount == 1)
8649         {
8650           emitcode ("mov", "c,acc.7");
8651           emitcode ("rrc", "a");
8652         }
8653       else if (shCount == 2)
8654         {
8655           emitcode ("mov", "c,acc.7");
8656           emitcode ("rrc", "a");
8657           emitcode ("mov", "c,acc.7");
8658           emitcode ("rrc", "a");
8659         }
8660       else
8661         {
8662           tlbl = newiTempLabel (NULL);
8663           /* rotate right accumulator */
8664           AccRol (8 - shCount);
8665           /* and kill the higher order bits */
8666           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8667           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8668           emitcode ("orl", "a,#!constbyte",
8669                     (unsigned char) ~SRMask[shCount]);
8670           emitLabel (tlbl);
8671         }
8672     }
8673 }
8674 #endif
8675
8676 #ifdef BETTER_LITERAL_SHIFT
8677 /*-----------------------------------------------------------------*/
8678 /* shiftR1Left2Result - shift right one byte from left to result   */
8679 /*-----------------------------------------------------------------*/
8680 static void
8681 shiftR1Left2Result (operand * left, int offl,
8682                     operand * result, int offr,
8683                     int shCount, int sign)
8684 {
8685   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8686   /* shift right accumulator */
8687   if (sign)
8688     AccSRsh (shCount);
8689   else
8690     AccRsh (shCount);
8691   aopPut (result, "a", offr);
8692 }
8693 #endif
8694
8695 #ifdef BETTER_LITERAL_SHIFT
8696 /*-----------------------------------------------------------------*/
8697 /* shiftL1Left2Result - shift left one byte from left to result    */
8698 /*-----------------------------------------------------------------*/
8699 static void
8700 shiftL1Left2Result (operand * left, int offl,
8701                     operand * result, int offr, int shCount)
8702 {
8703   char *l;
8704   l = aopGet (left, offl, FALSE, FALSE, NULL);
8705   MOVA (l);
8706   /* shift left accumulator */
8707   AccLsh (shCount);
8708   aopPut (result, "a", offr);
8709 }
8710 #endif
8711
8712 #ifdef BETTER_LITERAL_SHIFT
8713 /*-----------------------------------------------------------------*/
8714 /* movLeft2Result - move byte from left to result                  */
8715 /*-----------------------------------------------------------------*/
8716 static void
8717 movLeft2Result (operand * left, int offl,
8718                 operand * result, int offr, int sign)
8719 {
8720   char *l;
8721   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8722   {
8723       l = aopGet (left, offl, FALSE, FALSE, NULL);
8724
8725       if (*l == '@' && (IS_AOP_PREG (result)))
8726       {
8727           emitcode ("mov", "a,%s", l);
8728           aopPut (result, "a", offr);
8729       }
8730       else
8731       {
8732           if (!sign)
8733             {
8734               aopPut (result, l, offr);
8735             }
8736           else
8737             {
8738               /* MSB sign in acc.7 ! */
8739               if (getDataSize (left) == offl + 1)
8740                 {
8741                   MOVA (l);
8742                   aopPut (result, "a", offr);
8743                 }
8744             }
8745       }
8746   }
8747 }
8748 #endif
8749
8750 #ifdef BETTER_LITERAL_SHIFT
8751 /*-----------------------------------------------------------------*/
8752 /* AccAXRrl1 - right rotate a:x by 1                               */
8753 /*-----------------------------------------------------------------*/
8754 static void
8755 AccAXRrl1 (char *x)
8756 {
8757   emitcode ("mov", "c,acc.0");
8758   emitcode ("xch", "a,%s", x);
8759   emitcode ("rrc", "a");
8760   emitcode ("xch", "a,%s", x);
8761   emitcode ("rrc", "a");
8762 }
8763 #endif
8764
8765 #ifdef BETTER_LITERAL_SHIFT
8766 //REMOVE ME!!!
8767 /*-----------------------------------------------------------------*/
8768 /* AccAXLrl1 - left rotate a:x by 1                                */
8769 /*-----------------------------------------------------------------*/
8770 static void
8771 AccAXLrl1 (char *x)
8772 {
8773   emitcode ("mov", "c,acc.7");
8774   emitcode ("xch", "a,%s", x);
8775   emitcode ("rlc", "a");
8776   emitcode ("xch", "a,%s", x);
8777   emitcode ("rlc", "a");
8778 }
8779 #endif
8780
8781 #ifdef BETTER_LITERAL_SHIFT
8782 /*-----------------------------------------------------------------*/
8783 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8784 /*-----------------------------------------------------------------*/
8785 static void
8786 AccAXRsh1 (char *x)
8787 {
8788   emitcode ("rrc", "a");
8789   emitcode ("xch", "a,%s", x);
8790   emitcode ("rrc", "a");
8791   emitcode ("xch", "a,%s", x);
8792 }
8793 #endif
8794
8795 #ifdef BETTER_LITERAL_SHIFT
8796 /*-----------------------------------------------------------------*/
8797 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8798 /*-----------------------------------------------------------------*/
8799 static void
8800 AccAXLsh1 (char *x)
8801 {
8802   emitcode ("xch", "a,%s", x);
8803   emitcode ("add", "a,acc");
8804   emitcode ("xch", "a,%s", x);
8805   emitcode ("rlc", "a");
8806 }
8807 #endif
8808
8809 #ifdef BETTER_LITERAL_SHIFT
8810 /*-----------------------------------------------------------------*/
8811 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8812 /*-----------------------------------------------------------------*/
8813 static void
8814 AccAXLsh (char *x, int shCount)
8815 {
8816   switch (shCount)
8817     {
8818     case 0:
8819       break;
8820     case 1:
8821       AccAXLsh1 (x);
8822       break;
8823     case 2:
8824       AccAXLsh1 (x);
8825       AccAXLsh1 (x);
8826       break;
8827     case 3:
8828     case 4:
8829     case 5:                             // AAAAABBB:CCCCCDDD
8830
8831       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8832
8833       emitcode ("anl", "a,#!constbyte",
8834                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8835
8836       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8837
8838       AccRol (shCount);                 // DDDCCCCC:BBB00000
8839
8840       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8841
8842       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8843
8844       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8845
8846       emitcode ("anl", "a,#!constbyte",
8847                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8848
8849       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8850
8851       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8852
8853       break;
8854     case 6:                             // AAAAAABB:CCCCCCDD
8855       emitcode ("anl", "a,#!constbyte",
8856                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8857 #if 1
8858       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8859       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8860       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8861 #else
8862       emitcode ("mov", "c,acc.0");      // c = B
8863       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8864       emitcode("rrc","a");
8865       emitcode("xch","a,%s", x);
8866       emitcode("rrc","a");
8867       emitcode("mov","c,acc.0"); //<< get correct bit
8868       emitcode("xch","a,%s", x);
8869
8870       emitcode("rrc","a");
8871       emitcode("xch","a,%s", x);
8872       emitcode("rrc","a");
8873       emitcode("xch","a,%s", x);
8874 #endif
8875       break;
8876     case 7:                             // a:x <<= 7
8877
8878       emitcode ("anl", "a,#!constbyte",
8879                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8880
8881       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8882
8883       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8884
8885       break;
8886     default:
8887       break;
8888     }
8889 }
8890 #endif
8891
8892 #ifdef BETTER_LITERAL_SHIFT
8893 //REMOVE ME!!!
8894 /*-----------------------------------------------------------------*/
8895 /* AccAXRsh - right shift a:x known count (0..7)                   */
8896 /*-----------------------------------------------------------------*/
8897 static void
8898 AccAXRsh (char *x, int shCount)
8899 {
8900   switch (shCount)
8901     {
8902     case 0:
8903       break;
8904     case 1:
8905       CLRC;
8906       AccAXRsh1 (x);                    // 0->a:x
8907
8908       break;
8909     case 2:
8910       CLRC;
8911       AccAXRsh1 (x);                    // 0->a:x
8912
8913       CLRC;
8914       AccAXRsh1 (x);                    // 0->a:x
8915
8916       break;
8917     case 3:
8918     case 4:
8919     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8920
8921       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8922
8923       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8924
8925       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8926
8927       emitcode ("anl", "a,#!constbyte",
8928                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8929
8930       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8931
8932       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8933
8934       emitcode ("anl", "a,#!constbyte",
8935                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8936
8937       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8938
8939       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8940
8941       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8942
8943       break;
8944     case 6:                             // AABBBBBB:CCDDDDDD
8945
8946       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8947       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8948
8949       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8950
8951       emitcode ("anl", "a,#!constbyte",
8952                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8953
8954       break;
8955     case 7:                             // ABBBBBBB:CDDDDDDD
8956
8957       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8958
8959       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8960
8961       emitcode ("anl", "a,#!constbyte",
8962                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8963
8964       break;
8965     default:
8966       break;
8967     }
8968 }
8969 #endif
8970
8971 #ifdef BETTER_LITERAL_SHIFT
8972 /*-----------------------------------------------------------------*/
8973 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8974 /*-----------------------------------------------------------------*/
8975 static void
8976 AccAXRshS (char *x, int shCount)
8977 {
8978   symbol *tlbl;
8979   switch (shCount)
8980     {
8981     case 0:
8982       break;
8983     case 1:
8984       emitcode ("mov", "c,acc.7");
8985       AccAXRsh1 (x);                    // s->a:x
8986
8987       break;
8988     case 2:
8989       emitcode ("mov", "c,acc.7");
8990       AccAXRsh1 (x);                    // s->a:x
8991
8992       emitcode ("mov", "c,acc.7");
8993       AccAXRsh1 (x);                    // s->a:x
8994
8995       break;
8996     case 3:
8997     case 4:
8998     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8999
9000       tlbl = newiTempLabel (NULL);
9001       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9002
9003       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9004
9005       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9006
9007       emitcode ("anl", "a,#!constbyte",
9008                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9009
9010       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9011
9012       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9013
9014       emitcode ("anl", "a,#!constbyte",
9015                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9016
9017       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9018
9019       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9020
9021       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9022
9023       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9024       emitcode ("orl", "a,#!constbyte",
9025                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9026
9027       emitLabel (tlbl);
9028       break;                            // SSSSAAAA:BBBCCCCC
9029
9030     case 6:                             // AABBBBBB:CCDDDDDD
9031
9032       tlbl = newiTempLabel (NULL);
9033
9034       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9035       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9036
9037       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9038
9039       emitcode ("anl", "a,#!constbyte",
9040                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9041
9042       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9043       emitcode ("orl", "a,#!constbyte",
9044                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9045
9046       emitLabel (tlbl);
9047       break;
9048     case 7:                             // ABBBBBBB:CDDDDDDD
9049
9050       tlbl = newiTempLabel (NULL);
9051
9052       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9053
9054       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9055
9056       emitcode ("anl", "a,#!constbyte",
9057                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9058
9059       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9060       emitcode ("orl", "a,#!constbyte",
9061                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9062
9063       emitLabel (tlbl);
9064       break;
9065     default:
9066       break;
9067     }
9068 }
9069 #endif
9070
9071 #ifdef BETTER_LITERAL_SHIFT
9072 static void
9073 _loadLeftIntoAx(char    **lsb,
9074                 operand *left,
9075                 operand *result,
9076                 int     offl,
9077                 int     offr)
9078 {
9079   // Get the initial value from left into a pair of registers.
9080   // MSB must be in A, LSB can be any register.
9081   //
9082   // If the result is held in registers, it is an optimization
9083   // if the LSB can be held in the register which will hold the,
9084   // result LSB since this saves us from having to copy it into
9085   // the result following AccAXLsh.
9086   //
9087   // If the result is addressed indirectly, this is not a gain.
9088   if (AOP_NEEDSACC(result))
9089   {
9090        char *leftByte;
9091
9092        _startLazyDPSEvaluation();
9093       if (AOP_TYPE(left) == AOP_DPTR2)
9094        {
9095            // Get MSB in A.
9096            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9097            // get LSB in DP2_RESULT_REG.
9098            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9099            assert(!strcmp(leftByte, DP2_RESULT_REG));
9100        }
9101        else
9102        {
9103            // get LSB into DP2_RESULT_REG
9104            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9105            if (strcmp(leftByte, DP2_RESULT_REG))
9106            {
9107                TR_AP("#7");
9108                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9109            }
9110            // And MSB in A.
9111            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9112            assert(strcmp(leftByte, DP2_RESULT_REG));
9113            MOVA (leftByte);
9114        }
9115        _endLazyDPSEvaluation();
9116        *lsb = DP2_RESULT_REG;
9117   }
9118   else
9119   {
9120       if (sameRegs (AOP (result), AOP (left)) &&
9121         ((offl + MSB16) == offr))
9122       {
9123           /* don't crash result[offr] */
9124           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9125           emitcode ("xch", "a,%s",
9126                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9127       }
9128       else
9129       {
9130           movLeft2Result (left, offl, result, offr, 0);
9131           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9132       }
9133       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9134       assert(strcmp(*lsb,"a"));
9135   }
9136 }
9137
9138 static void
9139 _storeAxResults(char    *lsb,
9140                 operand *result,
9141                 int     offr)
9142 {
9143   _startLazyDPSEvaluation();
9144   if (AOP_NEEDSACC(result))
9145   {
9146       /* We have to explicitly update the result LSB.
9147        */
9148       emitcode ("xch","a,%s", lsb);
9149       aopPut (result, "a", offr);
9150       emitcode ("mov","a,%s", lsb);
9151   }
9152   if (getDataSize (result) > 1)
9153   {
9154       aopPut (result, "a", offr + MSB16);
9155   }
9156   _endLazyDPSEvaluation();
9157 }
9158
9159 /*-----------------------------------------------------------------*/
9160 /* shiftL2Left2Result - shift left two bytes from left to result   */
9161 /*-----------------------------------------------------------------*/
9162 static void
9163 shiftL2Left2Result (operand * left, int offl,
9164                     operand * result, int offr, int shCount)
9165 {
9166   char *lsb;
9167
9168   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9169
9170   AccAXLsh (lsb, shCount);
9171
9172   _storeAxResults(lsb, result, offr);
9173 }
9174 #endif
9175
9176 #ifdef BETTER_LITERAL_SHIFT
9177 /*-----------------------------------------------------------------*/
9178 /* shiftR2Left2Result - shift right two bytes from left to result  */
9179 /*-----------------------------------------------------------------*/
9180 static void
9181 shiftR2Left2Result (operand * left, int offl,
9182                     operand * result, int offr,
9183                     int shCount, int sign)
9184 {
9185   char *lsb;
9186
9187   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9188
9189   /* a:x >> shCount (x = lsb(result)) */
9190   if (sign)
9191   {
9192      AccAXRshS(lsb, shCount);
9193   }
9194   else
9195   {
9196     AccAXRsh(lsb, shCount);
9197   }
9198
9199   _storeAxResults(lsb, result, offr);
9200 }
9201 #endif
9202
9203 /*-----------------------------------------------------------------*/
9204 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9205 /*-----------------------------------------------------------------*/
9206 static void
9207 shiftLLeftOrResult (operand * left, int offl,
9208                     operand * result, int offr, int shCount)
9209 {
9210   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9211   /* shift left accumulator */
9212   AccLsh (shCount);
9213   /* or with result */
9214   emitcode ("orl", "a,%s",
9215             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9216   /* back to result */
9217   aopPut (result, "a", offr);
9218 }
9219
9220 #if 0
9221 //REMOVE ME!!!
9222 /*-----------------------------------------------------------------*/
9223 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9224 /*-----------------------------------------------------------------*/
9225 static void
9226 shiftRLeftOrResult (operand * left, int offl,
9227                     operand * result, int offr, int shCount)
9228 {
9229   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9230   /* shift right accumulator */
9231   AccRsh (shCount);
9232   /* or with result */
9233   emitcode ("orl", "a,%s",
9234             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9235   /* back to result */
9236   aopPut (result, "a", offr);
9237 }
9238 #endif
9239
9240 #ifdef BETTER_LITERAL_SHIFT
9241 /*-----------------------------------------------------------------*/
9242 /* genlshOne - left shift a one byte quantity by known count       */
9243 /*-----------------------------------------------------------------*/
9244 static void
9245 genlshOne (operand * result, operand * left, int shCount)
9246 {
9247   D (emitcode (";", "genlshOne"));
9248
9249   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9250 }
9251 #endif
9252
9253 #ifdef BETTER_LITERAL_SHIFT
9254 /*-----------------------------------------------------------------*/
9255 /* genlshTwo - left shift two bytes by known amount != 0           */
9256 /*-----------------------------------------------------------------*/
9257 static void
9258 genlshTwo (operand * result, operand * left, int shCount)
9259 {
9260   int size;
9261
9262   D (emitcode (";", "genlshTwo"));
9263
9264   size = getDataSize (result);
9265
9266   /* if shCount >= 8 */
9267   if (shCount >= 8)
9268   {
9269       shCount -= 8;
9270
9271       _startLazyDPSEvaluation();
9272
9273       if (size > 1)
9274         {
9275           if (shCount)
9276           {
9277             _endLazyDPSEvaluation();
9278             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9279             aopPut (result, zero, LSB);
9280           }
9281           else
9282           {
9283             movLeft2Result (left, LSB, result, MSB16, 0);
9284             aopPut (result, zero, LSB);
9285             _endLazyDPSEvaluation();
9286           }
9287         }
9288         else
9289         {
9290           aopPut (result, zero, LSB);
9291           _endLazyDPSEvaluation();
9292         }
9293   }
9294
9295   /*  1 <= shCount <= 7 */
9296   else
9297     {
9298       if (size == 1)
9299         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9300       else
9301         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9302     }
9303 }
9304 #endif
9305
9306 #if 0
9307 //REMOVE ME!!!
9308 /*-----------------------------------------------------------------*/
9309 /* shiftLLong - shift left one long from left to result            */
9310 /* offl = LSB or MSB16                                             */
9311 /*-----------------------------------------------------------------*/
9312 static void
9313 shiftLLong (operand * left, operand * result, int offr)
9314 {
9315   char *l;
9316   int size = AOP_SIZE (result);
9317
9318   if (size >= LSB + offr)
9319     {
9320       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9321       MOVA (l);
9322       emitcode ("add", "a,acc");
9323       if (sameRegs (AOP (left), AOP (result)) &&
9324           size >= MSB16 + offr && offr != LSB)
9325         emitcode ("xch", "a,%s",
9326                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9327       else
9328         aopPut (result, "a", LSB + offr);
9329     }
9330
9331   if (size >= MSB16 + offr)
9332     {
9333       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9334         {
9335           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9336           MOVA (l);
9337         }
9338       emitcode ("rlc", "a");
9339       if (sameRegs (AOP (left), AOP (result)) &&
9340           size >= MSB24 + offr && offr != LSB)
9341         emitcode ("xch", "a,%s",
9342                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9343       else
9344         aopPut (result, "a", MSB16 + offr);
9345     }
9346
9347   if (size >= MSB24 + offr)
9348     {
9349       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9350         {
9351           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9352           MOVA (l);
9353         }
9354       emitcode ("rlc", "a");
9355       if (sameRegs (AOP (left), AOP (result)) &&
9356           size >= MSB32 + offr && offr != LSB)
9357         emitcode ("xch", "a,%s",
9358                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9359       else
9360         aopPut (result, "a", MSB24 + offr);
9361     }
9362
9363   if (size > MSB32 + offr)
9364     {
9365       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9366         {
9367           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9368           MOVA (l);
9369         }
9370       emitcode ("rlc", "a");
9371       aopPut (result, "a", MSB32 + offr);
9372     }
9373   if (offr != LSB)
9374     aopPut (result, zero, LSB);
9375 }
9376 #endif
9377
9378 #if 0
9379 //REMOVE ME!!!
9380 /*-----------------------------------------------------------------*/
9381 /* genlshFour - shift four byte by a known amount != 0             */
9382 /*-----------------------------------------------------------------*/
9383 static void
9384 genlshFour (operand * result, operand * left, int shCount)
9385 {
9386   int size;
9387
9388   D (emitcode (";", "genlshFour"));
9389
9390   size = AOP_SIZE (result);
9391
9392   /* if shifting more that 3 bytes */
9393   if (shCount >= 24)
9394     {
9395       shCount -= 24;
9396       if (shCount)
9397         /* lowest order of left goes to the highest
9398            order of the destination */
9399         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9400       else
9401         movLeft2Result (left, LSB, result, MSB32, 0);
9402       aopPut (result, zero, LSB);
9403       aopPut (result, zero, MSB16);
9404       aopPut (result, zero, MSB24);
9405       return;
9406     }
9407
9408   /* more than two bytes */
9409   else if (shCount >= 16)
9410     {
9411       /* lower order two bytes goes to higher order two bytes */
9412       shCount -= 16;
9413       /* if some more remaining */
9414       if (shCount)
9415         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9416       else
9417         {
9418           movLeft2Result (left, MSB16, result, MSB32, 0);
9419           movLeft2Result (left, LSB, result, MSB24, 0);
9420         }
9421       aopPut (result, zero, MSB16);
9422       aopPut (result, zero, LSB);
9423       return;
9424     }
9425
9426   /* if more than 1 byte */
9427   else if (shCount >= 8)
9428     {
9429       /* lower order three bytes goes to higher order  three bytes */
9430       shCount -= 8;
9431       if (size == 2)
9432         {
9433           if (shCount)
9434             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9435           else
9436             movLeft2Result (left, LSB, result, MSB16, 0);
9437         }
9438       else
9439         {                       /* size = 4 */
9440           if (shCount == 0)
9441             {
9442               movLeft2Result (left, MSB24, result, MSB32, 0);
9443               movLeft2Result (left, MSB16, result, MSB24, 0);
9444               movLeft2Result (left, LSB, result, MSB16, 0);
9445               aopPut (result, zero, LSB);
9446             }
9447           else if (shCount == 1)
9448             shiftLLong (left, result, MSB16);
9449           else
9450             {
9451               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9452               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9453               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9454               aopPut (result, zero, LSB);
9455             }
9456         }
9457     }
9458
9459   /* 1 <= shCount <= 7 */
9460   else if (shCount <= 2)
9461     {
9462       shiftLLong (left, result, LSB);
9463       if (shCount == 2)
9464         shiftLLong (result, result, LSB);
9465     }
9466   /* 3 <= shCount <= 7, optimize */
9467   else
9468     {
9469       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9470       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9471       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9472     }
9473 }
9474 #endif
9475
9476 #ifdef BETTER_LITERAL_SHIFT
9477 /*-----------------------------------------------------------------*/
9478 /* genLeftShiftLiteral - left shifting by known count              */
9479 /*-----------------------------------------------------------------*/
9480 static bool
9481 genLeftShiftLiteral (operand * left,
9482                      operand * right,
9483                      operand * result,
9484                      iCode * ic)
9485 {
9486   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9487   int size;
9488
9489   size = getSize (operandType (result));
9490
9491   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9492
9493   /* We only handle certain easy cases so far. */
9494   if ((shCount != 0)
9495    && (shCount < (size * 8))
9496    && (size != 1)
9497    && (size != 2))
9498   {
9499       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9500       return FALSE;
9501   }
9502
9503   freeAsmop (right, NULL, ic, TRUE);
9504
9505   aopOp(left, ic, FALSE, FALSE);
9506   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9507
9508 #if 0 // debug spew
9509   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9510   {
9511         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9512         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9513         {
9514            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9515         }
9516   }
9517   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9518   {
9519         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9520         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9521         {
9522            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9523         }
9524   }
9525 #endif
9526
9527 #if VIEW_SIZE
9528   emitcode ("; shift left ", "result %d, left %d", size,
9529             AOP_SIZE (left));
9530 #endif
9531
9532   /* I suppose that the left size >= result size */
9533   if (shCount == 0)
9534   {
9535         _startLazyDPSEvaluation();
9536         while (size--)
9537         {
9538           movLeft2Result (left, size, result, size, 0);
9539         }
9540         _endLazyDPSEvaluation();
9541   }
9542   else if (shCount >= (size * 8))
9543   {
9544     _startLazyDPSEvaluation();
9545     while (size--)
9546     {
9547       aopPut (result, zero, size);
9548     }
9549     _endLazyDPSEvaluation();
9550   }
9551   else
9552   {
9553       switch (size)
9554         {
9555         case 1:
9556           genlshOne (result, left, shCount);
9557           break;
9558
9559         case 2:
9560           genlshTwo (result, left, shCount);
9561           break;
9562 #if 0
9563         case 4:
9564           genlshFour (result, left, shCount);
9565           break;
9566 #endif
9567         default:
9568           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9569                   "*** ack! mystery literal shift!\n");
9570           break;
9571         }
9572     }
9573   freeAsmop (result, NULL, ic, TRUE);
9574   freeAsmop (left, NULL, ic, TRUE);
9575   return TRUE;
9576 }
9577 #endif
9578
9579 /*-----------------------------------------------------------------*/
9580 /* genLeftShift - generates code for left shifting                 */
9581 /*-----------------------------------------------------------------*/
9582 static void
9583 genLeftShift (iCode * ic)
9584 {
9585   operand *left, *right, *result;
9586   int size, offset;
9587   char *l;
9588   symbol *tlbl, *tlbl1;
9589   bool pushedB;
9590
9591   D (emitcode (";", "genLeftShift"));
9592
9593   right = IC_RIGHT (ic);
9594   left = IC_LEFT (ic);
9595   result = IC_RESULT (ic);
9596
9597   aopOp (right, ic, FALSE, FALSE);
9598
9599
9600 #ifdef BETTER_LITERAL_SHIFT
9601   /* if the shift count is known then do it
9602      as efficiently as possible */
9603   if (AOP_TYPE (right) == AOP_LIT)
9604     {
9605       if (genLeftShiftLiteral (left, right, result, ic))
9606       {
9607         return;
9608       }
9609     }
9610 #endif
9611
9612   /* shift count is unknown then we have to form
9613      a loop get the loop count in B : Note: we take
9614      only the lower order byte since shifting
9615      more that 32 bits make no sense anyway, ( the
9616      largest size of an object can be only 32 bits ) */
9617
9618   pushedB = pushB ();
9619   if (AOP_TYPE (right) == AOP_LIT)
9620   {
9621       /* Really should be handled by genLeftShiftLiteral,
9622        * but since I'm too lazy to fix that today, at least we can make
9623        * some small improvement.
9624        */
9625        emitcode("mov", "b,#!constbyte",
9626                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9627   }
9628   else
9629   {
9630       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9631       emitcode ("inc", "b");
9632   }
9633   freeAsmop (right, NULL, ic, TRUE);
9634   aopOp (left, ic, FALSE, FALSE);
9635   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9636
9637   /* now move the left to the result if they are not the same */
9638   if (!sameRegs (AOP (left), AOP (result)) &&
9639       AOP_SIZE (result) > 1)
9640     {
9641
9642       size = AOP_SIZE (result);
9643       offset = 0;
9644       _startLazyDPSEvaluation ();
9645       while (size--)
9646         {
9647           l = aopGet (left, offset, FALSE, TRUE, NULL);
9648           if (*l == '@' && (IS_AOP_PREG (result)))
9649             {
9650
9651               emitcode ("mov", "a,%s", l);
9652               aopPut (result, "a", offset);
9653             }
9654           else
9655             aopPut (result, l, offset);
9656           offset++;
9657         }
9658       _endLazyDPSEvaluation ();
9659     }
9660
9661   tlbl = newiTempLabel (NULL);
9662   size = AOP_SIZE (result);
9663   offset = 0;
9664   tlbl1 = newiTempLabel (NULL);
9665
9666   /* if it is only one byte then */
9667   if (size == 1)
9668     {
9669       symbol *tlbl1 = newiTempLabel (NULL);
9670
9671       l = aopGet (left, 0, FALSE, FALSE, NULL);
9672       MOVA (l);
9673       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9674       emitLabel (tlbl);
9675       emitcode ("add", "a,acc");
9676       emitLabel (tlbl1);
9677       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9678       popB (pushedB);
9679       aopPut (result, "a", 0);
9680       goto release;
9681     }
9682
9683   reAdjustPreg (AOP (result));
9684
9685   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9686   emitLabel (tlbl);
9687   l = aopGet (result, offset, FALSE, FALSE, NULL);
9688   MOVA (l);
9689   emitcode ("add", "a,acc");
9690   aopPut (result, "a", offset++);
9691   _startLazyDPSEvaluation ();
9692   while (--size)
9693     {
9694       l = aopGet (result, offset, FALSE, FALSE, NULL);
9695       MOVA (l);
9696       emitcode ("rlc", "a");
9697       aopPut (result, "a", offset++);
9698     }
9699   _endLazyDPSEvaluation ();
9700   reAdjustPreg (AOP (result));
9701
9702   emitLabel (tlbl1);
9703   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9704   popB (pushedB);
9705 release:
9706   freeAsmop (result, NULL, ic, TRUE);
9707   freeAsmop (left, NULL, ic, TRUE);
9708 }
9709
9710 #ifdef BETTER_LITERAL_SHIFT
9711 /*-----------------------------------------------------------------*/
9712 /* genrshOne - right shift a one byte quantity by known count      */
9713 /*-----------------------------------------------------------------*/
9714 static void
9715 genrshOne (operand * result, operand * left,
9716            int shCount, int sign)
9717 {
9718   D (emitcode (";", "genrshOne"));
9719
9720   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9721 }
9722 #endif
9723
9724 #ifdef BETTER_LITERAL_SHIFT
9725 /*-----------------------------------------------------------------*/
9726 /* genrshTwo - right shift two bytes by known amount != 0          */
9727 /*-----------------------------------------------------------------*/
9728 static void
9729 genrshTwo (operand * result, operand * left,
9730            int shCount, int sign)
9731 {
9732   D (emitcode (";", "genrshTwo"));
9733
9734   /* if shCount >= 8 */
9735   if (shCount >= 8)
9736     {
9737       shCount -= 8;
9738       _startLazyDPSEvaluation();
9739       if (shCount)
9740         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9741       else
9742         movLeft2Result (left, MSB16, result, LSB, sign);
9743       addSign (result, MSB16, sign);
9744       _endLazyDPSEvaluation();
9745     }
9746
9747   /*  1 <= shCount <= 7 */
9748   else
9749     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9750 }
9751 #endif
9752
9753 /*-----------------------------------------------------------------*/
9754 /* shiftRLong - shift right one long from left to result           */
9755 /* offl = LSB or MSB16                                             */
9756 /*-----------------------------------------------------------------*/
9757 static void
9758 shiftRLong (operand * left, int offl,
9759             operand * result, int sign)
9760 {
9761   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9762
9763   if (overlapping && offl>1)
9764     {
9765       // we are in big trouble, but this shouldn't happen
9766       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9767     }
9768
9769   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9770
9771   if (offl==MSB16)
9772     {
9773       // shift is > 8
9774       if (sign)
9775         {
9776           emitcode ("rlc", "a");
9777           emitcode ("subb", "a,acc");
9778           emitcode ("xch", "a,%s",
9779                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9780         }
9781       else
9782         {
9783           aopPut (result, zero, MSB32);
9784         }
9785     }
9786
9787   if (!sign)
9788     {
9789       emitcode ("clr", "c");
9790     }
9791   else
9792     {
9793       emitcode ("mov", "c,acc.7");
9794     }
9795
9796   emitcode ("rrc", "a");
9797
9798   if (overlapping && offl==MSB16)
9799     {
9800       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9801     }
9802   else
9803     {
9804       aopPut (result, "a", MSB32 - offl);
9805       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9806     }
9807
9808   emitcode ("rrc", "a");
9809
9810   if (overlapping && offl==MSB16)
9811     {
9812       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9813     }
9814   else
9815     {
9816       aopPut (result, "a", MSB24 - offl);
9817       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9818     }
9819
9820   emitcode ("rrc", "a");
9821   if (offl != LSB)
9822     {
9823       aopPut (result, "a", MSB16 - offl);
9824     }
9825   else
9826     {
9827       if (overlapping && offl==MSB16)
9828         {
9829           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9830         }
9831       else
9832         {
9833           aopPut (result, "a", MSB16 - offl);
9834           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9835         }
9836       emitcode ("rrc", "a");
9837       aopPut (result, "a", LSB);
9838     }
9839 }
9840
9841 /*-----------------------------------------------------------------*/
9842 /* genrshFour - shift four byte by a known amount != 0             */
9843 /*-----------------------------------------------------------------*/
9844 static void
9845 genrshFour (operand * result, operand * left,
9846             int shCount, int sign)
9847 {
9848   D (emitcode (";", "genrshFour"));
9849
9850   /* if shifting more that 3 bytes */
9851   if (shCount >= 24)
9852     {
9853       shCount -= 24;
9854       _startLazyDPSEvaluation();
9855       if (shCount)
9856         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9857       else
9858         movLeft2Result (left, MSB32, result, LSB, sign);
9859       addSign (result, MSB16, sign);
9860       _endLazyDPSEvaluation();
9861     }
9862   else if (shCount >= 16)
9863     {
9864       shCount -= 16;
9865       _startLazyDPSEvaluation();
9866       if (shCount)
9867         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9868       else
9869         {
9870           movLeft2Result (left, MSB24, result, LSB, 0);
9871           movLeft2Result (left, MSB32, result, MSB16, sign);
9872         }
9873       addSign (result, MSB24, sign);
9874       _endLazyDPSEvaluation();
9875     }
9876   else if (shCount >= 8)
9877     {
9878       shCount -= 8;
9879       _startLazyDPSEvaluation();
9880       if (shCount == 1)
9881         {
9882           shiftRLong (left, MSB16, result, sign);
9883         }
9884       else if (shCount == 0)
9885         {
9886           movLeft2Result (left, MSB16, result, LSB, 0);
9887           movLeft2Result (left, MSB24, result, MSB16, 0);
9888           movLeft2Result (left, MSB32, result, MSB24, sign);
9889           addSign (result, MSB32, sign);
9890         }
9891       else
9892         {
9893           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9894           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9895           /* the last shift is signed */
9896           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9897           addSign (result, MSB32, sign);
9898         }
9899         _endLazyDPSEvaluation();
9900     }
9901   else
9902     {
9903       /* 1 <= shCount <= 7 */
9904       if (shCount <= 2)
9905         {
9906           shiftRLong (left, LSB, result, sign);
9907           if (shCount == 2)
9908             shiftRLong (result, LSB, result, sign);
9909         }
9910       else
9911         {
9912           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9913           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9914           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9915         }
9916     }
9917 }
9918
9919 #ifdef BETTER_LITERAL_SHIFT
9920 /*-----------------------------------------------------------------*/
9921 /* genRightShiftLiteral - right shifting by known count            */
9922 /*-----------------------------------------------------------------*/
9923 static bool
9924 genRightShiftLiteral (operand * left,
9925                       operand * right,
9926                       operand * result,
9927                       iCode * ic,
9928                       int sign)
9929 {
9930   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9931   int size;
9932
9933   size = getSize (operandType (result));
9934
9935   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9936
9937   /* We only handle certain easy cases so far. */
9938   if ((shCount != 0)
9939    && (shCount < (size * 8))
9940    && (size != 1)
9941    && (size != 2)
9942    && (size != 4))
9943   {
9944       D(emitcode (";", "genRightShiftLiteral wimping out"););
9945       return FALSE;
9946   }
9947
9948   freeAsmop (right, NULL, ic, TRUE);
9949
9950   aopOp (left, ic, FALSE, FALSE);
9951   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9952
9953 #if VIEW_SIZE
9954   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9955             AOP_SIZE (left));
9956 #endif
9957
9958   /* test the LEFT size !!! */
9959
9960   /* I suppose that the left size >= result size */
9961   if (shCount == 0)
9962   {
9963       size = getDataSize (result);
9964       _startLazyDPSEvaluation();
9965       while (size--)
9966         movLeft2Result (left, size, result, size, 0);
9967       _endLazyDPSEvaluation();
9968   }
9969   else if (shCount >= (size * 8))
9970     {
9971       if (sign)
9972         {
9973           /* get sign in acc.7 */
9974           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9975         }
9976       addSign (result, LSB, sign);
9977     }
9978   else
9979     {
9980       switch (size)
9981         {
9982         case 1:
9983           genrshOne (result, left, shCount, sign);
9984           break;
9985
9986         case 2:
9987           genrshTwo (result, left, shCount, sign);
9988           break;
9989 #if 1
9990         case 4:
9991           genrshFour (result, left, shCount, sign);
9992           break;
9993 #endif
9994         default:
9995           break;
9996         }
9997     }
9998   freeAsmop (result, NULL, ic, TRUE);
9999   freeAsmop (left, NULL, ic, TRUE);
10000
10001   return TRUE;
10002 }
10003 #endif
10004
10005 /*-----------------------------------------------------------------*/
10006 /* genSignedRightShift - right shift of signed number              */
10007 /*-----------------------------------------------------------------*/
10008 static void
10009 genSignedRightShift (iCode * ic)
10010 {
10011   operand *right, *left, *result;
10012   int size, offset;
10013   char *l;
10014   symbol *tlbl, *tlbl1;
10015   bool pushedB;
10016
10017   D (emitcode (";", "genSignedRightShift"));
10018
10019   /* we do it the hard way put the shift count in b
10020      and loop thru preserving the sign */
10021
10022   right = IC_RIGHT (ic);
10023   left = IC_LEFT (ic);
10024   result = IC_RESULT (ic);
10025
10026   aopOp (right, ic, FALSE, FALSE);
10027
10028 #ifdef BETTER_LITERAL_SHIFT
10029   if (AOP_TYPE (right) == AOP_LIT)
10030     {
10031       if (genRightShiftLiteral (left, right, result, ic, 1))
10032       {
10033         return;
10034       }
10035     }
10036 #endif
10037   /* shift count is unknown then we have to form
10038      a loop get the loop count in B : Note: we take
10039      only the lower order byte since shifting
10040      more that 32 bits make no sense anyway, ( the
10041      largest size of an object can be only 32 bits ) */
10042
10043   pushedB = pushB ();
10044   if (AOP_TYPE (right) == AOP_LIT)
10045   {
10046       /* Really should be handled by genRightShiftLiteral,
10047        * but since I'm too lazy to fix that today, at least we can make
10048        * some small improvement.
10049        */
10050        emitcode("mov", "b,#!constbyte",
10051                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10052   }
10053   else
10054   {
10055         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10056         emitcode ("inc", "b");
10057   }
10058   freeAsmop (right, NULL, ic, TRUE);
10059   aopOp (left, ic, FALSE, FALSE);
10060   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10061
10062   /* now move the left to the result if they are not the
10063      same */
10064   if (!sameRegs (AOP (left), AOP (result)) &&
10065       AOP_SIZE (result) > 1)
10066     {
10067
10068       size = AOP_SIZE (result);
10069       offset = 0;
10070       _startLazyDPSEvaluation ();
10071       while (size--)
10072         {
10073           l = aopGet (left, offset, FALSE, TRUE, NULL);
10074           if (*l == '@' && IS_AOP_PREG (result))
10075             {
10076
10077               emitcode ("mov", "a,%s", l);
10078               aopPut (result, "a", offset);
10079             }
10080           else
10081             aopPut (result, l, offset);
10082           offset++;
10083         }
10084       _endLazyDPSEvaluation ();
10085     }
10086
10087   /* mov the highest order bit to OVR */
10088   tlbl = newiTempLabel (NULL);
10089   tlbl1 = newiTempLabel (NULL);
10090
10091   size = AOP_SIZE (result);
10092   offset = size - 1;
10093   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10094   emitcode ("rlc", "a");
10095   emitcode ("mov", "ov,c");
10096   /* if it is only one byte then */
10097   if (size == 1)
10098     {
10099       l = aopGet (left, 0, FALSE, FALSE, NULL);
10100       MOVA (l);
10101       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10102       emitLabel (tlbl);
10103       emitcode ("mov", "c,ov");
10104       emitcode ("rrc", "a");
10105       emitLabel (tlbl1);
10106       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10107       popB (pushedB);
10108       aopPut (result, "a", 0);
10109       goto release;
10110     }
10111
10112   reAdjustPreg (AOP (result));
10113   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10114   emitLabel (tlbl);
10115   emitcode ("mov", "c,ov");
10116   _startLazyDPSEvaluation ();
10117   while (size--)
10118     {
10119       l = aopGet (result, offset, FALSE, FALSE, NULL);
10120       MOVA (l);
10121       emitcode ("rrc", "a");
10122       aopPut (result, "a", offset--);
10123     }
10124   _endLazyDPSEvaluation ();
10125   reAdjustPreg (AOP (result));
10126   emitLabel (tlbl1);
10127   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10128   popB (pushedB);
10129
10130 release:
10131   freeAsmop (result, NULL, ic, TRUE);
10132   freeAsmop (left, NULL, ic, TRUE);
10133 }
10134
10135 /*-----------------------------------------------------------------*/
10136 /* genRightShift - generate code for right shifting                */
10137 /*-----------------------------------------------------------------*/
10138 static void
10139 genRightShift (iCode * ic)
10140 {
10141   operand *right, *left, *result;
10142   sym_link *letype;
10143   int size, offset;
10144   char *l;
10145   symbol *tlbl, *tlbl1;
10146   bool pushedB;
10147
10148   D (emitcode (";", "genRightShift"));
10149
10150   /* if signed then we do it the hard way preserve the
10151      sign bit moving it inwards */
10152   letype = getSpec (operandType (IC_LEFT (ic)));
10153
10154   if (!SPEC_USIGN (letype))
10155     {
10156       genSignedRightShift (ic);
10157       return;
10158     }
10159
10160   /* signed & unsigned types are treated the same : i.e. the
10161      signed is NOT propagated inwards : quoting from the
10162      ANSI - standard : "for E1 >> E2, is equivalent to division
10163      by 2**E2 if unsigned or if it has a non-negative value,
10164      otherwise the result is implementation defined ", MY definition
10165      is that the sign does not get propagated */
10166
10167   right = IC_RIGHT (ic);
10168   left = IC_LEFT (ic);
10169   result = IC_RESULT (ic);
10170
10171   aopOp (right, ic, FALSE, FALSE);
10172
10173 #ifdef BETTER_LITERAL_SHIFT
10174   /* if the shift count is known then do it
10175      as efficiently as possible */
10176   if (AOP_TYPE (right) == AOP_LIT)
10177     {
10178       if (genRightShiftLiteral (left, right, result, ic, 0))
10179       {
10180         return;
10181       }
10182     }
10183 #endif
10184
10185   /* shift count is unknown then we have to form
10186      a loop get the loop count in B : Note: we take
10187      only the lower order byte since shifting
10188      more that 32 bits make no sense anyway, ( the
10189      largest size of an object can be only 32 bits ) */
10190
10191   pushedB = pushB ();
10192   if (AOP_TYPE (right) == AOP_LIT)
10193   {
10194       /* Really should be handled by genRightShiftLiteral,
10195        * but since I'm too lazy to fix that today, at least we can make
10196        * some small improvement.
10197        */
10198        emitcode("mov", "b,#!constbyte",
10199                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10200   }
10201   else
10202   {
10203       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10204       emitcode ("inc", "b");
10205   }
10206   freeAsmop (right, NULL, ic, TRUE);
10207   aopOp (left, ic, FALSE, FALSE);
10208   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10209
10210   /* now move the left to the result if they are not the
10211      same */
10212   if (!sameRegs (AOP (left), AOP (result)) &&
10213       AOP_SIZE (result) > 1)
10214     {
10215       size = AOP_SIZE (result);
10216       offset = 0;
10217       _startLazyDPSEvaluation ();
10218       while (size--)
10219         {
10220           l = aopGet (left, offset, FALSE, TRUE, NULL);
10221           if (*l == '@' && IS_AOP_PREG (result))
10222             {
10223
10224               emitcode ("mov", "a,%s", l);
10225               aopPut (result, "a", offset);
10226             }
10227           else
10228             aopPut (result, l, offset);
10229           offset++;
10230         }
10231       _endLazyDPSEvaluation ();
10232     }
10233
10234   tlbl = newiTempLabel (NULL);
10235   tlbl1 = newiTempLabel (NULL);
10236   size = AOP_SIZE (result);
10237   offset = size - 1;
10238
10239   /* if it is only one byte then */
10240   if (size == 1)
10241     {
10242       l = aopGet (left, 0, FALSE, FALSE, NULL);
10243       MOVA (l);
10244       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10245       emitLabel (tlbl);
10246       CLRC;
10247       emitcode ("rrc", "a");
10248       emitLabel (tlbl1);
10249       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10250       popB (pushedB);
10251       aopPut (result, "a", 0);
10252       goto release;
10253     }
10254
10255   reAdjustPreg (AOP (result));
10256   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10257   emitLabel (tlbl);
10258   CLRC;
10259   _startLazyDPSEvaluation ();
10260   while (size--)
10261     {
10262       l = aopGet (result, offset, FALSE, FALSE, NULL);
10263       MOVA (l);
10264       emitcode ("rrc", "a");
10265       aopPut (result, "a", offset--);
10266     }
10267   _endLazyDPSEvaluation ();
10268   reAdjustPreg (AOP (result));
10269
10270   emitLabel (tlbl1);
10271   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10272   popB (pushedB);
10273
10274 release:
10275   freeAsmop (result, NULL, ic, TRUE);
10276   freeAsmop (left, NULL, ic, TRUE);
10277 }
10278
10279 /*-----------------------------------------------------------------*/
10280 /* emitPtrByteGet - emits code to get a byte into A through a      */
10281 /*                  pointer register (R0, R1, or DPTR). The        */
10282 /*                  original value of A can be preserved in B.     */
10283 /*-----------------------------------------------------------------*/
10284 static void
10285 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10286 {
10287   switch (p_type)
10288     {
10289     case IPOINTER:
10290     case POINTER:
10291       if (preserveAinB)
10292         emitcode ("mov", "b,a");
10293       emitcode ("mov", "a,@%s", rname);
10294       break;
10295
10296     case PPOINTER:
10297       if (preserveAinB)
10298         emitcode ("mov", "b,a");
10299       emitcode ("movx", "a,@%s", rname);
10300       break;
10301
10302     case FPOINTER:
10303       if (preserveAinB)
10304         emitcode ("mov", "b,a");
10305       emitcode ("movx", "a,@dptr");
10306       break;
10307
10308     case CPOINTER:
10309       if (preserveAinB)
10310         emitcode ("mov", "b,a");
10311       emitcode ("clr", "a");
10312       emitcode ("movc", "a,@a+dptr");
10313       break;
10314
10315     case GPOINTER:
10316       if (preserveAinB)
10317         {
10318           emitcode ("push", "b");
10319           emitcode ("push", "acc");
10320         }
10321       emitcode ("lcall", "__gptrget");
10322       if (preserveAinB)
10323         emitcode ("pop", "b");
10324       break;
10325     }
10326 }
10327
10328 /*-----------------------------------------------------------------*/
10329 /* emitPtrByteSet - emits code to set a byte from src through a    */
10330 /*                  pointer register (R0, R1, or DPTR).            */
10331 /*-----------------------------------------------------------------*/
10332 static void
10333 emitPtrByteSet (char *rname, int p_type, char *src)
10334 {
10335   switch (p_type)
10336     {
10337     case IPOINTER:
10338     case POINTER:
10339       if (*src=='@')
10340         {
10341           MOVA (src);
10342           emitcode ("mov", "@%s,a", rname);
10343         }
10344       else
10345         emitcode ("mov", "@%s,%s", rname, src);
10346       break;
10347
10348     case PPOINTER:
10349       MOVA (src);
10350       emitcode ("movx", "@%s,a", rname);
10351       break;
10352
10353     case FPOINTER:
10354       MOVA (src);
10355       emitcode ("movx", "@dptr,a");
10356       break;
10357
10358     case GPOINTER:
10359       MOVA (src);
10360       emitcode ("lcall", "__gptrput");
10361       break;
10362     }
10363 }
10364
10365 /*-----------------------------------------------------------------*/
10366 /* genUnpackBits - generates code for unpacking bits               */
10367 /*-----------------------------------------------------------------*/
10368 static void
10369 genUnpackBits (operand * result, char *rname, int ptype)
10370 {
10371   int offset = 0;       /* result byte offset */
10372   int rsize;            /* result size */
10373   int rlen = 0;         /* remaining bitfield length */
10374   sym_link *etype;      /* bitfield type information */
10375   int blen;             /* bitfield length */
10376   int bstr;             /* bitfield starting bit within byte */
10377
10378   D(emitcode (";", "genUnpackBits"));
10379
10380   etype = getSpec (operandType (result));
10381   rsize = getSize (operandType (result));
10382   blen = SPEC_BLEN (etype);
10383   bstr = SPEC_BSTR (etype);
10384
10385   /* If the bitfield length is less than a byte */
10386   if (blen < 8)
10387     {
10388       emitPtrByteGet (rname, ptype, FALSE);
10389       AccRol (8 - bstr);
10390       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10391       if (!SPEC_USIGN (etype))
10392         {
10393           /* signed bitfield */
10394           symbol *tlbl = newiTempLabel (NULL);
10395
10396           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10397           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10398           emitLabel (tlbl);
10399         }
10400       aopPut (result, "a", offset++);
10401       goto finish;
10402     }
10403
10404   /* Bit field did not fit in a byte. Copy all
10405      but the partial byte at the end.  */
10406   for (rlen=blen;rlen>=8;rlen-=8)
10407     {
10408       emitPtrByteGet (rname, ptype, FALSE);
10409       aopPut (result, "a", offset++);
10410       if (rlen>8)
10411         emitcode ("inc", "%s", rname);
10412     }
10413
10414   /* Handle the partial byte at the end */
10415   if (rlen)
10416     {
10417       emitPtrByteGet (rname, ptype, FALSE);
10418       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10419       if (!SPEC_USIGN (etype))
10420         {
10421           /* signed bitfield */
10422           symbol *tlbl = newiTempLabel (NULL);
10423
10424           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10425           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10426           emitLabel (tlbl);
10427         }
10428       aopPut (result, "a", offset++);
10429     }
10430
10431 finish:
10432   if (offset < rsize)
10433     {
10434       char *source;
10435
10436       if (SPEC_USIGN (etype))
10437         source = zero;
10438       else
10439         {
10440           /* signed bitfield: sign extension with 0x00 or 0xff */
10441           emitcode ("rlc", "a");
10442           emitcode ("subb", "a,acc");
10443
10444           source = "a";
10445         }
10446       rsize -= offset;
10447       while (rsize--)
10448         aopPut (result, source, offset++);
10449     }
10450 }
10451
10452
10453 /*-----------------------------------------------------------------*/
10454 /* genDataPointerGet - generates code when ptr offset is known     */
10455 /*-----------------------------------------------------------------*/
10456 static void
10457 genDataPointerGet (operand * left,
10458                    operand * result,
10459                    iCode * ic)
10460 {
10461   char *l;
10462   char buffer[256];
10463   int size, offset = 0;
10464   aopOp (result, ic, TRUE, FALSE);
10465
10466   /* get the string representation of the name */
10467   l = aopGet (left, 0, FALSE, TRUE, NULL);
10468   size = AOP_SIZE (result);
10469   _startLazyDPSEvaluation ();
10470   while (size--)
10471     {
10472         if (offset)
10473         {
10474             SNPRINTF (buffer, sizeof(buffer),
10475                       "(%s + %d)", l + 1, offset);
10476         }
10477         else
10478         {
10479             SNPRINTF (buffer, sizeof(buffer),
10480                       "%s", l + 1);
10481         }
10482       aopPut (result, buffer, offset++);
10483     }
10484   _endLazyDPSEvaluation ();
10485
10486   freeAsmop (result, NULL, ic, TRUE);
10487   freeAsmop (left, NULL, ic, TRUE);
10488 }
10489
10490 /*-----------------------------------------------------------------*/
10491 /* genNearPointerGet - emitcode for near pointer fetch             */
10492 /*-----------------------------------------------------------------*/
10493 static void
10494 genNearPointerGet (operand * left,
10495                    operand * result,
10496                    iCode * ic,
10497                    iCode *pi)
10498 {
10499   asmop *aop = NULL;
10500   regs *preg;
10501   char *rname;
10502   sym_link *rtype, *retype, *letype;
10503   sym_link *ltype = operandType (left);
10504   char buffer[80];
10505
10506   rtype = operandType (result);
10507   retype = getSpec (rtype);
10508   letype = getSpec (ltype);
10509
10510   aopOp (left, ic, FALSE, FALSE);
10511
10512   /* if left is rematerialisable and
10513      result is not bitfield variable type and
10514      the left is pointer to data space i.e
10515      lower 128 bytes of space */
10516   if (AOP_TYPE (left) == AOP_IMMD &&
10517       !IS_BITFIELD (retype) &&
10518       !IS_BITFIELD (letype) &&
10519       DCL_TYPE (ltype) == POINTER)
10520     {
10521       genDataPointerGet (left, result, ic);
10522       return;
10523     }
10524
10525   /* if the value is already in a pointer register
10526      then don't need anything more */
10527   if (!AOP_INPREG (AOP (left)))
10528     {
10529       /* otherwise get a free pointer register */
10530       aop = newAsmop (0);
10531       preg = getFreePtr (ic, &aop, FALSE);
10532       emitcode ("mov", "%s,%s",
10533                 preg->name,
10534                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10535       rname = preg->name;
10536     }
10537   else
10538     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10539
10540   freeAsmop (left, NULL, ic, TRUE);
10541   aopOp (result, ic, FALSE, FALSE);
10542
10543   /* if bitfield then unpack the bits */
10544   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10545     genUnpackBits (result, rname, POINTER);
10546   else
10547     {
10548       /* we have can just get the values */
10549       int size = AOP_SIZE (result);
10550       int offset = 0;
10551
10552       while (size--)
10553         {
10554           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10555             {
10556
10557               emitcode ("mov", "a,@%s", rname);
10558               aopPut (result, "a", offset);
10559             }
10560           else
10561             {
10562               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10563               aopPut (result, buffer, offset);
10564             }
10565           offset++;
10566           if (size || pi)
10567             emitcode ("inc", "%s", rname);
10568         }
10569     }
10570
10571   /* now some housekeeping stuff */
10572   if (aop)      /* we had to allocate for this iCode */
10573     {
10574       if (pi) { /* post increment present */
10575         aopPut (left, rname, 0);
10576       }
10577       freeAsmop (NULL, aop, ic, TRUE);
10578     }
10579   else
10580     {
10581       /* we did not allocate which means left
10582          already in a pointer register, then
10583          if size > 0 && this could be used again
10584          we have to point it back to where it
10585          belongs */
10586       if (AOP_SIZE (result) > 1 &&
10587           !OP_SYMBOL (left)->remat &&
10588           (OP_SYMBOL (left)->liveTo > ic->seq ||
10589            ic->depth) &&
10590           !pi)
10591         {
10592           int size = AOP_SIZE (result) - 1;
10593           while (size--)
10594             emitcode ("dec", "%s", rname);
10595         }
10596     }
10597
10598   /* done */
10599   freeAsmop (result, NULL, ic, TRUE);
10600   if (pi) pi->generated = 1;
10601 }
10602
10603 /*-----------------------------------------------------------------*/
10604 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10605 /*-----------------------------------------------------------------*/
10606 static void
10607 genPagedPointerGet (operand * left,
10608                     operand * result,
10609                     iCode * ic,
10610                     iCode * pi)
10611 {
10612   asmop *aop = NULL;
10613   regs *preg;
10614   char *rname;
10615   sym_link *rtype, *retype, *letype;
10616
10617   rtype = operandType (result);
10618   retype = getSpec (rtype);
10619   letype = getSpec (operandType (left));
10620   aopOp (left, ic, FALSE, FALSE);
10621
10622   /* if the value is already in a pointer register
10623      then don't need anything more */
10624   if (!AOP_INPREG (AOP (left)))
10625     {
10626       /* otherwise get a free pointer register */
10627       aop = newAsmop (0);
10628       preg = getFreePtr (ic, &aop, FALSE);
10629       emitcode ("mov", "%s,%s",
10630                 preg->name,
10631                 aopGet (left, 0, FALSE, TRUE, NULL));
10632       rname = preg->name;
10633     }
10634   else
10635     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10636
10637   freeAsmop (left, NULL, ic, TRUE);
10638   aopOp (result, ic, FALSE, FALSE);
10639
10640   /* if bitfield then unpack the bits */
10641   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10642     genUnpackBits (result, rname, PPOINTER);
10643   else
10644     {
10645       /* we have can just get the values */
10646       int size = AOP_SIZE (result);
10647       int offset = 0;
10648
10649       while (size--)
10650         {
10651
10652           emitcode ("movx", "a,@%s", rname);
10653           aopPut (result, "a", offset);
10654
10655           offset++;
10656
10657           if (size || pi)
10658             emitcode ("inc", "%s", rname);
10659         }
10660     }
10661
10662   /* now some housekeeping stuff */
10663   if (aop)      /* we had to allocate for this iCode */
10664     {
10665       if (pi)
10666         aopPut (left, rname, 0);
10667       freeAsmop (NULL, aop, ic, TRUE);
10668     }
10669   else
10670     {
10671       /* we did not allocate which means left
10672          already in a pointer register, then
10673          if size > 0 && this could be used again
10674          we have to point it back to where it
10675          belongs */
10676       if (AOP_SIZE (result) > 1 &&
10677           !OP_SYMBOL (left)->remat &&
10678           (OP_SYMBOL (left)->liveTo > ic->seq ||
10679            ic->depth) &&
10680           !pi)
10681         {
10682           int size = AOP_SIZE (result) - 1;
10683           while (size--)
10684             emitcode ("dec", "%s", rname);
10685         }
10686     }
10687
10688   /* done */
10689   freeAsmop (result, NULL, ic, TRUE);
10690   if (pi) pi->generated = 1;
10691 }
10692
10693 /*-----------------------------------------------------------------*/
10694 /* genFarPointerGet - get value from far space                     */
10695 /*-----------------------------------------------------------------*/
10696 static void
10697 genFarPointerGet (operand * left,
10698                   operand * result, iCode * ic, iCode *pi)
10699 {
10700   int size, offset, dopi=1;
10701   sym_link *retype = getSpec (operandType (result));
10702   sym_link *letype = getSpec (operandType (left));
10703   D (emitcode (";", "genFarPointerGet"););
10704
10705   aopOp (left, ic, FALSE, FALSE);
10706
10707   /* if the operand is already in dptr
10708      then we do nothing else we move the value to dptr */
10709   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10710     {
10711       /* if this is rematerializable */
10712       if (AOP_TYPE (left) == AOP_IMMD)
10713         {
10714           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10715         }
10716       else
10717         {
10718           /* we need to get it byte by byte */
10719           _startLazyDPSEvaluation ();
10720           if (AOP_TYPE (left) != AOP_DPTR)
10721             {
10722               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10723               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10724               if (options.model == MODEL_FLAT24)
10725                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10726             }
10727           else
10728             {
10729               /* We need to generate a load to DPTR indirect through DPTR. */
10730               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10731               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10732               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10733               if (options.model == MODEL_FLAT24)
10734                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10735               emitcode ("pop", "dph");
10736               emitcode ("pop", "dpl");
10737               dopi =0;
10738             }
10739           _endLazyDPSEvaluation ();
10740         }
10741     }
10742   /* so dptr now contains the address */
10743   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10744
10745   /* if bit then unpack */
10746   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10747       if (AOP_INDPTRn(left)) {
10748           genSetDPTR(AOP(left)->aopu.dptr);
10749       }
10750       genUnpackBits (result, "dptr", FPOINTER);
10751       if (AOP_INDPTRn(left)) {
10752           genSetDPTR(0);
10753       }
10754   } else
10755     {
10756       size = AOP_SIZE (result);
10757       offset = 0;
10758
10759       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10760           while (size--) {
10761               genSetDPTR(AOP(left)->aopu.dptr);
10762               emitcode ("movx", "a,@dptr");
10763               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10764                   emitcode ("inc", "dptr");
10765               genSetDPTR (0);
10766               aopPut (result, "a", offset++);
10767           }
10768       } else {
10769           _startLazyDPSEvaluation ();
10770           while (size--) {
10771               if (AOP_INDPTRn(left)) {
10772                   genSetDPTR(AOP(left)->aopu.dptr);
10773               } else {
10774                   genSetDPTR (0);
10775               }
10776               _flushLazyDPS ();
10777
10778               emitcode ("movx", "a,@dptr");
10779               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10780                   emitcode ("inc", "dptr");
10781
10782               aopPut (result, "a", offset++);
10783           }
10784           _endLazyDPSEvaluation ();
10785       }
10786     }
10787   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10788       if (!AOP_INDPTRn(left)) {
10789           _startLazyDPSEvaluation ();
10790           aopPut (left, "dpl", 0);
10791           aopPut (left, "dph", 1);
10792           if (options.model == MODEL_FLAT24)
10793               aopPut (left, "dpx", 2);
10794           _endLazyDPSEvaluation ();
10795       }
10796     pi->generated = 1;
10797   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10798              AOP_SIZE(result) > 1 &&
10799              IS_SYMOP(left) &&
10800              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10801
10802       size = AOP_SIZE (result) - 1;
10803       if (AOP_INDPTRn(left)) {
10804           genSetDPTR(AOP(left)->aopu.dptr);
10805       }
10806       while (size--) emitcode ("lcall","__decdptr");
10807       if (AOP_INDPTRn(left)) {
10808           genSetDPTR(0);
10809       }
10810   }
10811
10812   freeAsmop (result, NULL, ic, TRUE);
10813   freeAsmop (left, NULL, ic, TRUE);
10814 }
10815
10816 /*-----------------------------------------------------------------*/
10817 /* genCodePointerGet - get value from code space                   */
10818 /*-----------------------------------------------------------------*/
10819 static void
10820 genCodePointerGet (operand * left,
10821                     operand * result, iCode * ic, iCode *pi)
10822 {
10823   int size, offset, dopi=1;
10824   sym_link *retype = getSpec (operandType (result));
10825
10826   aopOp (left, ic, FALSE, FALSE);
10827
10828   /* if the operand is already in dptr
10829      then we do nothing else we move the value to dptr */
10830   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10831     {
10832       /* if this is rematerializable */
10833       if (AOP_TYPE (left) == AOP_IMMD)
10834         {
10835           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10836         }
10837       else
10838         {                       /* we need to get it byte by byte */
10839           _startLazyDPSEvaluation ();
10840           if (AOP_TYPE (left) != AOP_DPTR)
10841             {
10842               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10843               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10844               if (options.model == MODEL_FLAT24)
10845                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10846             }
10847           else
10848             {
10849               /* We need to generate a load to DPTR indirect through DPTR. */
10850               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10851               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10852               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10853               if (options.model == MODEL_FLAT24)
10854                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10855               emitcode ("pop", "dph");
10856               emitcode ("pop", "dpl");
10857               dopi=0;
10858             }
10859           _endLazyDPSEvaluation ();
10860         }
10861     }
10862   /* so dptr now contains the address */
10863   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10864
10865   /* if bit then unpack */
10866   if (IS_BITFIELD (retype)) {
10867       if (AOP_INDPTRn(left)) {
10868           genSetDPTR(AOP(left)->aopu.dptr);
10869       }
10870       genUnpackBits (result, "dptr", CPOINTER);
10871       if (AOP_INDPTRn(left)) {
10872           genSetDPTR(0);
10873       }
10874   } else
10875     {
10876       size = AOP_SIZE (result);
10877       offset = 0;
10878       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10879           while (size--) {
10880               genSetDPTR(AOP(left)->aopu.dptr);
10881               emitcode ("clr", "a");
10882               emitcode ("movc", "a,@a+dptr");
10883               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10884                   emitcode ("inc", "dptr");
10885               genSetDPTR (0);
10886               aopPut (result, "a", offset++);
10887           }
10888       } else {
10889           _startLazyDPSEvaluation ();
10890           while (size--)
10891               {
10892                   if (AOP_INDPTRn(left)) {
10893                       genSetDPTR(AOP(left)->aopu.dptr);
10894                   } else {
10895                       genSetDPTR (0);
10896                   }
10897                   _flushLazyDPS ();
10898
10899                   emitcode ("clr", "a");
10900                   emitcode ("movc", "a,@a+dptr");
10901                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10902                       emitcode ("inc", "dptr");
10903                   aopPut (result, "a", offset++);
10904               }
10905           _endLazyDPSEvaluation ();
10906       }
10907     }
10908   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10909       if (!AOP_INDPTRn(left)) {
10910           _startLazyDPSEvaluation ();
10911
10912           aopPut (left, "dpl", 0);
10913           aopPut (left, "dph", 1);
10914           if (options.model == MODEL_FLAT24)
10915               aopPut (left, "dpx", 2);
10916
10917           _endLazyDPSEvaluation ();
10918       }
10919       pi->generated = 1;
10920   } else if (IS_SYMOP(left) &&
10921              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10922              AOP_SIZE(result) > 1 &&
10923              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10924
10925       size = AOP_SIZE (result) - 1;
10926       if (AOP_INDPTRn(left)) {
10927           genSetDPTR(AOP(left)->aopu.dptr);
10928       }
10929       while (size--) emitcode ("lcall","__decdptr");
10930       if (AOP_INDPTRn(left)) {
10931           genSetDPTR(0);
10932       }
10933   }
10934
10935   freeAsmop (result, NULL, ic, TRUE);
10936   freeAsmop (left, NULL, ic, TRUE);
10937 }
10938
10939 /*-----------------------------------------------------------------*/
10940 /* genGenPointerGet - get value from generic pointer space         */
10941 /*-----------------------------------------------------------------*/
10942 static void
10943 genGenPointerGet (operand * left,
10944                   operand * result, iCode * ic, iCode * pi)
10945 {
10946   int size, offset;
10947   bool pushedB;
10948   sym_link *retype = getSpec (operandType (result));
10949   sym_link *letype = getSpec (operandType (left));
10950
10951   D (emitcode (";", "genGenPointerGet"));
10952
10953   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10954
10955   pushedB = pushB ();
10956   /* if the operand is already in dptr
10957      then we do nothing else we move the value to dptr */
10958   if (AOP_TYPE (left) != AOP_STR)
10959     {
10960       /* if this is rematerializable */
10961       if (AOP_TYPE (left) == AOP_IMMD)
10962         {
10963           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10964           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10965             {
10966               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10967             }
10968           else
10969             {
10970               emitcode ("mov", "b,#%d", pointerCode (retype));
10971             }
10972         }
10973       else
10974         {                       /* we need to get it byte by byte */
10975           _startLazyDPSEvaluation ();
10976           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10977           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10978           if (options.model == MODEL_FLAT24) {
10979               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10980               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10981           } else {
10982               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10983           }
10984           _endLazyDPSEvaluation ();
10985         }
10986     }
10987
10988   /* so dptr-b now contains the address */
10989   aopOp (result, ic, FALSE, TRUE);
10990
10991   /* if bit then unpack */
10992   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10993   {
10994     genUnpackBits (result, "dptr", GPOINTER);
10995   }
10996   else
10997     {
10998         size = AOP_SIZE (result);
10999         offset = 0;
11000
11001         while (size--)
11002         {
11003             if (size)
11004             {
11005                 // Get two bytes at a time, results in _AP & A.
11006                 // dptr will be incremented ONCE by __gptrgetWord.
11007                 //
11008                 // Note: any change here must be coordinated
11009                 // with the implementation of __gptrgetWord
11010                 // in device/lib/_gptrget.c
11011                 emitcode ("lcall", "__gptrgetWord");
11012                 aopPut (result, "a", offset++);
11013                 aopPut (result, DP2_RESULT_REG, offset++);
11014                 size--;
11015             }
11016             else
11017             {
11018                 // Only one byte to get.
11019                 emitcode ("lcall", "__gptrget");
11020                 aopPut (result, "a", offset++);
11021             }
11022
11023             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11024             {
11025                 emitcode ("inc", "dptr");
11026             }
11027         }
11028     }
11029
11030   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11031     _startLazyDPSEvaluation ();
11032
11033     aopPut (left, "dpl", 0);
11034     aopPut (left, "dph", 1);
11035     if (options.model == MODEL_FLAT24) {
11036         aopPut (left, "dpx", 2);
11037         aopPut (left, "b", 3);
11038     } else  aopPut (left, "b", 2);
11039
11040     _endLazyDPSEvaluation ();
11041
11042     pi->generated = 1;
11043   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11044              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11045
11046       size = AOP_SIZE (result) - 1;
11047       while (size--) emitcode ("lcall","__decdptr");
11048   }
11049   popB (pushedB);
11050
11051   freeAsmop (result, NULL, ic, TRUE);
11052   freeAsmop (left, NULL, ic, TRUE);
11053 }
11054
11055 /*-----------------------------------------------------------------*/
11056 /* genPointerGet - generate code for pointer get                   */
11057 /*-----------------------------------------------------------------*/
11058 static void
11059 genPointerGet (iCode * ic, iCode *pi)
11060 {
11061   operand *left, *result;
11062   sym_link *type, *etype;
11063   int p_type;
11064
11065   D (emitcode (";", "genPointerGet"));
11066
11067   left = IC_LEFT (ic);
11068   result = IC_RESULT (ic);
11069
11070   /* depending on the type of pointer we need to
11071      move it to the correct pointer register */
11072   type = operandType (left);
11073   etype = getSpec (type);
11074   /* if left is of type of pointer then it is simple */
11075   if (IS_PTR (type) && !IS_FUNC (type->next))
11076     p_type = DCL_TYPE (type);
11077   else
11078     {
11079       /* we have to go by the storage class */
11080       p_type = PTR_TYPE (SPEC_OCLS (etype));
11081     }
11082
11083   /* special case when cast remat */
11084   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11085       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11086     {
11087       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11088       type = operandType (left);
11089       p_type = DCL_TYPE (type);
11090     }
11091   /* now that we have the pointer type we assign
11092      the pointer values */
11093   switch (p_type)
11094     {
11095
11096     case POINTER:
11097     case IPOINTER:
11098       genNearPointerGet (left, result, ic, pi);
11099       break;
11100
11101     case PPOINTER:
11102       genPagedPointerGet (left, result, ic, pi);
11103       break;
11104
11105     case FPOINTER:
11106       genFarPointerGet (left, result, ic, pi);
11107       break;
11108
11109     case CPOINTER:
11110       genCodePointerGet (left, result, ic, pi);
11111       break;
11112
11113     case GPOINTER:
11114       genGenPointerGet (left, result, ic, pi);
11115       break;
11116     }
11117 }
11118
11119
11120 /*-----------------------------------------------------------------*/
11121 /* genPackBits - generates code for packed bit storage             */
11122 /*-----------------------------------------------------------------*/
11123 static void
11124 genPackBits (sym_link * etype,
11125              operand * right,
11126              char *rname, int p_type)
11127 {
11128   int offset = 0;       /* source byte offset */
11129   int rlen = 0;         /* remaining bitfield length */
11130   int blen;             /* bitfield length */
11131   int bstr;             /* bitfield starting bit within byte */
11132   int litval;           /* source literal value (if AOP_LIT) */
11133   unsigned char mask;   /* bitmask within current byte */
11134
11135   D(emitcode (";", "genPackBits"));
11136
11137   blen = SPEC_BLEN (etype);
11138   bstr = SPEC_BSTR (etype);
11139
11140   /* If the bitfield length is less than a byte */
11141   if (blen < 8)
11142     {
11143       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11144               (unsigned char) (0xFF >> (8 - bstr)));
11145
11146       if (AOP_TYPE (right) == AOP_LIT)
11147         {
11148           /* Case with a bitfield length <8 and literal source
11149           */
11150           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11151           litval <<= bstr;
11152           litval &= (~mask) & 0xff;
11153           emitPtrByteGet (rname, p_type, FALSE);
11154           if ((mask|litval)!=0xff)
11155             emitcode ("anl","a,#!constbyte", mask);
11156           if (litval)
11157             emitcode ("orl","a,#!constbyte", litval);
11158         }
11159       else
11160         {
11161           if ((blen==1) && (p_type!=GPOINTER))
11162             {
11163               /* Case with a bitfield length == 1 and no generic pointer
11164               */
11165               if (AOP_TYPE (right) == AOP_CRY)
11166                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11167               else
11168                 {
11169                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11170                   emitcode ("rrc","a");
11171                 }
11172               emitPtrByteGet (rname, p_type, FALSE);
11173               emitcode ("mov","acc.%d,c",bstr);
11174             }
11175           else
11176             {
11177               bool pushedB;
11178               /* Case with a bitfield length < 8 and arbitrary source
11179               */
11180               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11181               /* shift and mask source value */
11182               AccLsh (bstr);
11183               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11184
11185               pushedB = pushB ();
11186               /* transfer A to B and get next byte */
11187               emitPtrByteGet (rname, p_type, TRUE);
11188
11189               emitcode ("anl", "a,#!constbyte", mask);
11190               emitcode ("orl", "a,b");
11191               if (p_type == GPOINTER)
11192                 emitcode ("pop", "b");
11193
11194               popB (pushedB);
11195            }
11196         }
11197
11198       emitPtrByteSet (rname, p_type, "a");
11199       return;
11200     }
11201
11202   /* Bit length is greater than 7 bits. In this case, copy  */
11203   /* all except the partial byte at the end                 */
11204   for (rlen=blen;rlen>=8;rlen-=8)
11205     {
11206       emitPtrByteSet (rname, p_type,
11207                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11208       if (rlen>8)
11209         emitcode ("inc", "%s", rname);
11210     }
11211
11212   /* If there was a partial byte at the end */
11213   if (rlen)
11214     {
11215       mask = (((unsigned char) -1 << rlen) & 0xff);
11216
11217       if (AOP_TYPE (right) == AOP_LIT)
11218         {
11219           /* Case with partial byte and literal source
11220           */
11221           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11222           litval >>= (blen-rlen);
11223           litval &= (~mask) & 0xff;
11224           emitPtrByteGet (rname, p_type, FALSE);
11225           if ((mask|litval)!=0xff)
11226             emitcode ("anl","a,#!constbyte", mask);
11227           if (litval)
11228             emitcode ("orl","a,#!constbyte", litval);
11229         }
11230       else
11231         {
11232           bool pushedB;
11233           /* Case with partial byte and arbitrary source
11234           */
11235           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11236           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11237
11238           pushedB = pushB ();
11239           /* transfer A to B and get next byte */
11240           emitPtrByteGet (rname, p_type, TRUE);
11241
11242           emitcode ("anl", "a,#!constbyte", mask);
11243           emitcode ("orl", "a,b");
11244           if (p_type == GPOINTER)
11245             emitcode ("pop", "b");
11246
11247           popB (pushedB);
11248         }
11249       emitPtrByteSet (rname, p_type, "a");
11250     }
11251 }
11252
11253
11254 /*-----------------------------------------------------------------*/
11255 /* genDataPointerSet - remat pointer to data space                 */
11256 /*-----------------------------------------------------------------*/
11257 static void
11258 genDataPointerSet (operand * right,
11259                    operand * result,
11260                    iCode * ic)
11261 {
11262   int size, offset = 0;
11263   char *l, buffer[256];
11264
11265   D (emitcode (";", "genDataPointerSet"));
11266
11267   aopOp (right, ic, FALSE, FALSE);
11268
11269   l = aopGet (result, 0, FALSE, TRUE, NULL);
11270   size = AOP_SIZE (right);
11271   while (size--)
11272     {
11273       if (offset)
11274           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11275       else
11276           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11277       emitcode ("mov", "%s,%s", buffer,
11278                 aopGet (right, offset++, FALSE, FALSE, NULL));
11279     }
11280
11281   freeAsmop (result, NULL, ic, TRUE);
11282   freeAsmop (right, NULL, ic, TRUE);
11283 }
11284
11285 /*-----------------------------------------------------------------*/
11286 /* genNearPointerSet - emitcode for near pointer put                */
11287 /*-----------------------------------------------------------------*/
11288 static void
11289 genNearPointerSet (operand * right,
11290                    operand * result,
11291                    iCode * ic,
11292                    iCode * pi)
11293 {
11294   asmop *aop = NULL;
11295   char *rname, *l;
11296   sym_link *retype, *letype;
11297   sym_link *ptype = operandType (result);
11298
11299   D (emitcode (";", "genNearPointerSet"));
11300
11301   retype = getSpec (operandType (right));
11302   letype = getSpec (ptype);
11303
11304   aopOp (result, ic, FALSE, FALSE);
11305
11306   /* if the result is rematerializable &
11307      in data space & not a bit variable */
11308   if (AOP_TYPE (result) == AOP_IMMD &&
11309       DCL_TYPE (ptype) == POINTER &&
11310       !IS_BITVAR (retype) &&
11311       !IS_BITVAR (letype))
11312     {
11313       genDataPointerSet (right, result, ic);
11314       return;
11315     }
11316
11317   /* if the value is already in a pointer register
11318      then don't need anything more */
11319   if (!AOP_INPREG (AOP (result)))
11320     {
11321       /* otherwise get a free pointer register */
11322       regs *preg;
11323
11324       aop = newAsmop (0);
11325       preg = getFreePtr (ic, &aop, FALSE);
11326       emitcode ("mov", "%s,%s",
11327                 preg->name,
11328                 aopGet (result, 0, FALSE, TRUE, NULL));
11329       rname = preg->name;
11330     }
11331   else
11332     {
11333       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11334     }
11335
11336   aopOp (right, ic, FALSE, FALSE);
11337
11338   /* if bitfield then unpack the bits */
11339   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11340     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11341   else
11342     {
11343       /* we can just get the values */
11344       int size = AOP_SIZE (right);
11345       int offset = 0;
11346
11347       while (size--)
11348         {
11349           l = aopGet (right, offset, FALSE, TRUE, NULL);
11350           if ((*l == '@') || (strcmp (l, "acc") == 0))
11351             {
11352               MOVA (l);
11353               emitcode ("mov", "@%s,a", rname);
11354             }
11355           else
11356             emitcode ("mov", "@%s,%s", rname, l);
11357           if (size || pi)
11358             emitcode ("inc", "%s", rname);
11359           offset++;
11360         }
11361     }
11362
11363   /* now some housekeeping stuff */
11364   if (aop)      /* we had to allocate for this iCode */
11365     {
11366       if (pi)
11367         aopPut (result, rname, 0);
11368       freeAsmop (NULL, aop, ic, TRUE);
11369     }
11370   else
11371     {
11372       /* we did not allocate which means left
11373          already in a pointer register, then
11374          if size > 0 && this could be used again
11375          we have to point it back to where it
11376          belongs */
11377       if (AOP_SIZE (right) > 1 &&
11378           !OP_SYMBOL (result)->remat &&
11379           (OP_SYMBOL (result)->liveTo > ic->seq ||
11380            ic->depth) &&
11381           !pi)
11382         {
11383           int size = AOP_SIZE (right) - 1;
11384           while (size--)
11385             emitcode ("dec", "%s", rname);
11386         }
11387     }
11388
11389   /* done */
11390   if (pi) pi->generated = 1;
11391   freeAsmop (result, NULL, ic, TRUE);
11392   freeAsmop (right, NULL, ic, TRUE);
11393 }
11394
11395 /*-----------------------------------------------------------------*/
11396 /* genPagedPointerSet - emitcode for Paged pointer put             */
11397 /*-----------------------------------------------------------------*/
11398 static void
11399 genPagedPointerSet (operand * right,
11400                     operand * result,
11401                     iCode * ic,
11402                     iCode *pi)
11403 {
11404   asmop *aop = NULL;
11405   char *rname, *l;
11406   sym_link *retype, *letype;
11407
11408   D (emitcode (";", "genPagedPointerSet"));
11409
11410   retype = getSpec (operandType (right));
11411   letype = getSpec (operandType (result));
11412
11413   aopOp (result, ic, FALSE, FALSE);
11414
11415   /* if the value is already in a pointer register
11416      then don't need anything more */
11417   if (!AOP_INPREG (AOP (result)))
11418     {
11419       /* otherwise get a free pointer register */
11420       regs *preg;
11421
11422       aop = newAsmop (0);
11423       preg = getFreePtr (ic, &aop, FALSE);
11424       emitcode ("mov", "%s,%s",
11425                 preg->name,
11426                 aopGet (result, 0, FALSE, TRUE, NULL));
11427       rname = preg->name;
11428     }
11429   else
11430     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11431
11432   aopOp (right, ic, FALSE, FALSE);
11433
11434   /* if bitfield then unpack the bits */
11435   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11436     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11437   else
11438     {
11439       /* we have can just get the values */
11440       int size = AOP_SIZE (right);
11441       int offset = 0;
11442
11443       while (size--)
11444         {
11445           l = aopGet (right, offset, FALSE, TRUE, NULL);
11446           MOVA (l);
11447           emitcode ("movx", "@%s,a", rname);
11448
11449           if (size || pi)
11450             emitcode ("inc", "%s", rname);
11451
11452           offset++;
11453         }
11454     }
11455
11456   /* now some housekeeping stuff */
11457   if (aop)
11458     {
11459       if (pi)
11460         aopPut (result, rname, 0);
11461       /* we had to allocate for this iCode */
11462       freeAsmop (NULL, aop, ic, TRUE);
11463     }
11464   else
11465     {
11466       /* we did not allocate which means left
11467          already in a pointer register, then
11468          if size > 0 && this could be used again
11469          we have to point it back to where it
11470          belongs */
11471       if (AOP_SIZE (right) > 1 &&
11472           !OP_SYMBOL (result)->remat &&
11473           (OP_SYMBOL (result)->liveTo > ic->seq ||
11474            ic->depth) &&
11475           !pi)
11476         {
11477           int size = AOP_SIZE (right) - 1;
11478           while (size--)
11479             emitcode ("dec", "%s", rname);
11480         }
11481     }
11482
11483   /* done */
11484   if (pi) pi->generated = 1;
11485   freeAsmop (result, NULL, ic, TRUE);
11486   freeAsmop (right, NULL, ic, TRUE);
11487 }
11488
11489 /*-----------------------------------------------------------------*/
11490 /* genFarPointerSet - set value from far space                     */
11491 /*-----------------------------------------------------------------*/
11492 static void
11493 genFarPointerSet (operand * right,
11494                   operand * result, iCode * ic, iCode *pi)
11495 {
11496   int size, offset, dopi=1;
11497   sym_link *retype = getSpec (operandType (right));
11498   sym_link *letype = getSpec (operandType (result));
11499
11500   aopOp (result, ic, FALSE, FALSE);
11501
11502   /* if the operand is already in dptr
11503      then we do nothing else we move the value to dptr */
11504   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11505     {
11506       /* if this is remateriazable */
11507       if (AOP_TYPE (result) == AOP_IMMD)
11508         emitcode ("mov", "dptr,%s",
11509                   aopGet (result, 0, TRUE, FALSE, NULL));
11510       else
11511         {
11512           /* we need to get it byte by byte */
11513           _startLazyDPSEvaluation ();
11514           if (AOP_TYPE (result) != AOP_DPTR)
11515             {
11516               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11517               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11518               if (options.model == MODEL_FLAT24)
11519                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11520             }
11521           else
11522             {
11523               /* We need to generate a load to DPTR indirect through DPTR. */
11524               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11525
11526               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11527               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11528               if (options.model == MODEL_FLAT24)
11529                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11530               emitcode ("pop", "dph");
11531               emitcode ("pop", "dpl");
11532               dopi=0;
11533             }
11534           _endLazyDPSEvaluation ();
11535         }
11536     }
11537   /* so dptr now contains the address */
11538   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11539
11540   /* if bit then unpack */
11541   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11542   {
11543       if (AOP_INDPTRn(result)) {
11544           genSetDPTR(AOP(result)->aopu.dptr);
11545       }
11546       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11547       if (AOP_INDPTRn(result)) {
11548           genSetDPTR(0);
11549       }
11550   } else {
11551       size = AOP_SIZE (right);
11552       offset = 0;
11553       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11554           while (size--) {
11555               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11556
11557               genSetDPTR(AOP(result)->aopu.dptr);
11558               emitcode ("movx", "@dptr,a");
11559               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11560                   emitcode ("inc", "dptr");
11561               genSetDPTR (0);
11562           }
11563       } else {
11564           _startLazyDPSEvaluation ();
11565           while (size--) {
11566               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11567
11568               if (AOP_INDPTRn(result)) {
11569                   genSetDPTR(AOP(result)->aopu.dptr);
11570               } else {
11571                   genSetDPTR (0);
11572               }
11573               _flushLazyDPS ();
11574
11575               emitcode ("movx", "@dptr,a");
11576               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11577                   emitcode ("inc", "dptr");
11578           }
11579           _endLazyDPSEvaluation ();
11580       }
11581   }
11582
11583   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11584       if (!AOP_INDPTRn(result)) {
11585           _startLazyDPSEvaluation ();
11586
11587           aopPut (result,"dpl",0);
11588           aopPut (result,"dph",1);
11589           if (options.model == MODEL_FLAT24)
11590               aopPut (result,"dpx",2);
11591
11592           _endLazyDPSEvaluation ();
11593       }
11594       pi->generated=1;
11595   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11596              AOP_SIZE(right) > 1 &&
11597              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11598
11599       size = AOP_SIZE (right) - 1;
11600       if (AOP_INDPTRn(result)) {
11601           genSetDPTR(AOP(result)->aopu.dptr);
11602       }
11603       while (size--) emitcode ("lcall","__decdptr");
11604       if (AOP_INDPTRn(result)) {
11605           genSetDPTR(0);
11606       }
11607   }
11608   freeAsmop (result, NULL, ic, TRUE);
11609   freeAsmop (right, NULL, ic, TRUE);
11610 }
11611
11612 /*-----------------------------------------------------------------*/
11613 /* genGenPointerSet - set value from generic pointer space         */
11614 /*-----------------------------------------------------------------*/
11615 static void
11616 genGenPointerSet (operand * right,
11617                   operand * result, iCode * ic, iCode *pi)
11618 {
11619   int size, offset;
11620   bool pushedB;
11621   sym_link *retype = getSpec (operandType (right));
11622   sym_link *letype = getSpec (operandType (result));
11623
11624   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11625
11626   pushedB = pushB ();
11627   /* if the operand is already in dptr
11628      then we do nothing else we move the value to dptr */
11629   if (AOP_TYPE (result) != AOP_STR)
11630     {
11631       _startLazyDPSEvaluation ();
11632       /* if this is remateriazable */
11633       if (AOP_TYPE (result) == AOP_IMMD)
11634         {
11635           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11636           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11637           {
11638               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11639           }
11640           else
11641           {
11642               emitcode ("mov",
11643                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11644           }
11645         }
11646       else
11647         {                       /* we need to get it byte by byte */
11648           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11649           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11650           if (options.model == MODEL_FLAT24) {
11651             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11652             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11653           } else {
11654             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11655           }
11656         }
11657       _endLazyDPSEvaluation ();
11658     }
11659   /* so dptr + b now contains the address */
11660   aopOp (right, ic, FALSE, TRUE);
11661
11662   /* if bit then unpack */
11663   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11664     {
11665         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11666     }
11667   else
11668     {
11669         size = AOP_SIZE (right);
11670         offset = 0;
11671
11672         _startLazyDPSEvaluation ();
11673         while (size--)
11674         {
11675             if (size)
11676             {
11677                 // Set two bytes at a time, passed in _AP & A.
11678                 // dptr will be incremented ONCE by __gptrputWord.
11679                 //
11680                 // Note: any change here must be coordinated
11681                 // with the implementation of __gptrputWord
11682                 // in device/lib/_gptrput.c
11683                 emitcode("mov", "_ap, %s",
11684                          aopGet (right, offset++, FALSE, FALSE, NULL));
11685                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11686
11687                 genSetDPTR (0);
11688                 _flushLazyDPS ();
11689                 emitcode ("lcall", "__gptrputWord");
11690                 size--;
11691             }
11692             else
11693             {
11694                 // Only one byte to put.
11695                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11696
11697                 genSetDPTR (0);
11698                 _flushLazyDPS ();
11699                 emitcode ("lcall", "__gptrput");
11700             }
11701
11702             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11703             {
11704                 emitcode ("inc", "dptr");
11705             }
11706         }
11707         _endLazyDPSEvaluation ();
11708     }
11709
11710   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11711       _startLazyDPSEvaluation ();
11712
11713       aopPut (result, "dpl",0);
11714       aopPut (result, "dph",1);
11715       if (options.model == MODEL_FLAT24) {
11716           aopPut (result, "dpx",2);
11717           aopPut (result, "b",3);
11718       } else {
11719           aopPut (result, "b",2);
11720       }
11721       _endLazyDPSEvaluation ();
11722
11723       pi->generated=1;
11724   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11725              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11726
11727       size = AOP_SIZE (right) - 1;
11728       while (size--) emitcode ("lcall","__decdptr");
11729   }
11730   popB (pushedB);
11731
11732   freeAsmop (result, NULL, ic, TRUE);
11733   freeAsmop (right, NULL, ic, TRUE);
11734 }
11735
11736 /*-----------------------------------------------------------------*/
11737 /* genPointerSet - stores the value into a pointer location        */
11738 /*-----------------------------------------------------------------*/
11739 static void
11740 genPointerSet (iCode * ic, iCode *pi)
11741 {
11742   operand *right, *result;
11743   sym_link *type, *etype;
11744   int p_type;
11745
11746   D (emitcode (";", "genPointerSet"));
11747
11748   right = IC_RIGHT (ic);
11749   result = IC_RESULT (ic);
11750
11751   /* depending on the type of pointer we need to
11752      move it to the correct pointer register */
11753   type = operandType (result);
11754   etype = getSpec (type);
11755   /* if left is of type of pointer then it is simple */
11756   if (IS_PTR (type) && !IS_FUNC (type->next))
11757     {
11758       p_type = DCL_TYPE (type);
11759     }
11760   else
11761     {
11762       /* we have to go by the storage class */
11763       p_type = PTR_TYPE (SPEC_OCLS (etype));
11764     }
11765
11766   /* special case when cast remat */
11767   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11768       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11769           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11770           type = operandType (result);
11771           p_type = DCL_TYPE (type);
11772   }
11773
11774   /* now that we have the pointer type we assign
11775      the pointer values */
11776   switch (p_type)
11777     {
11778
11779     case POINTER:
11780     case IPOINTER:
11781       genNearPointerSet (right, result, ic, pi);
11782       break;
11783
11784     case PPOINTER:
11785       genPagedPointerSet (right, result, ic, pi);
11786       break;
11787
11788     case FPOINTER:
11789       genFarPointerSet (right, result, ic, pi);
11790       break;
11791
11792     case GPOINTER:
11793       genGenPointerSet (right, result, ic, pi);
11794       break;
11795
11796     default:
11797       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11798               "genPointerSet: illegal pointer type");
11799     }
11800 }
11801
11802 /*-----------------------------------------------------------------*/
11803 /* genIfx - generate code for Ifx statement                        */
11804 /*-----------------------------------------------------------------*/
11805 static void
11806 genIfx (iCode * ic, iCode * popIc)
11807 {
11808   operand *cond = IC_COND (ic);
11809   int isbit = 0;
11810   char *dup = NULL;
11811
11812   D (emitcode (";", "genIfx"));
11813
11814   aopOp (cond, ic, FALSE, FALSE);
11815
11816   /* get the value into acc */
11817   if (AOP_TYPE (cond) != AOP_CRY)
11818     {
11819       toBoolean (cond);
11820     }
11821   else
11822     {
11823       isbit = 1;
11824       if (AOP(cond)->aopu.aop_dir)
11825         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11826     }
11827
11828   /* the result is now in the accumulator or a directly addressable bit */
11829   freeAsmop (cond, NULL, ic, TRUE);
11830
11831   /* if there was something to be popped then do it */
11832   if (popIc)
11833     genIpop (popIc);
11834
11835   /* if the condition is a bit variable */
11836   if (isbit && dup)
11837     genIfxJump (ic, dup);
11838   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11839     genIfxJump (ic, SPIL_LOC (cond)->rname);
11840   else if (isbit && !IS_ITEMP (cond))
11841     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11842   else
11843     genIfxJump (ic, "a");
11844
11845   ic->generated = 1;
11846 }
11847
11848 /*-----------------------------------------------------------------*/
11849 /* genAddrOf - generates code for address of                       */
11850 /*-----------------------------------------------------------------*/
11851 static void
11852 genAddrOf (iCode * ic)
11853 {
11854   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11855   int size, offset;
11856
11857   D (emitcode (";", "genAddrOf"));
11858
11859   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11860
11861   /* if the operand is on the stack then we
11862      need to get the stack offset of this
11863      variable */
11864   if (sym->onStack)
11865   {
11866
11867       /* if 10 bit stack */
11868       if (options.stack10bit) {
11869           char buff[10];
11870           int  offset;
11871
11872           tsprintf(buff, sizeof(buff),
11873                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11874           /* if it has an offset then we need to compute it */
11875 /*        emitcode ("subb", "a,#!constbyte", */
11876 /*                  -((sym->stack < 0) ? */
11877 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11878 /*                    ((short) sym->stack)) & 0xff); */
11879 /*        emitcode ("mov","b,a"); */
11880 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11881 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11882 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11883           if (sym->stack) {
11884               emitcode ("mov", "a,_bpx");
11885               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11886                                              ((char) (sym->stack - _G.nRegsSaved)) :
11887                                              ((char) sym->stack )) & 0xff);
11888               emitcode ("mov", "b,a");
11889               emitcode ("mov", "a,_bpx+1");
11890
11891               offset = (((sym->stack < 0) ?
11892                          ((short) (sym->stack - _G.nRegsSaved)) :
11893                          ((short) sym->stack )) >> 8) & 0xff;
11894
11895               emitcode ("addc","a,#!constbyte", offset);
11896
11897               aopPut (IC_RESULT (ic), "b", 0);
11898               aopPut (IC_RESULT (ic), "a", 1);
11899               aopPut (IC_RESULT (ic), buff, 2);
11900           } else {
11901               /* we can just move _bp */
11902               aopPut (IC_RESULT (ic), "_bpx", 0);
11903               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11904               aopPut (IC_RESULT (ic), buff, 2);
11905           }
11906       } else {
11907           /* if it has an offset then we need to compute it */
11908           if (sym->stack)
11909             {
11910               emitcode ("mov", "a,_bp");
11911               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11912               aopPut (IC_RESULT (ic), "a", 0);
11913             }
11914           else
11915             {
11916               /* we can just move _bp */
11917               aopPut (IC_RESULT (ic), "_bp", 0);
11918             }
11919           /* fill the result with zero */
11920           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11921
11922
11923           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11924               fprintf (stderr,
11925                        "*** warning: pointer to stack var truncated.\n");
11926           }
11927
11928           offset = 1;
11929           while (size--)
11930             {
11931               aopPut (IC_RESULT (ic), zero, offset++);
11932             }
11933       }
11934       goto release;
11935   }
11936
11937   /* object not on stack then we need the name */
11938   size = AOP_SIZE (IC_RESULT (ic));
11939   offset = 0;
11940
11941   while (size--)
11942     {
11943       char s[SDCC_NAME_MAX];
11944       if (offset) {
11945           switch (offset) {
11946           case 1:
11947               tsprintf(s, sizeof(s), "#!his",sym->rname);
11948               break;
11949           case 2:
11950               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11951               break;
11952           case 3:
11953               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11954               break;
11955           default: /* should not need this (just in case) */
11956               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11957                        sym->rname,
11958                        offset * 8);
11959           }
11960       }
11961       else
11962       {
11963           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11964       }
11965
11966       aopPut (IC_RESULT (ic), s, offset++);
11967     }
11968
11969 release:
11970   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11971
11972 }
11973
11974 #if 0 // obsolete, and buggy for != xdata
11975 /*-----------------------------------------------------------------*/
11976 /* genArrayInit - generates code for address of                       */
11977 /*-----------------------------------------------------------------*/
11978 static void
11979 genArrayInit (iCode * ic)
11980 {
11981     literalList *iLoop;
11982     int         ix, count;
11983     int         elementSize = 0, eIndex;
11984     unsigned    val, lastVal;
11985     sym_link    *type;
11986     operand     *left=IC_LEFT(ic);
11987
11988     D (emitcode (";", "genArrayInit"));
11989
11990     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11991
11992     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11993     {
11994         // Load immediate value into DPTR.
11995         emitcode("mov", "dptr, %s",
11996              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11997     }
11998     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11999     {
12000 #if 0
12001       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12002               "Unexpected operand to genArrayInit.\n");
12003       exit(1);
12004 #else
12005       // a regression because of SDCCcse.c:1.52
12006       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12007       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12008       if (options.model == MODEL_FLAT24)
12009         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12010 #endif
12011     }
12012
12013     type = operandType(IC_LEFT(ic));
12014
12015     if (type && type->next)
12016     {
12017         elementSize = getSize(type->next);
12018     }
12019     else
12020     {
12021         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12022                                 "can't determine element size in genArrayInit.\n");
12023         exit(1);
12024     }
12025
12026     iLoop = IC_ARRAYILIST(ic);
12027     lastVal = 0xffff;
12028
12029     while (iLoop)
12030     {
12031         bool firstpass = TRUE;
12032
12033         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12034                  iLoop->count, (int)iLoop->literalValue, elementSize);
12035
12036         ix = iLoop->count;
12037
12038         while (ix)
12039         {
12040             symbol *tlbl = NULL;
12041
12042             count = ix > 256 ? 256 : ix;
12043
12044             if (count > 1)
12045             {
12046                 tlbl = newiTempLabel (NULL);
12047                 if (firstpass || (count & 0xff))
12048                 {
12049                     emitcode("mov", "b, #!constbyte", count & 0xff);
12050                 }
12051
12052                 emitLabel (tlbl);
12053             }
12054
12055             firstpass = FALSE;
12056
12057             for (eIndex = 0; eIndex < elementSize; eIndex++)
12058             {
12059                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12060                 if (val != lastVal)
12061                 {
12062                     emitcode("mov", "a, #!constbyte", val);
12063                     lastVal = val;
12064                 }
12065
12066                 emitcode("movx", "@dptr, a");
12067                 emitcode("inc", "dptr");
12068             }
12069
12070             if (count > 1)
12071             {
12072                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12073             }
12074
12075             ix -= count;
12076         }
12077
12078         iLoop = iLoop->next;
12079     }
12080
12081     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12082 }
12083 #endif
12084
12085 /*-----------------------------------------------------------------*/
12086 /* genFarFarAssign - assignment when both are in far space         */
12087 /*-----------------------------------------------------------------*/
12088 static void
12089 genFarFarAssign (operand * result, operand * right, iCode * ic)
12090 {
12091   int size = AOP_SIZE (right);
12092   int offset = 0;
12093   symbol *rSym = NULL;
12094
12095   if (size == 1)
12096   {
12097       /* quick & easy case. */
12098       D (emitcode(";","genFarFarAssign (1 byte case)"));
12099       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12100       freeAsmop (right, NULL, ic, FALSE);
12101       /* now assign DPTR to result */
12102       _G.accInUse++;
12103       aopOp(result, ic, FALSE, FALSE);
12104       _G.accInUse--;
12105       aopPut (result, "a", 0);
12106       freeAsmop(result, NULL, ic, FALSE);
12107       return;
12108   }
12109
12110   /* See if we've got an underlying symbol to abuse. */
12111   if (IS_SYMOP(result) && OP_SYMBOL(result))
12112   {
12113       if (IS_TRUE_SYMOP(result))
12114       {
12115           rSym = OP_SYMBOL(result);
12116       }
12117       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12118       {
12119           rSym = OP_SYMBOL(result)->usl.spillLoc;
12120       }
12121   }
12122
12123   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12124   {
12125       /* We can use the '390 auto-toggle feature to good effect here. */
12126
12127       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12128       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12129       emitcode ("mov", "dptr,#%s", rSym->rname);
12130       /* DP2 = result, DP1 = right, DP1 is current. */
12131       while (size)
12132       {
12133           emitcode("movx", "a,@dptr");
12134           emitcode("movx", "@dptr,a");
12135           if (--size)
12136           {
12137                emitcode("inc", "dptr");
12138                emitcode("inc", "dptr");
12139           }
12140       }
12141       emitcode("mov", "dps,#0");
12142       freeAsmop (right, NULL, ic, FALSE);
12143 #if 0
12144 some alternative code for processors without auto-toggle
12145 no time to test now, so later well put in...kpb
12146         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12147         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12148         emitcode ("mov", "dptr,#%s", rSym->rname);
12149         /* DP2 = result, DP1 = right, DP1 is current. */
12150         while (size)
12151         {
12152           --size;
12153           emitcode("movx", "a,@dptr");
12154           if (size)
12155             emitcode("inc", "dptr");
12156           emitcode("inc", "dps");
12157           emitcode("movx", "@dptr,a");
12158           if (size)
12159             emitcode("inc", "dptr");
12160           emitcode("inc", "dps");
12161         }
12162         emitcode("mov", "dps,#0");
12163         freeAsmop (right, NULL, ic, FALSE);
12164 #endif
12165   }
12166   else
12167   {
12168       D (emitcode (";", "genFarFarAssign"));
12169       aopOp (result, ic, TRUE, TRUE);
12170
12171       _startLazyDPSEvaluation ();
12172
12173       while (size--)
12174         {
12175           aopPut (result,
12176                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12177           offset++;
12178         }
12179       _endLazyDPSEvaluation ();
12180       freeAsmop (result, NULL, ic, FALSE);
12181       freeAsmop (right, NULL, ic, FALSE);
12182   }
12183 }
12184
12185 /*-----------------------------------------------------------------*/
12186 /* genAssign - generate code for assignment                        */
12187 /*-----------------------------------------------------------------*/
12188 static void
12189 genAssign (iCode * ic)
12190 {
12191   operand *result, *right;
12192   int size, offset;
12193   unsigned long lit = 0L;
12194
12195   D (emitcode (";", "genAssign"));
12196
12197   result = IC_RESULT (ic);
12198   right = IC_RIGHT (ic);
12199
12200   /* if they are the same */
12201   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12202     return;
12203
12204   aopOp (right, ic, FALSE, FALSE);
12205
12206   emitcode (";", "genAssign: resultIsFar = %s",
12207             isOperandInFarSpace (result) ?
12208             "TRUE" : "FALSE");
12209
12210   /* special case both in far space */
12211   if ((AOP_TYPE (right) == AOP_DPTR ||
12212        AOP_TYPE (right) == AOP_DPTR2) &&
12213   /* IS_TRUE_SYMOP(result)       && */
12214       isOperandInFarSpace (result))
12215     {
12216       genFarFarAssign (result, right, ic);
12217       return;
12218     }
12219
12220   aopOp (result, ic, TRUE, FALSE);
12221
12222   /* if they are the same registers */
12223   if (sameRegs (AOP (right), AOP (result)))
12224     goto release;
12225
12226   /* if the result is a bit */
12227   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12228     {
12229       /* if the right size is a literal then
12230          we know what the value is */
12231       if (AOP_TYPE (right) == AOP_LIT)
12232         {
12233           if (((int) operandLitValue (right)))
12234             aopPut (result, one, 0);
12235           else
12236             aopPut (result, zero, 0);
12237           goto release;
12238         }
12239
12240       /* the right is also a bit variable */
12241       if (AOP_TYPE (right) == AOP_CRY)
12242         {
12243           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12244           aopPut (result, "c", 0);
12245           goto release;
12246         }
12247
12248       /* we need to or */
12249       toBoolean (right);
12250       aopPut (result, "a", 0);
12251       goto release;
12252     }
12253
12254   /* bit variables done */
12255   /* general case */
12256   size = AOP_SIZE (result);
12257   offset = 0;
12258   if (AOP_TYPE (right) == AOP_LIT)
12259     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12260
12261   if ((size > 1) &&
12262       (AOP_TYPE (result) != AOP_REG) &&
12263       (AOP_TYPE (right) == AOP_LIT) &&
12264       !IS_FLOAT (operandType (right)))
12265     {
12266       _startLazyDPSEvaluation ();
12267       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12268         {
12269           aopPut (result,
12270                   aopGet (right, offset, FALSE, FALSE, NULL),
12271                   offset);
12272           offset++;
12273           size--;
12274         }
12275       /* And now fill the rest with zeros. */
12276       if (size)
12277         {
12278           emitcode ("clr", "a");
12279         }
12280       while (size--)
12281         {
12282           aopPut (result, "a", offset++);
12283         }
12284       _endLazyDPSEvaluation ();
12285     }
12286   else
12287     {
12288       _startLazyDPSEvaluation ();
12289       while (size--)
12290         {
12291           aopPut (result,
12292                   aopGet (right, offset, FALSE, FALSE, NULL),
12293                   offset);
12294           offset++;
12295         }
12296       _endLazyDPSEvaluation ();
12297     }
12298
12299 release:
12300   freeAsmop (result, NULL, ic, TRUE);
12301   freeAsmop (right, NULL, ic, TRUE);
12302 }
12303
12304 /*-----------------------------------------------------------------*/
12305 /* genJumpTab - generates code for jump table                      */
12306 /*-----------------------------------------------------------------*/
12307 static void
12308 genJumpTab (iCode * ic)
12309 {
12310   symbol *jtab;
12311   char *l;
12312
12313   D (emitcode (";", "genJumpTab"));
12314
12315   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12316   /* get the condition into accumulator */
12317   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12318   MOVA (l);
12319   /* multiply by four! */
12320   emitcode ("add", "a,acc");
12321   emitcode ("add", "a,acc");
12322   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12323
12324   jtab = newiTempLabel (NULL);
12325   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12326   emitcode ("jmp", "@a+dptr");
12327   emitLabel (jtab);
12328   /* now generate the jump labels */
12329   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12330        jtab = setNextItem (IC_JTLABELS (ic)))
12331     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12332
12333 }
12334
12335 /*-----------------------------------------------------------------*/
12336 /* genCast - gen code for casting                                  */
12337 /*-----------------------------------------------------------------*/
12338 static void
12339 genCast (iCode * ic)
12340 {
12341   operand *result = IC_RESULT (ic);
12342   sym_link *ctype = operandType (IC_LEFT (ic));
12343   sym_link *rtype = operandType (IC_RIGHT (ic));
12344   operand *right = IC_RIGHT (ic);
12345   int size, offset;
12346
12347   D (emitcode (";", "genCast"));
12348
12349   /* if they are equivalent then do nothing */
12350   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12351     return;
12352
12353   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12354   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12355
12356   /* if the result is a bit (and not a bitfield) */
12357   if (IS_BIT (OP_SYMBOL (result)->type))
12358     {
12359       /* if the right size is a literal then
12360          we know what the value is */
12361       if (AOP_TYPE (right) == AOP_LIT)
12362         {
12363           if (((int) operandLitValue (right)))
12364             aopPut (result, one, 0);
12365           else
12366             aopPut (result, zero, 0);
12367
12368           goto release;
12369         }
12370
12371       /* the right is also a bit variable */
12372       if (AOP_TYPE (right) == AOP_CRY)
12373         {
12374           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12375           aopPut (result, "c", 0);
12376           goto release;
12377         }
12378
12379       /* we need to or */
12380       toBoolean (right);
12381       aopPut (result, "a", 0);
12382       goto release;
12383     }
12384
12385   /* if they are the same size : or less */
12386   if (AOP_SIZE (result) <= AOP_SIZE (right))
12387     {
12388
12389       /* if they are in the same place */
12390       if (sameRegs (AOP (right), AOP (result)))
12391         goto release;
12392
12393       /* if they in different places then copy */
12394       size = AOP_SIZE (result);
12395       offset = 0;
12396       _startLazyDPSEvaluation ();
12397       while (size--)
12398         {
12399           aopPut (result,
12400                   aopGet (right, offset, FALSE, FALSE, NULL),
12401                   offset);
12402           offset++;
12403         }
12404       _endLazyDPSEvaluation ();
12405       goto release;
12406     }
12407
12408   /* if the result is of type pointer */
12409   if (IS_PTR (ctype))
12410     {
12411
12412       int p_type;
12413       sym_link *type = operandType (right);
12414
12415       /* pointer to generic pointer */
12416       if (IS_GENPTR (ctype))
12417         {
12418           if (IS_PTR (type))
12419             {
12420               p_type = DCL_TYPE (type);
12421             }
12422           else
12423             {
12424 #if OLD_CAST_BEHAVIOR
12425               /* KV: we are converting a non-pointer type to
12426                * a generic pointer. This (ifdef'd out) code
12427                * says that the resulting generic pointer
12428                * should have the same class as the storage
12429                * location of the non-pointer variable.
12430                *
12431                * For example, converting an int (which happens
12432                * to be stored in DATA space) to a pointer results
12433                * in a DATA generic pointer; if the original int
12434                * in XDATA space, so will be the resulting pointer.
12435                *
12436                * I don't like that behavior, and thus this change:
12437                * all such conversions will be forced to XDATA and
12438                * throw a warning. If you want some non-XDATA
12439                * type, or you want to suppress the warning, you
12440                * must go through an intermediate cast, like so:
12441                *
12442                * char _generic *gp = (char _xdata *)(intVar);
12443                */
12444               sym_link *etype = getSpec (type);
12445
12446               /* we have to go by the storage class */
12447               if (SPEC_OCLS (etype) != generic)
12448                 {
12449                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12450                 }
12451               else
12452 #endif
12453                 {
12454                   /* Converting unknown class (i.e. register variable)
12455                    * to generic pointer. This is not good, but
12456                    * we'll make a guess (and throw a warning).
12457                    */
12458                   p_type = FPOINTER;
12459                   werror (W_INT_TO_GEN_PTR_CAST);
12460                 }
12461             }
12462
12463           /* the first two bytes are known */
12464           size = GPTRSIZE - 1;
12465           offset = 0;
12466           _startLazyDPSEvaluation ();
12467           while (size--)
12468             {
12469               aopPut (result,
12470                       aopGet (right, offset, FALSE, FALSE, NULL),
12471                       offset);
12472               offset++;
12473             }
12474           _endLazyDPSEvaluation ();
12475
12476           /* the last byte depending on type */
12477             {
12478                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12479                 char gpValStr[10];
12480
12481                 if (gpVal == -1)
12482                 {
12483                     // pointerTypeToGPByte will have bitched.
12484                     exit(1);
12485                 }
12486
12487                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12488                 aopPut (result, gpValStr, GPTRSIZE - 1);
12489             }
12490           goto release;
12491         }
12492
12493       /* just copy the pointers */
12494       size = AOP_SIZE (result);
12495       offset = 0;
12496       _startLazyDPSEvaluation ();
12497       while (size--)
12498         {
12499           aopPut (result,
12500                   aopGet (right, offset, FALSE, FALSE, NULL),
12501                   offset);
12502           offset++;
12503         }
12504       _endLazyDPSEvaluation ();
12505       goto release;
12506     }
12507
12508   /* so we now know that the size of destination is greater
12509      than the size of the source */
12510   /* we move to result for the size of source */
12511   size = AOP_SIZE (right);
12512   offset = 0;
12513   _startLazyDPSEvaluation ();
12514   while (size--)
12515     {
12516       aopPut (result,
12517               aopGet (right, offset, FALSE, FALSE, NULL),
12518               offset);
12519       offset++;
12520     }
12521   _endLazyDPSEvaluation ();
12522
12523   /* now depending on the sign of the source && destination */
12524   size = AOP_SIZE (result) - AOP_SIZE (right);
12525   /* if unsigned or not an integral type */
12526   /* also, if the source is a bit, we don't need to sign extend, because
12527    * it can't possibly have set the sign bit.
12528    */
12529   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12530     {
12531       while (size--)
12532         {
12533           aopPut (result, zero, offset++);
12534         }
12535     }
12536   else
12537     {
12538       /* we need to extend the sign :{ */
12539       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12540                         FALSE, FALSE, NULL));
12541       emitcode ("rlc", "a");
12542       emitcode ("subb", "a,acc");
12543       while (size--)
12544         aopPut (result, "a", offset++);
12545     }
12546
12547   /* we are done hurray !!!! */
12548
12549 release:
12550   freeAsmop (right, NULL, ic, TRUE);
12551   freeAsmop (result, NULL, ic, TRUE);
12552
12553 }
12554
12555 /*-----------------------------------------------------------------*/
12556 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12557 /*-----------------------------------------------------------------*/
12558 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12559 {
12560     operand *from , *to , *count;
12561     symbol *lbl;
12562     bitVect *rsave;
12563     int i;
12564
12565     /* we know it has to be 3 parameters */
12566     assert (nparms == 3);
12567
12568     rsave = newBitVect(16);
12569     /* save DPTR if it needs to be saved */
12570     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12571             if (bitVectBitValue(ic->rMask,i))
12572                     rsave = bitVectSetBit(rsave,i);
12573     }
12574     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12575                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12576     savermask(rsave);
12577
12578     to = parms[0];
12579     from = parms[1];
12580     count = parms[2];
12581
12582     aopOp (from, ic->next, FALSE, FALSE);
12583
12584     /* get from into DPTR1 */
12585     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12586     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12587     if (options.model == MODEL_FLAT24) {
12588         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12589     }
12590
12591     freeAsmop (from, NULL, ic, FALSE);
12592     aopOp (to, ic, FALSE, FALSE);
12593     /* get "to" into DPTR */
12594     /* if the operand is already in dptr
12595        then we do nothing else we move the value to dptr */
12596     if (AOP_TYPE (to) != AOP_STR) {
12597         /* if already in DPTR then we need to push */
12598         if (AOP_TYPE(to) == AOP_DPTR) {
12599             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12600             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12601             if (options.model == MODEL_FLAT24)
12602                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12603             emitcode ("pop", "dph");
12604             emitcode ("pop", "dpl");
12605         } else {
12606             _startLazyDPSEvaluation ();
12607             /* if this is remateriazable */
12608             if (AOP_TYPE (to) == AOP_IMMD) {
12609                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12610             } else {                    /* we need to get it byte by byte */
12611                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12612                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12613                 if (options.model == MODEL_FLAT24) {
12614                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12615                 }
12616             }
12617             _endLazyDPSEvaluation ();
12618         }
12619     }
12620     freeAsmop (to, NULL, ic, FALSE);
12621     _G.dptrInUse = _G.dptr1InUse = 1;
12622     aopOp (count, ic->next->next, FALSE,FALSE);
12623     lbl =newiTempLabel(NULL);
12624
12625     /* now for the actual copy */
12626     if (AOP_TYPE(count) == AOP_LIT &&
12627         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12628         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12629         if (fromc) {
12630             emitcode ("lcall","__bi_memcpyc2x_s");
12631         } else {
12632             emitcode ("lcall","__bi_memcpyx2x_s");
12633         }
12634         freeAsmop (count, NULL, ic, FALSE);
12635     } else {
12636         symbol *lbl1 = newiTempLabel(NULL);
12637
12638         emitcode (";"," Auto increment but no djnz");
12639         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12640         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12641         freeAsmop (count, NULL, ic, FALSE);
12642         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12643         emitLabel (lbl);
12644         if (fromc) {
12645             emitcode ("clr","a");
12646             emitcode ("movc", "a,@a+dptr");
12647         } else
12648             emitcode ("movx", "a,@dptr");
12649         emitcode ("movx", "@dptr,a");
12650         emitcode ("inc", "dptr");
12651         emitcode ("inc", "dptr");
12652         emitcode ("mov","a,b");
12653         emitcode ("orl","a,_ap");
12654         emitcode ("jz","!tlabel",lbl1->key+100);
12655         emitcode ("mov","a,_ap");
12656         emitcode ("add","a,#!constbyte",0xFF);
12657         emitcode ("mov","_ap,a");
12658         emitcode ("mov","a,b");
12659         emitcode ("addc","a,#!constbyte",0xFF);
12660         emitcode ("mov","b,a");
12661         emitcode ("sjmp","!tlabel",lbl->key+100);
12662         emitLabel (lbl1);
12663     }
12664     emitcode ("mov", "dps,#0");
12665     _G.dptrInUse = _G.dptr1InUse = 0;
12666     unsavermask(rsave);
12667
12668 }
12669
12670 /*-----------------------------------------------------------------*/
12671 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12672 /*-----------------------------------------------------------------*/
12673 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12674 {
12675     operand *from , *to , *count;
12676     symbol *lbl,*lbl2;
12677     bitVect *rsave;
12678     int i;
12679
12680     /* we know it has to be 3 parameters */
12681     assert (nparms == 3);
12682
12683     rsave = newBitVect(16);
12684     /* save DPTR if it needs to be saved */
12685     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12686             if (bitVectBitValue(ic->rMask,i))
12687                     rsave = bitVectSetBit(rsave,i);
12688     }
12689     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12690                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12691     savermask(rsave);
12692
12693     to = parms[0];
12694     from = parms[1];
12695     count = parms[2];
12696
12697     aopOp (from, ic->next, FALSE, FALSE);
12698
12699     /* get from into DPTR1 */
12700     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12701     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12702     if (options.model == MODEL_FLAT24) {
12703         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12704     }
12705
12706     freeAsmop (from, NULL, ic, FALSE);
12707     aopOp (to, ic, FALSE, FALSE);
12708     /* get "to" into DPTR */
12709     /* if the operand is already in dptr
12710        then we do nothing else we move the value to dptr */
12711     if (AOP_TYPE (to) != AOP_STR) {
12712         /* if already in DPTR then we need to push */
12713         if (AOP_TYPE(to) == AOP_DPTR) {
12714             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12715             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12716             if (options.model == MODEL_FLAT24)
12717                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12718             emitcode ("pop", "dph");
12719             emitcode ("pop", "dpl");
12720         } else {
12721             _startLazyDPSEvaluation ();
12722             /* if this is remateriazable */
12723             if (AOP_TYPE (to) == AOP_IMMD) {
12724                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12725             } else {                    /* we need to get it byte by byte */
12726                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12727                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12728                 if (options.model == MODEL_FLAT24) {
12729                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12730                 }
12731             }
12732             _endLazyDPSEvaluation ();
12733         }
12734     }
12735     freeAsmop (to, NULL, ic, FALSE);
12736     _G.dptrInUse = _G.dptr1InUse = 1;
12737     aopOp (count, ic->next->next, FALSE,FALSE);
12738     lbl =newiTempLabel(NULL);
12739     lbl2 =newiTempLabel(NULL);
12740
12741     /* now for the actual compare */
12742     if (AOP_TYPE(count) == AOP_LIT &&
12743         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12744         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12745         if (fromc)
12746             emitcode("lcall","__bi_memcmpc2x_s");
12747         else
12748             emitcode("lcall","__bi_memcmpx2x_s");
12749         freeAsmop (count, NULL, ic, FALSE);
12750         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12751         aopPut(IC_RESULT(ic),"a",0);
12752         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12753     } else {
12754         symbol *lbl1 = newiTempLabel(NULL);
12755
12756         emitcode("push","ar0");
12757         emitcode (";"," Auto increment but no djnz");
12758         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12759         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12760         freeAsmop (count, NULL, ic, FALSE);
12761         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12762         emitLabel (lbl);
12763         if (fromc) {
12764             emitcode ("clr","a");
12765             emitcode ("movc", "a,@a+dptr");
12766         } else
12767             emitcode ("movx", "a,@dptr");
12768         emitcode ("mov","r0,a");
12769         emitcode ("movx", "a,@dptr");
12770         emitcode ("clr","c");
12771         emitcode ("subb","a,r0");
12772         emitcode ("jnz","!tlabel",lbl2->key+100);
12773         emitcode ("inc", "dptr");
12774         emitcode ("inc", "dptr");
12775         emitcode ("mov","a,b");
12776         emitcode ("orl","a,_ap");
12777         emitcode ("jz","!tlabel",lbl1->key+100);
12778         emitcode ("mov","a,_ap");
12779         emitcode ("add","a,#!constbyte",0xFF);
12780         emitcode ("mov","_ap,a");
12781         emitcode ("mov","a,b");
12782         emitcode ("addc","a,#!constbyte",0xFF);
12783         emitcode ("mov","b,a");
12784         emitcode ("sjmp","!tlabel",lbl->key+100);
12785         emitLabel (lbl1);
12786         emitcode ("clr","a");
12787         emitLabel (lbl2);
12788         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12789         aopPut(IC_RESULT(ic),"a",0);
12790         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12791         emitcode("pop","ar0");
12792         emitcode ("mov", "dps,#0");
12793     }
12794     _G.dptrInUse = _G.dptr1InUse = 0;
12795     unsavermask(rsave);
12796
12797 }
12798
12799 /*-----------------------------------------------------------------*/
12800 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12801 /* port, first parameter output area second parameter pointer to   */
12802 /* port third parameter count                                      */
12803 /*-----------------------------------------------------------------*/
12804 static void genInp( iCode *ic, int nparms, operand **parms)
12805 {
12806     operand *from , *to , *count;
12807     symbol *lbl;
12808     bitVect *rsave;
12809     int i;
12810
12811     /* we know it has to be 3 parameters */
12812     assert (nparms == 3);
12813
12814     rsave = newBitVect(16);
12815     /* save DPTR if it needs to be saved */
12816     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12817             if (bitVectBitValue(ic->rMask,i))
12818                     rsave = bitVectSetBit(rsave,i);
12819     }
12820     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12821                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12822     savermask(rsave);
12823
12824     to = parms[0];
12825     from = parms[1];
12826     count = parms[2];
12827
12828     aopOp (from, ic->next, FALSE, FALSE);
12829
12830     /* get from into DPTR1 */
12831     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12832     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12833     if (options.model == MODEL_FLAT24) {
12834         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12835     }
12836
12837     freeAsmop (from, NULL, ic, FALSE);
12838     aopOp (to, ic, FALSE, FALSE);
12839     /* get "to" into DPTR */
12840     /* if the operand is already in dptr
12841        then we do nothing else we move the value to dptr */
12842     if (AOP_TYPE (to) != AOP_STR) {
12843         /* if already in DPTR then we need to push */
12844         if (AOP_TYPE(to) == AOP_DPTR) {
12845             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12846             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12847             if (options.model == MODEL_FLAT24)
12848                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12849             emitcode ("pop", "dph");
12850             emitcode ("pop", "dpl");
12851         } else {
12852             _startLazyDPSEvaluation ();
12853             /* if this is remateriazable */
12854             if (AOP_TYPE (to) == AOP_IMMD) {
12855                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12856             } else {                    /* we need to get it byte by byte */
12857                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12858                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12859                 if (options.model == MODEL_FLAT24) {
12860                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12861                 }
12862             }
12863             _endLazyDPSEvaluation ();
12864         }
12865     }
12866     freeAsmop (to, NULL, ic, FALSE);
12867
12868     _G.dptrInUse = _G.dptr1InUse = 1;
12869     aopOp (count, ic->next->next, FALSE,FALSE);
12870     lbl =newiTempLabel(NULL);
12871
12872     /* now for the actual copy */
12873     if (AOP_TYPE(count) == AOP_LIT &&
12874         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12875         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12876         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12877         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12878         freeAsmop (count, NULL, ic, FALSE);
12879         emitLabel (lbl);
12880         emitcode ("movx", "a,@dptr");   /* read data from port */
12881         emitcode ("dec","dps");         /* switch to DPTR */
12882         emitcode ("movx", "@dptr,a");   /* save into location */
12883         emitcode ("inc", "dptr");       /* point to next area */
12884         emitcode ("inc","dps");         /* switch to DPTR2 */
12885         emitcode ("djnz","b,!tlabel",lbl->key+100);
12886     } else {
12887         symbol *lbl1 = newiTempLabel(NULL);
12888
12889         emitcode (";"," Auto increment but no djnz");
12890         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12891         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12892         freeAsmop (count, NULL, ic, FALSE);
12893         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12894         emitLabel (lbl);
12895         emitcode ("movx", "a,@dptr");
12896         emitcode ("dec","dps");         /* switch to DPTR */
12897         emitcode ("movx", "@dptr,a");
12898         emitcode ("inc", "dptr");
12899         emitcode ("inc","dps");         /* switch to DPTR2 */
12900 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12901 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12902         emitcode ("mov","a,b");
12903         emitcode ("orl","a,_ap");
12904         emitcode ("jz","!tlabel",lbl1->key+100);
12905         emitcode ("mov","a,_ap");
12906         emitcode ("add","a,#!constbyte",0xFF);
12907         emitcode ("mov","_ap,a");
12908         emitcode ("mov","a,b");
12909         emitcode ("addc","a,#!constbyte",0xFF);
12910         emitcode ("mov","b,a");
12911         emitcode ("sjmp","!tlabel",lbl->key+100);
12912         emitLabel (lbl1);
12913     }
12914     emitcode ("mov", "dps,#0");
12915     _G.dptrInUse = _G.dptr1InUse = 0;
12916     unsavermask(rsave);
12917
12918 }
12919
12920 /*-----------------------------------------------------------------*/
12921 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12922 /* port, first parameter output area second parameter pointer to   */
12923 /* port third parameter count                                      */
12924 /*-----------------------------------------------------------------*/
12925 static void genOutp( iCode *ic, int nparms, operand **parms)
12926 {
12927     operand *from , *to , *count;
12928     symbol *lbl;
12929     bitVect *rsave;
12930     int i;
12931
12932     /* we know it has to be 3 parameters */
12933     assert (nparms == 3);
12934
12935     rsave = newBitVect(16);
12936     /* save DPTR if it needs to be saved */
12937     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12938             if (bitVectBitValue(ic->rMask,i))
12939                     rsave = bitVectSetBit(rsave,i);
12940     }
12941     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12942                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12943     savermask(rsave);
12944
12945     to = parms[0];
12946     from = parms[1];
12947     count = parms[2];
12948
12949     aopOp (from, ic->next, FALSE, FALSE);
12950
12951     /* get from into DPTR1 */
12952     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12953     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12954     if (options.model == MODEL_FLAT24) {
12955         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12956     }
12957
12958     freeAsmop (from, NULL, ic, FALSE);
12959     aopOp (to, ic, FALSE, FALSE);
12960     /* get "to" into DPTR */
12961     /* if the operand is already in dptr
12962        then we do nothing else we move the value to dptr */
12963     if (AOP_TYPE (to) != AOP_STR) {
12964         /* if already in DPTR then we need to push */
12965         if (AOP_TYPE(to) == AOP_DPTR) {
12966             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12967             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12968             if (options.model == MODEL_FLAT24)
12969                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12970             emitcode ("pop", "dph");
12971             emitcode ("pop", "dpl");
12972         } else {
12973             _startLazyDPSEvaluation ();
12974             /* if this is remateriazable */
12975             if (AOP_TYPE (to) == AOP_IMMD) {
12976                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12977             } else {                    /* we need to get it byte by byte */
12978                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12979                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12980                 if (options.model == MODEL_FLAT24) {
12981                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12982                 }
12983             }
12984             _endLazyDPSEvaluation ();
12985         }
12986     }
12987     freeAsmop (to, NULL, ic, FALSE);
12988
12989     _G.dptrInUse = _G.dptr1InUse = 1;
12990     aopOp (count, ic->next->next, FALSE,FALSE);
12991     lbl =newiTempLabel(NULL);
12992
12993     /* now for the actual copy */
12994     if (AOP_TYPE(count) == AOP_LIT &&
12995         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12996         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12997         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12998         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12999         emitLabel (lbl);
13000         emitcode ("movx", "a,@dptr");   /* read data from port */
13001         emitcode ("inc","dps");         /* switch to DPTR2 */
13002         emitcode ("movx", "@dptr,a");   /* save into location */
13003         emitcode ("inc", "dptr");       /* point to next area */
13004         emitcode ("dec","dps");         /* switch to DPTR */
13005         emitcode ("djnz","b,!tlabel",lbl->key+100);
13006         freeAsmop (count, NULL, ic, FALSE);
13007     } else {
13008         symbol *lbl1 = newiTempLabel(NULL);
13009
13010         emitcode (";"," Auto increment but no djnz");
13011         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13012         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13013         freeAsmop (count, NULL, ic, FALSE);
13014         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13015         emitLabel (lbl);
13016         emitcode ("movx", "a,@dptr");
13017         emitcode ("inc", "dptr");
13018         emitcode ("inc","dps");         /* switch to DPTR2 */
13019         emitcode ("movx", "@dptr,a");
13020         emitcode ("dec","dps");         /* switch to DPTR */
13021         emitcode ("mov","a,b");
13022         emitcode ("orl","a,_ap");
13023         emitcode ("jz","!tlabel",lbl1->key+100);
13024         emitcode ("mov","a,_ap");
13025         emitcode ("add","a,#!constbyte",0xFF);
13026         emitcode ("mov","_ap,a");
13027         emitcode ("mov","a,b");
13028         emitcode ("addc","a,#!constbyte",0xFF);
13029         emitcode ("mov","b,a");
13030         emitcode ("sjmp","!tlabel",lbl->key+100);
13031         emitLabel (lbl1);
13032     }
13033     emitcode ("mov", "dps,#0");
13034     _G.dptrInUse = _G.dptr1InUse = 0;
13035     unsavermask(rsave);
13036
13037 }
13038
13039 /*-----------------------------------------------------------------*/
13040 /* genSwapW - swap lower & high order bytes                        */
13041 /*-----------------------------------------------------------------*/
13042 static void genSwapW(iCode *ic, int nparms, operand **parms)
13043 {
13044     operand *dest;
13045     operand *src;
13046     assert (nparms==1);
13047
13048     src = parms[0];
13049     dest=IC_RESULT(ic);
13050
13051     assert(getSize(operandType(src))==2);
13052
13053     aopOp (src, ic, FALSE, FALSE);
13054     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13055     _G.accInUse++;
13056     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13057     _G.accInUse--;
13058     freeAsmop (src, NULL, ic, FALSE);
13059
13060     aopOp (dest,ic, FALSE, FALSE);
13061     aopPut(dest,"b",0);
13062     aopPut(dest,"a",1);
13063     freeAsmop (dest, NULL, ic, FALSE);
13064 }
13065
13066 /*-----------------------------------------------------------------*/
13067 /* genMemsetX - gencode for memSetX data                           */
13068 /*-----------------------------------------------------------------*/
13069 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13070 {
13071     operand *to , *val , *count;
13072     symbol *lbl;
13073     char *l;
13074     int i;
13075     bitVect *rsave;
13076
13077     /* we know it has to be 3 parameters */
13078     assert (nparms == 3);
13079
13080     to = parms[0];
13081     val = parms[1];
13082     count = parms[2];
13083
13084     /* save DPTR if it needs to be saved */
13085     rsave = newBitVect(16);
13086     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13087             if (bitVectBitValue(ic->rMask,i))
13088                     rsave = bitVectSetBit(rsave,i);
13089     }
13090     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13091                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13092     savermask(rsave);
13093
13094     aopOp (to, ic, FALSE, FALSE);
13095     /* get "to" into DPTR */
13096     /* if the operand is already in dptr
13097        then we do nothing else we move the value to dptr */
13098     if (AOP_TYPE (to) != AOP_STR) {
13099         /* if already in DPTR then we need to push */
13100         if (AOP_TYPE(to) == AOP_DPTR) {
13101             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13102             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13103             if (options.model == MODEL_FLAT24)
13104                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13105             emitcode ("pop", "dph");
13106             emitcode ("pop", "dpl");
13107         } else {
13108             _startLazyDPSEvaluation ();
13109             /* if this is remateriazable */
13110             if (AOP_TYPE (to) == AOP_IMMD) {
13111                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13112             } else {                    /* we need to get it byte by byte */
13113                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13114                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13115                 if (options.model == MODEL_FLAT24) {
13116                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13117                 }
13118             }
13119             _endLazyDPSEvaluation ();
13120         }
13121     }
13122     freeAsmop (to, NULL, ic, FALSE);
13123
13124     aopOp (val, ic->next->next, FALSE,FALSE);
13125     aopOp (count, ic->next->next, FALSE,FALSE);
13126     lbl =newiTempLabel(NULL);
13127     /* now for the actual copy */
13128     if (AOP_TYPE(count) == AOP_LIT &&
13129         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13130         l = aopGet(val, 0, FALSE, FALSE, NULL);
13131         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13132         MOVA(l);
13133         emitLabel (lbl);
13134         emitcode ("movx", "@dptr,a");
13135         emitcode ("inc", "dptr");
13136         emitcode ("djnz","b,!tlabel",lbl->key+100);
13137     } else {
13138         symbol *lbl1 = newiTempLabel(NULL);
13139
13140         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13141         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13142         emitLabel (lbl);
13143         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13144         emitcode ("movx", "@dptr,a");
13145         emitcode ("inc", "dptr");
13146         emitcode ("mov","a,b");
13147         emitcode ("orl","a,_ap");
13148         emitcode ("jz","!tlabel",lbl1->key+100);
13149         emitcode ("mov","a,_ap");
13150         emitcode ("add","a,#!constbyte",0xFF);
13151         emitcode ("mov","_ap,a");
13152         emitcode ("mov","a,b");
13153         emitcode ("addc","a,#!constbyte",0xFF);
13154         emitcode ("mov","b,a");
13155         emitcode ("sjmp","!tlabel",lbl->key+100);
13156         emitLabel (lbl1);
13157     }
13158     freeAsmop (count, NULL, ic, FALSE);
13159     unsavermask(rsave);
13160 }
13161
13162 /*-----------------------------------------------------------------*/
13163 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13164 /*-----------------------------------------------------------------*/
13165 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13166 {
13167         bitVect *rsave ;
13168         operand *pnum, *result;
13169         int i;
13170
13171         assert (nparms==1);
13172         /* save registers that need to be saved */
13173         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13174                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13175
13176         pnum = parms[0];
13177         aopOp (pnum, ic, FALSE, FALSE);
13178         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13179         freeAsmop (pnum, NULL, ic, FALSE);
13180         emitcode ("lcall","NatLib_LoadPrimitive");
13181         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13182         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13183             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13184                 for (i = (size-1) ; i >= 0 ; i-- ) {
13185                         emitcode ("push","a%s",javaRet[i]);
13186                 }
13187                 for (i=0; i < size ; i++ ) {
13188                         emitcode ("pop","a%s",
13189                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13190                 }
13191         } else {
13192                 for (i = 0 ; i < size ; i++ ) {
13193                         aopPut(result,javaRet[i],i);
13194                 }
13195         }
13196         freeAsmop (result, NULL, ic, FALSE);
13197         unsavermask(rsave);
13198 }
13199
13200 /*-----------------------------------------------------------------*/
13201 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13202 /*-----------------------------------------------------------------*/
13203 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13204 {
13205         bitVect *rsave ;
13206         operand *pnum, *result;
13207         int size = 3;
13208         int i;
13209
13210         assert (nparms==1);
13211         /* save registers that need to be saved */
13212         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13213                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13214
13215         pnum = parms[0];
13216         aopOp (pnum, ic, FALSE, FALSE);
13217         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13218         freeAsmop (pnum, NULL, ic, FALSE);
13219         emitcode ("lcall","NatLib_LoadPointer");
13220         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13221         if (AOP_TYPE(result)!=AOP_STR) {
13222                 for (i = 0 ; i < size ; i++ ) {
13223                         aopPut(result,fReturn[i],i);
13224                 }
13225         }
13226         freeAsmop (result, NULL, ic, FALSE);
13227         unsavermask(rsave);
13228 }
13229
13230 /*-----------------------------------------------------------------*/
13231 /* genNatLibInstallStateBlock -                                    */
13232 /*-----------------------------------------------------------------*/
13233 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13234                                        operand **parms, const char *name)
13235 {
13236         bitVect *rsave ;
13237         operand *psb, *handle;
13238         assert (nparms==2);
13239
13240         /* save registers that need to be saved */
13241         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13242                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13243         psb = parms[0];
13244         handle = parms[1];
13245
13246         /* put pointer to state block into DPTR1 */
13247         aopOp (psb, ic, FALSE, FALSE);
13248         if (AOP_TYPE (psb) == AOP_IMMD) {
13249                 emitcode ("mov","dps,#1");
13250                 emitcode ("mov", "dptr,%s",
13251                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13252                 emitcode ("mov","dps,#0");
13253         } else {
13254                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13255                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13256                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13257         }
13258         freeAsmop (psb, NULL, ic, FALSE);
13259
13260         /* put libraryID into DPTR */
13261         emitcode ("mov","dptr,#LibraryID");
13262
13263         /* put handle into r3:r2 */
13264         aopOp (handle, ic, FALSE, FALSE);
13265         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13266                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13267                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13268                 emitcode ("pop","ar3");
13269                 emitcode ("pop","ar2");
13270         } else {
13271                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13272                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13273         }
13274         freeAsmop (psb, NULL, ic, FALSE);
13275
13276         /* make the call */
13277         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13278
13279         /* put return value into place*/
13280         _G.accInUse++;
13281         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13282         _G.accInUse--;
13283         aopPut(IC_RESULT(ic),"a",0);
13284         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13285         unsavermask(rsave);
13286 }
13287
13288 /*-----------------------------------------------------------------*/
13289 /* genNatLibRemoveStateBlock -                                     */
13290 /*-----------------------------------------------------------------*/
13291 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13292 {
13293         bitVect *rsave ;
13294
13295         assert(nparms==0);
13296
13297         /* save registers that need to be saved */
13298         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13299                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13300
13301         /* put libraryID into DPTR */
13302         emitcode ("mov","dptr,#LibraryID");
13303         /* make the call */
13304         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13305         unsavermask(rsave);
13306 }
13307
13308 /*-----------------------------------------------------------------*/
13309 /* genNatLibGetStateBlock -                                        */
13310 /*-----------------------------------------------------------------*/
13311 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13312                                    operand **parms,const char *name)
13313 {
13314         bitVect *rsave ;
13315         symbol *lbl = newiTempLabel(NULL);
13316
13317         assert(nparms==0);
13318         /* save registers that need to be saved */
13319         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13320                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13321
13322         /* put libraryID into DPTR */
13323         emitcode ("mov","dptr,#LibraryID");
13324         /* make the call */
13325         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13326         emitcode ("jnz","!tlabel",lbl->key+100);
13327
13328         /* put return value into place */
13329         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13330         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13331                 emitcode ("push","ar3");
13332                 emitcode ("push","ar2");
13333                 emitcode ("pop","%s",
13334                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13335                 emitcode ("pop","%s",
13336                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13337         } else {
13338                 aopPut(IC_RESULT(ic),"r2",0);
13339                 aopPut(IC_RESULT(ic),"r3",1);
13340         }
13341         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13342         emitLabel (lbl);
13343         unsavermask(rsave);
13344 }
13345
13346 /*-----------------------------------------------------------------*/
13347 /* genMMMalloc -                                                   */
13348 /*-----------------------------------------------------------------*/
13349 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13350                          int size, const char *name)
13351 {
13352         bitVect *rsave ;
13353         operand *bsize;
13354         symbol *rsym;
13355         symbol *lbl = newiTempLabel(NULL);
13356
13357         assert (nparms == 1);
13358         /* save registers that need to be saved */
13359         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13360                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13361
13362         bsize=parms[0];
13363         aopOp (bsize,ic,FALSE,FALSE);
13364
13365         /* put the size in R4-R2 */
13366         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13367                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13368                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13369                 if (size==3) {
13370                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13371                         emitcode("pop","ar4");
13372                 }
13373                 emitcode("pop","ar3");
13374                 emitcode("pop","ar2");
13375         } else {
13376                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13377                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13378                 if (size==3) {
13379                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13380                 }
13381         }
13382         freeAsmop (bsize, NULL, ic, FALSE);
13383
13384         /* make the call */
13385         emitcode ("lcall","MM_%s",name);
13386         emitcode ("jz","!tlabel",lbl->key+100);
13387         emitcode ("mov","r2,#!constbyte",0xff);
13388         emitcode ("mov","r3,#!constbyte",0xff);
13389         emitLabel (lbl);
13390         /* we don't care about the pointer : we just save the handle */
13391         rsym = OP_SYMBOL(IC_RESULT(ic));
13392         if (rsym->liveFrom != rsym->liveTo) {
13393                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13394                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13395                         emitcode ("push","ar3");
13396                         emitcode ("push","ar2");
13397                         emitcode ("pop","%s",
13398                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13399                         emitcode ("pop","%s",
13400                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13401                 } else {
13402                         aopPut(IC_RESULT(ic),"r2",0);
13403                         aopPut(IC_RESULT(ic),"r3",1);
13404                 }
13405                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13406         }
13407         unsavermask(rsave);
13408 }
13409
13410 /*-----------------------------------------------------------------*/
13411 /* genMMDeref -                                                    */
13412 /*-----------------------------------------------------------------*/
13413 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13414 {
13415         bitVect *rsave ;
13416         operand *handle;
13417
13418         assert (nparms == 1);
13419         /* save registers that need to be saved */
13420         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13421                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13422
13423         handle=parms[0];
13424         aopOp (handle,ic,FALSE,FALSE);
13425
13426         /* put the size in R4-R2 */
13427         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13428                 emitcode("push","%s",
13429                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13430                 emitcode("push","%s",
13431                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13432                 emitcode("pop","ar3");
13433                 emitcode("pop","ar2");
13434         } else {
13435                 emitcode ("mov","r2,%s",
13436                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13437                 emitcode ("mov","r3,%s",
13438                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13439         }
13440         freeAsmop (handle, NULL, ic, FALSE);
13441
13442         /* make the call */
13443         emitcode ("lcall","MM_Deref");
13444
13445         {
13446                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13447                 if (rsym->liveFrom != rsym->liveTo) {
13448                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13449                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13450                             _startLazyDPSEvaluation ();
13451
13452                             aopPut(IC_RESULT(ic),"dpl",0);
13453                             aopPut(IC_RESULT(ic),"dph",1);
13454                             aopPut(IC_RESULT(ic),"dpx",2);
13455
13456                             _endLazyDPSEvaluation ();
13457
13458                         }
13459                 }
13460         }
13461         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13462         unsavermask(rsave);
13463 }
13464
13465 /*-----------------------------------------------------------------*/
13466 /* genMMUnrestrictedPersist -                                      */
13467 /*-----------------------------------------------------------------*/
13468 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13469 {
13470         bitVect *rsave ;
13471         operand *handle;
13472
13473         assert (nparms == 1);
13474         /* save registers that need to be saved */
13475         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13476                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13477
13478         handle=parms[0];
13479         aopOp (handle,ic,FALSE,FALSE);
13480
13481         /* put the size in R3-R2 */
13482         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13483                 emitcode("push","%s",
13484                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13485                 emitcode("push","%s",
13486                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13487                 emitcode("pop","ar3");
13488                 emitcode("pop","ar2");
13489         } else {
13490                 emitcode ("mov","r2,%s",
13491                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13492                 emitcode ("mov","r3,%s",
13493                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13494         }
13495         freeAsmop (handle, NULL, ic, FALSE);
13496
13497         /* make the call */
13498         emitcode ("lcall","MM_UnrestrictedPersist");
13499
13500         {
13501                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13502                 if (rsym->liveFrom != rsym->liveTo) {
13503                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13504                         aopPut(IC_RESULT(ic),"a",0);
13505                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13506                 }
13507         }
13508         unsavermask(rsave);
13509 }
13510
13511 /*-----------------------------------------------------------------*/
13512 /* genSystemExecJavaProcess -                                      */
13513 /*-----------------------------------------------------------------*/
13514 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13515 {
13516         bitVect *rsave ;
13517         operand *handle, *pp;
13518
13519         assert (nparms==2);
13520         /* save registers that need to be saved */
13521         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13522                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13523
13524         pp = parms[0];
13525         handle = parms[1];
13526
13527         /* put the handle in R3-R2 */
13528         aopOp (handle,ic,FALSE,FALSE);
13529         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13530                 emitcode("push","%s",
13531                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13532                 emitcode("push","%s",
13533                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13534                 emitcode("pop","ar3");
13535                 emitcode("pop","ar2");
13536         } else {
13537                 emitcode ("mov","r2,%s",
13538                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13539                 emitcode ("mov","r3,%s",
13540                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13541         }
13542         freeAsmop (handle, NULL, ic, FALSE);
13543
13544         /* put pointer in DPTR */
13545         aopOp (pp,ic,FALSE,FALSE);
13546         if (AOP_TYPE(pp) == AOP_IMMD) {
13547                 emitcode ("mov", "dptr,%s",
13548                           aopGet (pp, 0, TRUE, FALSE, NULL));
13549         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13550                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13551                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13552                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13553         }
13554         freeAsmop (handle, NULL, ic, FALSE);
13555
13556         /* make the call */
13557         emitcode ("lcall","System_ExecJavaProcess");
13558
13559         /* put result in place */
13560         {
13561                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13562                 if (rsym->liveFrom != rsym->liveTo) {
13563                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13564                         aopPut(IC_RESULT(ic),"a",0);
13565                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13566                 }
13567         }
13568
13569         unsavermask(rsave);
13570 }
13571
13572 /*-----------------------------------------------------------------*/
13573 /* genSystemRTCRegisters -                                         */
13574 /*-----------------------------------------------------------------*/
13575 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13576                                   char *name)
13577 {
13578         bitVect *rsave ;
13579         operand *pp;
13580
13581         assert (nparms==1);
13582         /* save registers that need to be saved */
13583         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13584                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13585
13586         pp=parms[0];
13587         /* put pointer in DPTR */
13588         aopOp (pp,ic,FALSE,FALSE);
13589         if (AOP_TYPE (pp) == AOP_IMMD) {
13590                 emitcode ("mov","dps,#1");
13591                 emitcode ("mov", "dptr,%s",
13592                           aopGet (pp, 0, TRUE, FALSE, NULL));
13593                 emitcode ("mov","dps,#0");
13594         } else {
13595                 emitcode ("mov","dpl1,%s",
13596                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13597                 emitcode ("mov","dph1,%s",
13598                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13599                 emitcode ("mov","dpx1,%s",
13600                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13601         }
13602         freeAsmop (pp, NULL, ic, FALSE);
13603
13604         /* make the call */
13605         emitcode ("lcall","System_%sRTCRegisters",name);
13606
13607         unsavermask(rsave);
13608 }
13609
13610 /*-----------------------------------------------------------------*/
13611 /* genSystemThreadSleep -                                          */
13612 /*-----------------------------------------------------------------*/
13613 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13614 {
13615         bitVect *rsave ;
13616         operand *to, *s;
13617
13618         assert (nparms==1);
13619         /* save registers that need to be saved */
13620         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13621                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13622
13623         to = parms[0];
13624         aopOp(to,ic,FALSE,FALSE);
13625         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13626             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13627                 emitcode ("push","%s",
13628                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13629                 emitcode ("push","%s",
13630                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13631                 emitcode ("push","%s",
13632                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13633                 emitcode ("push","%s",
13634                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13635                 emitcode ("pop","ar3");
13636                 emitcode ("pop","ar2");
13637                 emitcode ("pop","ar1");
13638                 emitcode ("pop","ar0");
13639         } else {
13640                 emitcode ("mov","r0,%s",
13641                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13642                 emitcode ("mov","r1,%s",
13643                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13644                 emitcode ("mov","r2,%s",
13645                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13646                 emitcode ("mov","r3,%s",
13647                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13648         }
13649         freeAsmop (to, NULL, ic, FALSE);
13650
13651         /* suspend in acc */
13652         s = parms[1];
13653         aopOp(s,ic,FALSE,FALSE);
13654         emitcode ("mov","a,%s",
13655                   aopGet(s,0,FALSE,TRUE,NULL));
13656         freeAsmop (s, NULL, ic, FALSE);
13657
13658         /* make the call */
13659         emitcode ("lcall","System_%s",name);
13660
13661         unsavermask(rsave);
13662 }
13663
13664 /*-----------------------------------------------------------------*/
13665 /* genSystemThreadResume -                                         */
13666 /*-----------------------------------------------------------------*/
13667 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13668 {
13669         bitVect *rsave ;
13670         operand *tid,*pid;
13671
13672         assert (nparms==2);
13673         /* save registers that need to be saved */
13674         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13675                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13676
13677         tid = parms[0];
13678         pid = parms[1];
13679
13680         /* PID in R0 */
13681         aopOp(pid,ic,FALSE,FALSE);
13682         emitcode ("mov","r0,%s",
13683                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13684         freeAsmop (pid, NULL, ic, FALSE);
13685
13686         /* tid into ACC */
13687         aopOp(tid,ic,FALSE,FALSE);
13688         emitcode ("mov","a,%s",
13689                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13690         freeAsmop (tid, NULL, ic, FALSE);
13691
13692         emitcode ("lcall","System_ThreadResume");
13693
13694         /* put result into place */
13695         {
13696                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13697                 if (rsym->liveFrom != rsym->liveTo) {
13698                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13699                         aopPut(IC_RESULT(ic),"a",0);
13700                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13701                 }
13702         }
13703         unsavermask(rsave);
13704 }
13705
13706 /*-----------------------------------------------------------------*/
13707 /* genSystemProcessResume -                                        */
13708 /*-----------------------------------------------------------------*/
13709 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13710 {
13711         bitVect *rsave ;
13712         operand *pid;
13713
13714         assert (nparms==1);
13715         /* save registers that need to be saved */
13716         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13717                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13718
13719         pid = parms[0];
13720
13721         /* pid into ACC */
13722         aopOp(pid,ic,FALSE,FALSE);
13723         emitcode ("mov","a,%s",
13724                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13725         freeAsmop (pid, NULL, ic, FALSE);
13726
13727         emitcode ("lcall","System_ProcessResume");
13728
13729         unsavermask(rsave);
13730 }
13731
13732 /*-----------------------------------------------------------------*/
13733 /* genSystem -                                                     */
13734 /*-----------------------------------------------------------------*/
13735 static void genSystem (iCode *ic,int nparms,char *name)
13736 {
13737         assert(nparms == 0);
13738
13739         emitcode ("lcall","System_%s",name);
13740 }
13741
13742 /*-----------------------------------------------------------------*/
13743 /* genSystemPoll -                                                  */
13744 /*-----------------------------------------------------------------*/
13745 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13746 {
13747         bitVect *rsave ;
13748         operand *fp;
13749
13750         assert (nparms==1);
13751         /* save registers that need to be saved */
13752         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13753                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13754
13755         fp = parms[0];
13756         aopOp (fp,ic,FALSE,FALSE);
13757         if (AOP_TYPE (fp) == AOP_IMMD) {
13758                 emitcode ("mov", "dptr,%s",
13759                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13760         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13761                 emitcode ("mov","dpl,%s",
13762                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13763                 emitcode ("mov","dph,%s",
13764                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13765                 emitcode ("mov","dpx,%s",
13766                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13767         }
13768         freeAsmop (fp, NULL, ic, FALSE);
13769
13770         emitcode ("lcall","System_%sPoll",name);
13771
13772         /* put result into place */
13773         {
13774                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13775                 if (rsym->liveFrom != rsym->liveTo) {
13776                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13777                         aopPut(IC_RESULT(ic),"a",0);
13778                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13779                 }
13780         }
13781         unsavermask(rsave);
13782 }
13783
13784 /*-----------------------------------------------------------------*/
13785 /* genSystemGetCurrentID -                                         */
13786 /*-----------------------------------------------------------------*/
13787 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13788 {
13789         assert (nparms==0);
13790
13791         emitcode ("lcall","System_GetCurrent%sId",name);
13792         /* put result into place */
13793         {
13794                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13795                 if (rsym->liveFrom != rsym->liveTo) {
13796                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13797                         aopPut(IC_RESULT(ic),"a",0);
13798                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13799                 }
13800         }
13801 }
13802
13803 /*-----------------------------------------------------------------*/
13804 /* genDjnz - generate decrement & jump if not zero instrucion      */
13805 /*-----------------------------------------------------------------*/
13806 static int
13807 genDjnz (iCode * ic, iCode * ifx)
13808 {
13809   symbol *lbl, *lbl1;
13810   if (!ifx)
13811     return 0;
13812
13813   /* if the if condition has a false label
13814      then we cannot save */
13815   if (IC_FALSE (ifx))
13816     return 0;
13817
13818   /* if the minus is not of the form a = a - 1 */
13819   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13820       !IS_OP_LITERAL (IC_RIGHT (ic)))
13821     return 0;
13822
13823   if (operandLitValue (IC_RIGHT (ic)) != 1)
13824     return 0;
13825
13826   /* if the size of this greater than one then no
13827      saving */
13828   if (getSize (operandType (IC_RESULT (ic))) > 1)
13829     return 0;
13830
13831   /* otherwise we can save BIG */
13832
13833   D (emitcode (";", "genDjnz"));
13834
13835   lbl = newiTempLabel (NULL);
13836   lbl1 = newiTempLabel (NULL);
13837
13838   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13839
13840   if (AOP_NEEDSACC(IC_RESULT(ic)))
13841   {
13842       /* If the result is accessed indirectly via
13843        * the accumulator, we must explicitly write
13844        * it back after the decrement.
13845        */
13846       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13847
13848       if (strcmp(rByte, "a"))
13849       {
13850            /* Something is hopelessly wrong */
13851            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13852                    __FILE__, __LINE__);
13853            /* We can just give up; the generated code will be inefficient,
13854             * but what the hey.
13855             */
13856            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13857            return 0;
13858       }
13859       emitcode ("dec", "%s", rByte);
13860       aopPut (IC_RESULT (ic), rByte, 0);
13861       emitcode ("jnz", "!tlabel", lbl->key + 100);
13862   }
13863   else if (IS_AOP_PREG (IC_RESULT (ic)))
13864     {
13865       emitcode ("dec", "%s",
13866                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13867       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13868       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13869       ifx->generated = 1;
13870       emitcode ("jnz", "!tlabel", lbl->key + 100);
13871     }
13872   else
13873     {
13874       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13875                 lbl->key + 100);
13876     }
13877   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13878   emitLabel (lbl);
13879   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13880   emitLabel (lbl1);
13881
13882   if (!ifx->generated)
13883       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13884   ifx->generated = 1;
13885   return 1;
13886 }
13887
13888 /*-----------------------------------------------------------------*/
13889 /* genReceive - generate code for a receive iCode                  */
13890 /*-----------------------------------------------------------------*/
13891 static void
13892 genReceive (iCode * ic)
13893 {
13894     int size = getSize (operandType (IC_RESULT (ic)));
13895     int offset = 0;
13896     int rb1off ;
13897
13898     D (emitcode (";", "genReceive"));
13899
13900     if (ic->argreg == 1)
13901     {
13902         /* first parameter */
13903         if (AOP_IS_STR(IC_RESULT(ic)))
13904         {
13905             /* Nothing to do: it's already in the proper place. */
13906             return;
13907         }
13908         else
13909         {
13910             bool useDp2;
13911
13912             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13913                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13914                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13915
13916             _G.accInUse++;
13917             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13918             _G.accInUse--;
13919
13920             /* Sanity checking... */
13921             if (AOP_USESDPTR(IC_RESULT(ic)))
13922             {
13923                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13924                         "genReceive got unexpected DPTR.");
13925             }
13926             assignResultValue (IC_RESULT (ic), NULL);
13927         }
13928     }
13929     else if (ic->argreg > 12)
13930     { /* bit parameters */
13931       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13932         {
13933           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13934           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13935           outBitC(IC_RESULT (ic));
13936         }
13937     }
13938     else
13939     {
13940         /* second receive onwards */
13941         /* this gets a little tricky since unused receives will be
13942          eliminated, we have saved the reg in the type field . and
13943          we use that to figure out which register to use */
13944         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13945         rb1off = ic->argreg;
13946         while (size--)
13947         {
13948             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13949         }
13950     }
13951     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13952 }
13953
13954 /*-----------------------------------------------------------------*/
13955 /* genDummyRead - generate code for dummy read of volatiles        */
13956 /*-----------------------------------------------------------------*/
13957 static void
13958 genDummyRead (iCode * ic)
13959 {
13960   operand *op;
13961   int size, offset;
13962
13963   D (emitcode(";", "genDummyRead"));
13964
13965   op = IC_RIGHT (ic);
13966   if (op && IS_SYMOP (op))
13967     {
13968       aopOp (op, ic, FALSE, FALSE);
13969
13970       /* if the result is a bit */
13971       if (AOP_TYPE (op) == AOP_CRY)
13972         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13973       else
13974         {
13975           /* bit variables done */
13976           /* general case */
13977           size = AOP_SIZE (op);
13978           offset = 0;
13979           while (size--)
13980           {
13981             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13982             offset++;
13983           }
13984         }
13985
13986       freeAsmop (op, NULL, ic, TRUE);
13987     }
13988
13989   op = IC_LEFT (ic);
13990   if (op && IS_SYMOP (op))
13991     {
13992       aopOp (op, ic, FALSE, FALSE);
13993
13994       /* if the result is a bit */
13995       if (AOP_TYPE (op) == AOP_CRY)
13996         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13997       else
13998         {
13999           /* bit variables done */
14000           /* general case */
14001           size = AOP_SIZE (op);
14002           offset = 0;
14003           while (size--)
14004           {
14005             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14006             offset++;
14007           }
14008         }
14009
14010       freeAsmop (op, NULL, ic, TRUE);
14011     }
14012 }
14013
14014 /*-----------------------------------------------------------------*/
14015 /* genCritical - generate code for start of a critical sequence    */
14016 /*-----------------------------------------------------------------*/
14017 static void
14018 genCritical (iCode *ic)
14019 {
14020   symbol *tlbl = newiTempLabel (NULL);
14021
14022   D (emitcode(";", "genCritical"));
14023
14024   if (IC_RESULT (ic))
14025     {
14026       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14027       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14028       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14029       aopPut (IC_RESULT (ic), zero, 0);
14030       emitLabel (tlbl);
14031       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14032     }
14033   else
14034     {
14035       emitcode ("setb", "c");
14036       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14037       emitcode ("clr", "c");
14038       emitLabel (tlbl);
14039       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14040     }
14041 }
14042
14043 /*-----------------------------------------------------------------*/
14044 /* genEndCritical - generate code for end of a critical sequence   */
14045 /*-----------------------------------------------------------------*/
14046 static void
14047 genEndCritical (iCode *ic)
14048 {
14049   D(emitcode(";", "genEndCritical"));
14050
14051   if (IC_RIGHT (ic))
14052     {
14053       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14054       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14055         {
14056           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14057           emitcode ("mov", "ea,c");
14058         }
14059       else
14060         {
14061           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14062           emitcode ("rrc", "a");
14063           emitcode ("mov", "ea,c");
14064         }
14065       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14066     }
14067   else
14068     {
14069       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14070       emitcode ("mov", "ea,c");
14071     }
14072 }
14073
14074
14075
14076 /*-----------------------------------------------------------------*/
14077 /* genBuiltIn - calls the appropriate function to  generating code */
14078 /* for a built in function                                         */
14079 /*-----------------------------------------------------------------*/
14080 static void genBuiltIn (iCode *ic)
14081 {
14082         operand *bi_parms[MAX_BUILTIN_ARGS];
14083         int nbi_parms;
14084         iCode *bi_iCode;
14085         symbol *bif;
14086
14087         /* get all the arguments for a built in function */
14088         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14089
14090         /* which function is it */
14091         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14092         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14093                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14094         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14095                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14096         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14097                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14098         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14099                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14100         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14101                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14102         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14103                 genInp(bi_iCode,nbi_parms,bi_parms);
14104         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14105                 genOutp(bi_iCode,nbi_parms,bi_parms);
14106         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14107                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14108                 /* JavaNative builtIns */
14109         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14110                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14111         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14112                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14113         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14114                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14115         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14116                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14117         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14118                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14119         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14120                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14121         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14122                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14123         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14124                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14125         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14126                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14127         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14128                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14129         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14130                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14131         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14132                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14133         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14134                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14135         } else if (strcmp(bif->name,"MM_Free")==0) {
14136                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14137         } else if (strcmp(bif->name,"MM_Deref")==0) {
14138                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14139         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14140                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14141         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14142                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14143         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14144                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14145         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14146                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14147         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14148                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14149         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14150                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14151         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14152                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14153         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14154                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14155         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14156                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14157         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14158                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14159         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14160                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14161         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14162                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14163         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14164                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14165         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14166                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14167         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14168                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14169         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14170                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14171         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14172                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14173         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14174                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14175         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14176                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14177         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14178                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14179         } else {
14180                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14181                 return ;
14182         }
14183         return ;
14184 }
14185
14186 /*-----------------------------------------------------------------*/
14187 /* gen390Code - generate code for Dallas 390 based controllers     */
14188 /*-----------------------------------------------------------------*/
14189 void
14190 gen390Code (iCode * lic)
14191 {
14192   iCode *ic;
14193   int cln = 0;
14194
14195   _G.currentFunc = NULL;
14196   lineHead = lineCurr = NULL;
14197   dptrn[1][0] = "dpl1";
14198   dptrn[1][1] = "dph1";
14199   dptrn[1][2] = "dpx1";
14200
14201   if (options.model == MODEL_FLAT24) {
14202     fReturnSizeDS390 = 5;
14203     fReturn = fReturn24;
14204   } else {
14205     fReturnSizeDS390 = 4;
14206     fReturn = fReturn16;
14207     options.stack10bit=0;
14208   }
14209 #if 1
14210   /* print the allocation information */
14211   if (allocInfo && currFunc)
14212     printAllocInfo (currFunc, codeOutBuf);
14213 #endif
14214   /* if debug information required */
14215   if (options.debug && currFunc)
14216     {
14217       debugFile->writeFunction (currFunc, lic);
14218     }
14219   /* stack pointer name */
14220   if (options.useXstack)
14221     spname = "_spx";
14222   else
14223     spname = "sp";
14224
14225
14226   for (ic = lic; ic; ic = ic->next)
14227     {
14228       _G.current_iCode = ic;
14229
14230       if (ic->lineno && cln != ic->lineno)
14231         {
14232           if (options.debug)
14233             {
14234               debugFile->writeCLine (ic);
14235             }
14236           if (!options.noCcodeInAsm) {
14237             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14238                       printCLine(ic->filename, ic->lineno));
14239           }
14240           cln = ic->lineno;
14241         }
14242       if (options.iCodeInAsm) {
14243         char *iLine = printILine(ic);
14244         emitcode(";", "ic:%d: %s", ic->key, iLine);
14245         dbuf_free(iLine);
14246       }
14247       /* if the result is marked as
14248          spilt and rematerializable or code for
14249          this has already been generated then
14250          do nothing */
14251       if (resultRemat (ic) || ic->generated)
14252         continue;
14253
14254       /* depending on the operation */
14255       switch (ic->op)
14256         {
14257         case '!':
14258           genNot (ic);
14259           break;
14260
14261         case '~':
14262           genCpl (ic);
14263           break;
14264
14265         case UNARYMINUS:
14266           genUminus (ic);
14267           break;
14268
14269         case IPUSH:
14270           genIpush (ic);
14271           break;
14272
14273         case IPOP:
14274           /* IPOP happens only when trying to restore a
14275              spilt live range, if there is an ifx statement
14276              following this pop then the if statement might
14277              be using some of the registers being popped which
14278              would destory the contents of the register so
14279              we need to check for this condition and handle it */
14280           if (ic->next &&
14281               ic->next->op == IFX &&
14282               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14283             genIfx (ic->next, ic);
14284           else
14285             genIpop (ic);
14286           break;
14287
14288         case CALL:
14289           genCall (ic);
14290           break;
14291
14292         case PCALL:
14293           genPcall (ic);
14294           break;
14295
14296         case FUNCTION:
14297           genFunction (ic);
14298           break;
14299
14300         case ENDFUNCTION:
14301           genEndFunction (ic);
14302           break;
14303
14304         case RETURN:
14305           genRet (ic);
14306           break;
14307
14308         case LABEL:
14309           genLabel (ic);
14310           break;
14311
14312         case GOTO:
14313           genGoto (ic);
14314           break;
14315
14316         case '+':
14317           genPlus (ic);
14318           break;
14319
14320         case '-':
14321           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14322             genMinus (ic);
14323           break;
14324
14325         case '*':
14326           genMult (ic);
14327           break;
14328
14329         case '/':
14330           genDiv (ic);
14331           break;
14332
14333         case '%':
14334           genMod (ic);
14335           break;
14336
14337         case '>':
14338           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14339           break;
14340
14341         case '<':
14342           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14343           break;
14344
14345         case LE_OP:
14346         case GE_OP:
14347         case NE_OP:
14348
14349           /* note these two are xlated by algebraic equivalence
14350              during parsing SDCC.y */
14351           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14352                   "got '>=' or '<=' shouldn't have come here");
14353           break;
14354
14355         case EQ_OP:
14356           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14357           break;
14358
14359         case AND_OP:
14360           genAndOp (ic);
14361           break;
14362
14363         case OR_OP:
14364           genOrOp (ic);
14365           break;
14366
14367         case '^':
14368           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14369           break;
14370
14371         case '|':
14372           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14373           break;
14374
14375         case BITWISEAND:
14376           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14377           break;
14378
14379         case INLINEASM:
14380           genInline (ic);
14381           break;
14382
14383         case RRC:
14384           genRRC (ic);
14385           break;
14386
14387         case RLC:
14388           genRLC (ic);
14389           break;
14390
14391         case GETHBIT:
14392           genGetHbit (ic);
14393           break;
14394
14395         case LEFT_OP:
14396           genLeftShift (ic);
14397           break;
14398
14399         case RIGHT_OP:
14400           genRightShift (ic);
14401           break;
14402
14403         case GET_VALUE_AT_ADDRESS:
14404           genPointerGet (ic,
14405                          hasInc (IC_LEFT (ic), ic,
14406                                  getSize (operandType (IC_RESULT (ic)))));
14407           break;
14408
14409         case '=':
14410           if (POINTER_SET (ic))
14411             genPointerSet (ic,
14412                            hasInc (IC_RESULT (ic), ic,
14413                                    getSize (operandType (IC_RIGHT (ic)))));
14414           else
14415             genAssign (ic);
14416           break;
14417
14418         case IFX:
14419           genIfx (ic, NULL);
14420           break;
14421
14422         case ADDRESS_OF:
14423           genAddrOf (ic);
14424           break;
14425
14426         case JUMPTABLE:
14427           genJumpTab (ic);
14428           break;
14429
14430         case CAST:
14431           genCast (ic);
14432           break;
14433
14434         case RECEIVE:
14435           genReceive (ic);
14436           break;
14437
14438         case SEND:
14439           if (ic->builtinSEND)
14440             genBuiltIn(ic);
14441           else
14442             addSet (&_G.sendSet, ic);
14443           break;
14444
14445         case DUMMY_READ_VOLATILE:
14446           genDummyRead (ic);
14447           break;
14448
14449         case CRITICAL:
14450           genCritical (ic);
14451           break;
14452
14453         case ENDCRITICAL:
14454           genEndCritical (ic);
14455           break;
14456
14457         case SWAP:
14458           genSwap (ic);
14459           break;
14460
14461 #if 0 // obsolete, and buggy for != xdata
14462         case ARRAYINIT:
14463             genArrayInit(ic);
14464             break;
14465 #endif
14466
14467         default:
14468             /* This should never happen, right? */
14469             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n", 
14470                     ic->op, ic->op, __FILE__, __LINE__);
14471             ic = ic;
14472         }
14473     }
14474
14475
14476   /* now we are ready to call the
14477      peep hole optimizer */
14478   if (!options.nopeep)
14479     peepHole (&lineHead);
14480
14481   /* now do the actual printing */
14482   printLine (lineHead, codeOutBuf);
14483   return;
14484 }