* sim/ucsim/cmd.src/cmdutil.cc: NUL device is detected as CG_FILE type
[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) x
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 && *lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246     }
247
248   lineCurr->isInline = _G.inLine;
249   lineCurr->isDebug = _G.debugLine;
250   lineCurr->ic = _G.current_iCode;
251   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
252   lineCurr->isComment = (*lbp == ';');
253   va_end (ap);
254
255   dbuf_destroy(&dbuf);
256 }
257
258 static void
259 emitLabel (symbol *tlbl)
260 {
261   emitcode ("", "!tlabeldef", tlbl->key + 100);
262   lineCurr->isLabel = 1;
263 }
264
265 /*-----------------------------------------------------------------*/
266 /* ds390_emitDebuggerSymbol - associate the current code location  */
267 /*   with a debugger symbol                                        */
268 /*-----------------------------------------------------------------*/
269 void
270 ds390_emitDebuggerSymbol (char * debugSym)
271 {
272   _G.debugLine = 1;
273   emitcode ("", "%s ==.", debugSym);
274   _G.debugLine = 0;
275 }
276
277 /*-----------------------------------------------------------------*/
278 /* mova - moves specified value into accumulator                   */
279 /*-----------------------------------------------------------------*/
280 static void
281 mova (const char *x)
282 {
283   /* do some early peephole optimization */
284   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
285     return;
286
287   emitcode("mov", "a,%s", x);
288 }
289
290 /*-----------------------------------------------------------------*/
291 /* movb - moves specified value into register b                    */
292 /*-----------------------------------------------------------------*/
293 static void
294 movb (const char *x)
295 {
296   /* do some early peephole optimization */
297   if (!strncmp(x, "b", 2))
298     return;
299
300   emitcode("mov","b,%s", x);
301 }
302
303 /*-----------------------------------------------------------------*/
304 /* movc - moves specified value into the carry                     */
305 /*-----------------------------------------------------------------*/
306 static void
307 movc (const char *s)
308 {
309   if (s == zero)
310     CLRC;
311   else if (s == one)
312     SETC;
313   else if (strcmp (s, "c"))
314     {/* it's not in carry already */
315       MOVA (s);
316       /* set C, if a >= 1 */
317       emitcode ("add", "a,#0xff");
318     }
319 }
320
321 /*-----------------------------------------------------------------*/
322 /* pushB - saves register B if necessary                           */
323 /*-----------------------------------------------------------------*/
324 static bool
325 pushB (void)
326 {
327   bool pushedB = FALSE;
328
329   if (BINUSE)
330     {
331       emitcode ("push", "b");
332 //    printf("B was in use !\n");
333       pushedB = TRUE;
334     }
335   else
336     {
337       OPINB++;
338     }
339   return pushedB;
340 }
341
342 /*-----------------------------------------------------------------*/
343 /* popB - restores value of register B if necessary                */
344 /*-----------------------------------------------------------------*/
345 static void
346 popB (bool pushedB)
347 {
348   if (pushedB)
349     {
350       emitcode ("pop", "b");
351     }
352   else
353     {
354       OPINB--;
355     }
356 }
357
358 /*-----------------------------------------------------------------*/
359 /* pushReg - saves register                                        */
360 /*-----------------------------------------------------------------*/
361 static bool
362 pushReg (int index, bool bits_pushed)
363 {
364   regs * reg = REG_WITH_INDEX (index);
365   if (reg->type == REG_BIT)
366     {
367       if (!bits_pushed)
368         emitcode ("push", "%s", reg->base);
369       return TRUE;
370     }
371   else
372     emitcode ("push", "%s", reg->dname);
373   return bits_pushed;
374 }
375
376 /*-----------------------------------------------------------------*/
377 /* popReg - restores register                                      */
378 /*-----------------------------------------------------------------*/
379 static bool
380 popReg (int index, bool bits_popped)
381 {
382   regs * reg = REG_WITH_INDEX (index);
383   if (reg->type == REG_BIT)
384     {
385       if (!bits_popped)
386         emitcode ("pop", "%s", reg->base);
387       return TRUE;
388     }
389   else
390     emitcode ("pop", "%s", reg->dname);
391   return bits_popped;
392 }
393
394 /*-----------------------------------------------------------------*/
395 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
396 /*-----------------------------------------------------------------*/
397 static regs *
398 getFreePtr (iCode * ic, asmop ** aopp, bool result)
399 {
400   bool r0iu, r1iu;
401   bool r0ou, r1ou;
402
403   /* the logic: if r0 & r1 used in the instruction
404      then we are in trouble otherwise */
405
406   /* first check if r0 & r1 are used by this
407      instruction, in which case we are in trouble */
408   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
409   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
410   if (r0iu && r1iu) {
411       goto endOfWorld;
412     }
413
414   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
415   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
416
417   /* if no usage of r0 then return it */
418   if (!r0iu && !r0ou)
419     {
420       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
421       (*aopp)->type = AOP_R0;
422
423       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
424     }
425
426   /* if no usage of r1 then return it */
427   if (!r1iu && !r1ou)
428     {
429       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
430       (*aopp)->type = AOP_R1;
431
432       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
433     }
434
435   /* now we know they both have usage */
436   /* if r0 not used in this instruction */
437   if (!r0iu)
438     {
439       /* push it if not already pushed */
440       if (!_G.r0Pushed)
441         {
442           emitcode ("push", "%s",
443                     REG_WITH_INDEX (R0_IDX)->dname);
444           _G.r0Pushed++;
445         }
446
447       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
448       (*aopp)->type = AOP_R0;
449
450       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
451     }
452
453   /* if r1 not used then */
454
455   if (!r1iu)
456     {
457       /* push it if not already pushed */
458       if (!_G.r1Pushed)
459         {
460           emitcode ("push", "%s",
461                     REG_WITH_INDEX (R1_IDX)->dname);
462           _G.r1Pushed++;
463         }
464
465       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
466       (*aopp)->type = AOP_R1;
467       return REG_WITH_INDEX (R1_IDX);
468     }
469
470 endOfWorld:
471   /* I said end of world, but not quite end of world yet */
472   /* if this is a result then we can push it on the stack */
473   if (result)
474     {
475       (*aopp)->type = AOP_STK;
476       return NULL;
477     }
478
479   /* now this is REALLY the end of the world */
480   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
481           "getFreePtr should never reach here");
482   exit (1);
483
484   return NULL; // notreached, but makes compiler happy.
485 }
486
487
488 /*-----------------------------------------------------------------*/
489 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
490 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
491 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
492 /*-----------------------------------------------------------------*/
493 static void
494 genSetDPTR (int n)
495 {
496
497   /* If we are doing lazy evaluation, simply note the desired
498    * change, but don't emit any code yet.
499    */
500   if (_lazyDPS)
501     {
502       _desiredDPS = n;
503       return;
504     }
505
506   if (!n)
507     {
508       emitcode ("mov", "dps,#0");
509     }
510   else
511     {
512       TR_DPTR("#1");
513       emitcode ("mov", "dps,#1");
514     }
515 }
516
517 /*------------------------------------------------------------------*/
518 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
519 /*                                                                  */
520 /* Any code that operates on DPTR (NB: not on the individual        */
521 /* components, like DPH) *must* call _flushLazyDPS() before using   */
522 /* DPTR within a lazy DPS evaluation block.                         */
523 /*                                                                  */
524 /* Note that aopPut and aopGet already contain the proper calls to  */
525 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
526 /* DPS evaluation block.                                            */
527 /*                                                                  */
528 /* Also, _flushLazyDPS must be called before any flow control       */
529 /* operations that could potentially branch out of the block.       */
530 /*                                                                  */
531 /* Lazy DPS evaluation is simply an optimization (though an         */
532 /* important one), so if in doubt, leave it out.                    */
533 /*------------------------------------------------------------------*/
534 static void
535 _startLazyDPSEvaluation (void)
536 {
537   _currentDPS = 0;
538   _desiredDPS = 0;
539 #ifdef BETTER_LITERAL_SHIFT
540   _lazyDPS++;
541 #else
542   _lazyDPS = 1;
543 #endif
544 }
545
546 /*------------------------------------------------------------------*/
547 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
548 /* desired one. Call before using DPTR within a lazy DPS evaluation */
549 /* block.                                                           */
550 /*------------------------------------------------------------------*/
551 static void
552 _flushLazyDPS (void)
553 {
554   if (!_lazyDPS)
555     {
556       /* nothing to do. */
557       return;
558     }
559
560   if (_desiredDPS != _currentDPS)
561     {
562       if (_desiredDPS)
563         {
564           emitcode ("inc", "dps");
565         }
566       else
567         {
568           emitcode ("dec", "dps");
569         }
570       _currentDPS = _desiredDPS;
571     }
572 }
573
574 /*-----------------------------------------------------------------*/
575 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
576 /*                                                                 */
577 /* Forces us back to the safe state (standard DPTR selected).      */
578 /*-----------------------------------------------------------------*/
579 static void
580 _endLazyDPSEvaluation (void)
581 {
582 #ifdef BETTER_LITERAL_SHIFT
583   _lazyDPS--;
584 #else
585   _lazyDPS = 0;
586 #endif
587   if (!_lazyDPS)
588   {
589     if (_currentDPS)
590     {
591       genSetDPTR (0);
592       _flushLazyDPS ();
593     }
594     _currentDPS = 0;
595     _desiredDPS = 0;
596   }
597 }
598
599
600 /*-----------------------------------------------------------------*/
601 /* newAsmop - creates a new asmOp                                  */
602 /*-----------------------------------------------------------------*/
603 static asmop *
604 newAsmop (short type)
605 {
606   asmop *aop;
607
608   aop = Safe_calloc (1, sizeof (asmop));
609   aop->type = type;
610   aop->allocated = 1;
611   return aop;
612 }
613
614 /*-----------------------------------------------------------------*/
615 /* pointerCode - returns the code for a pointer type               */
616 /*-----------------------------------------------------------------*/
617 static int
618 pointerCode (sym_link * etype)
619 {
620
621   return PTR_TYPE (SPEC_OCLS (etype));
622
623 }
624
625 /*-----------------------------------------------------------------*/
626 /* leftRightUseAcc - returns size of accumulator use by operands   */
627 /*-----------------------------------------------------------------*/
628 static int
629 leftRightUseAcc(iCode *ic)
630 {
631   operand *op;
632   int size;
633   int accuseSize = 0;
634   int accuse = 0;
635
636   if (!ic)
637     {
638       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
639               "null iCode pointer");
640       return 0;
641     }
642
643   if (ic->op == IFX)
644     {
645       op = IC_COND (ic);
646       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
647         {
648           accuse = 1;
649           size = getSize (OP_SYMBOL (op)->type);
650           if (size>accuseSize)
651             accuseSize = size;
652         }
653     }
654   else if (ic->op == JUMPTABLE)
655     {
656       op = IC_JTCOND (ic);
657       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
658         {
659           accuse = 1;
660           size = getSize (OP_SYMBOL (op)->type);
661           if (size>accuseSize)
662             accuseSize = size;
663         }
664     }
665   else
666     {
667       op = IC_LEFT (ic);
668       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
669         {
670           accuse = 1;
671           size = getSize (OP_SYMBOL (op)->type);
672           if (size>accuseSize)
673             accuseSize = size;
674         }
675       op = IC_RIGHT (ic);
676       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
677         {
678           accuse = 1;
679           size = getSize (OP_SYMBOL (op)->type);
680           if (size>accuseSize)
681             accuseSize = size;
682         }
683     }
684
685   if (accuseSize)
686     return accuseSize;
687   else
688     return accuse;
689 }
690
691 /*-----------------------------------------------------------------*/
692 /* aopForSym - for a true symbol                                   */
693 /*-----------------------------------------------------------------*/
694 static asmop *
695 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
696 {
697   asmop *aop;
698   memmap *space;
699   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
700   char *dpl = useDP2 ? "dpl1" : "dpl";
701   char *dph = useDP2 ? "dph1" : "dph";
702   char *dpx = useDP2 ? "dpx1" : "dpx";
703
704   wassertl (ic != NULL, "Got a null iCode");
705   wassertl (sym != NULL, "Got a null symbol");
706
707   space = SPEC_OCLS (sym->etype);
708
709   /* if already has one */
710   if (sym->aop)
711     {
712       if ((sym->aop->type == AOP_DPTR && useDP2)
713           || (sym->aop->type == AOP_DPTR2 && !useDP2))
714         sym->aop = NULL;
715       else
716         {
717           sym->aop->allocated++;
718           return sym->aop;
719         }
720     }
721
722   /* assign depending on the storage class */
723   /* if it is on the stack or indirectly addressable */
724   /* space we need to assign either r0 or r1 to it   */
725   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
726     {
727       sym->aop = aop = newAsmop (0);
728       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
729       aop->size = getSize (sym->type);
730
731       /* now assign the address of the variable to
732          the pointer register */
733       if (aop->type != AOP_STK)
734         {
735           if (sym->onStack)
736             {
737               signed char offset = ((sym->stack < 0) ?
738                          ((signed char) (sym->stack - _G.nRegsSaved)) :
739                          ((signed char) sym->stack)) & 0xff;
740
741               if ((abs(offset) <= 3) ||
742                   (accuse && (abs(offset) <= 7)))
743                 {
744                   emitcode ("mov", "%s,_bp",
745                             aop->aopu.aop_ptr->name);
746                   while (offset < 0)
747                     {
748                       emitcode ("dec", aop->aopu.aop_ptr->name);
749                       offset++;
750                     }
751                   while (offset > 0)
752                     {
753                       emitcode ("inc", aop->aopu.aop_ptr->name);
754                       offset--;
755                     }
756                 }
757               else
758                 {
759                   if (accuse)
760                     emitcode ("push", "acc");
761                   emitcode ("mov", "a,_bp");
762                   emitcode ("add", "a,#!constbyte", offset);
763                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
764                   if (accuse)
765                     emitcode ("pop", "acc");
766                 }
767             }
768           else
769             {
770               emitcode ("mov", "%s,#%s",
771                         aop->aopu.aop_ptr->name,
772                         sym->rname);
773             }
774           aop->paged = space->paged;
775         }
776       else
777         aop->aopu.aop_stk = sym->stack;
778       return aop;
779     }
780
781   if (sym->onStack && options.stack10bit)
782     {
783       short stack_val = -((sym->stack < 0) ?
784                           ((short) (sym->stack - _G.nRegsSaved)) :
785                           ((short) sym->stack)) ;
786       if (_G.dptrInUse ) {
787           emitcode ("push",dpl);
788           emitcode ("push",dph);
789           emitcode ("push",dpx);
790       }
791       /* It's on the 10 bit stack, which is located in
792        * far data space.
793        */
794       if (stack_val < 0 && stack_val > -5)
795         { /* between -5 & -1 */
796           if (options.model == MODEL_FLAT24)
797             {
798               emitcode ("mov", "%s,#!constbyte", dpx,
799                         (options.stack_loc >> 16) & 0xff);
800             }
801           emitcode ("mov", "%s,_bpx+1", dph);
802           emitcode ("mov", "%s,_bpx", dpl);
803           if (useDP2) {
804               emitcode ("mov","dps,#1");
805           }
806           stack_val = -stack_val;
807           while (stack_val--) {
808               emitcode ("inc","dptr");
809           }
810           if (useDP2) {
811               emitcode("mov","dps,#0");
812           }
813         }
814       else
815         {
816           if (accuse)
817               emitcode ("push", "acc");
818
819           emitcode ("mov", "a,_bpx");
820           emitcode ("clr","c");
821           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
822           emitcode ("mov","%s,a", dpl);
823           emitcode ("mov","a,_bpx+1");
824           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
825           emitcode ("mov", "%s,a", dph);
826           if (options.model == MODEL_FLAT24)
827             {
828               emitcode ("mov", "%s,#!constbyte", dpx,
829                         (options.stack_loc >> 16) & 0xff);
830             }
831
832           if (accuse)
833               emitcode ("pop", "acc");
834         }
835       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
836       aop->size = getSize (sym->type);
837       return aop;
838     }
839
840   /* if in bit space */
841   if (IN_BITSPACE (space))
842     {
843       sym->aop = aop = newAsmop (AOP_CRY);
844       aop->aopu.aop_dir = sym->rname;
845       aop->size = getSize (sym->type);
846       return aop;
847     }
848   /* if it is in direct space */
849   if (IN_DIRSPACE (space))
850     {
851       sym->aop = aop = newAsmop (AOP_DIR);
852       aop->aopu.aop_dir = sym->rname;
853       aop->size = getSize (sym->type);
854       return aop;
855     }
856
857   /* special case for a function */
858   if (IS_FUNC (sym->type) && !(sym->isitmp))
859     {
860       sym->aop = aop = newAsmop (AOP_IMMD);
861       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
862       aop->size = FPTRSIZE;
863       return aop;
864     }
865
866   /* only remaining is far space */
867   /* in which case DPTR gets the address */
868   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
869   if (useDP2)
870     {
871       genSetDPTR (1);
872       _flushLazyDPS ();
873       emitcode ("mov", "dptr,#%s", sym->rname);
874       genSetDPTR (0);
875     }
876   else
877     {
878       emitcode ("mov", "dptr,#%s", sym->rname);
879     }
880   aop->size = getSize (sym->type);
881
882   /* if it is in code space */
883   if (IN_CODESPACE (space))
884     aop->code = 1;
885
886   return aop;
887 }
888
889 /*-----------------------------------------------------------------*/
890 /* aopForRemat - rematerialzes an object                           */
891 /*-----------------------------------------------------------------*/
892 static asmop *
893 aopForRemat (symbol * sym)
894 {
895   iCode *ic = sym->rematiCode;
896   asmop *aop = newAsmop (AOP_IMMD);
897   int ptr_type = 0;
898   int val = 0;
899
900   for (;;)
901     {
902       if (ic->op == '+')
903         val += (int) operandLitValue (IC_RIGHT (ic));
904       else if (ic->op == '-')
905         val -= (int) operandLitValue (IC_RIGHT (ic));
906       else if (IS_CAST_ICODE(ic)) {
907               sym_link *from_type = operandType(IC_RIGHT(ic));
908               aop->aopu.aop_immd.from_cast_remat = 1;
909               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
910               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
911               continue;
912       } else break;
913
914       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
915     }
916
917   if (val)
918   {
919       SNPRINTF (buffer, sizeof(buffer),
920                 "(%s %c 0x%06x)",
921                 OP_SYMBOL (IC_LEFT (ic))->rname,
922                 val >= 0 ? '+' : '-',
923                 abs (val) & 0xffffff);
924   }
925   else
926   {
927       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
928       {
929           SNPRINTF(buffer, sizeof(buffer),
930                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
931       }
932       else
933       {
934           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
935       }
936   }
937
938   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
939   /* set immd2 field if required */
940   if (aop->aopu.aop_immd.from_cast_remat)
941   {
942       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
943       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
944   }
945
946   return aop;
947 }
948
949 /*-----------------------------------------------------------------*/
950 /* aopHasRegs - returns true if aop has regs between from-to       */
951 /*-----------------------------------------------------------------*/
952 static int aopHasRegs(asmop *aop, int from, int to)
953 {
954     int size =0;
955
956     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
957
958     for (; size < aop->size ; size++) {
959         int reg;
960         for (reg = from ; reg <= to ; reg++)
961             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
962     }
963     return 0;
964 }
965
966 /*-----------------------------------------------------------------*/
967 /* regsInCommon - two operands have some registers in common       */
968 /*-----------------------------------------------------------------*/
969 static bool
970 regsInCommon (operand * op1, operand * op2)
971 {
972   symbol *sym1, *sym2;
973   int i;
974
975   /* if they have registers in common */
976   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
977     return FALSE;
978
979   sym1 = OP_SYMBOL (op1);
980   sym2 = OP_SYMBOL (op2);
981
982   if (sym1->nRegs == 0 || sym2->nRegs == 0)
983     return FALSE;
984
985   for (i = 0; i < sym1->nRegs; i++)
986     {
987       int j;
988       if (!sym1->regs[i])
989         continue;
990
991       for (j = 0; j < sym2->nRegs; j++)
992         {
993           if (!sym2->regs[j])
994             continue;
995
996           if (sym2->regs[j] == sym1->regs[i])
997             return TRUE;
998         }
999     }
1000
1001   return FALSE;
1002 }
1003
1004 /*-----------------------------------------------------------------*/
1005 /* operandsEqu - equivalent                                        */
1006 /*-----------------------------------------------------------------*/
1007 static bool
1008 operandsEqu (operand * op1, operand * op2)
1009 {
1010   symbol *sym1, *sym2;
1011
1012   /* if they're not symbols */
1013   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1014     return FALSE;
1015
1016   sym1 = OP_SYMBOL (op1);
1017   sym2 = OP_SYMBOL (op2);
1018
1019   /* if both are itemps & one is spilt
1020      and the other is not then false */
1021   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1022       sym1->isspilt != sym2->isspilt)
1023     return FALSE;
1024
1025   /* if they are the same */
1026   if (sym1 == sym2)
1027     return TRUE;
1028
1029   /* if they have the same rname */
1030   if (sym1->rname[0] && sym2->rname[0] &&
1031       strcmp (sym1->rname, sym2->rname) == 0 &&
1032       !(IS_PARM (op2) && IS_ITEMP (op1)))
1033     return TRUE;
1034
1035   /* if left is a tmp & right is not */
1036   if (IS_ITEMP (op1) &&
1037       !IS_ITEMP (op2) &&
1038       sym1->isspilt &&
1039       (sym1->usl.spillLoc == sym2))
1040     return TRUE;
1041
1042   if (IS_ITEMP (op2) &&
1043       !IS_ITEMP (op1) &&
1044       sym2->isspilt &&
1045       sym1->level > 0 &&
1046       (sym2->usl.spillLoc == sym1))
1047     return TRUE;
1048
1049   /* are they spilt to the same location */
1050   if (IS_ITEMP (op2) &&
1051       IS_ITEMP (op1) &&
1052       sym2->isspilt &&
1053       sym1->isspilt &&
1054       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1055     return TRUE;
1056
1057   return FALSE;
1058 }
1059
1060 /*-----------------------------------------------------------------*/
1061 /* sameRegs - two asmops have the same registers                   */
1062 /*-----------------------------------------------------------------*/
1063 static bool
1064 sameRegs (asmop * aop1, asmop * aop2)
1065 {
1066   int i;
1067
1068   if (aop1 == aop2)
1069     {
1070       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1071         {
1072           return FALSE;
1073         }
1074       return TRUE;
1075     }
1076
1077   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1078     return FALSE;
1079
1080   if (aop1->type != aop2->type)
1081     return FALSE;
1082
1083   if (aop1->size != aop2->size)
1084     return FALSE;
1085
1086   for (i = 0; i < aop1->size; i++)
1087     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1088       return FALSE;
1089
1090   return TRUE;
1091 }
1092
1093 /*-----------------------------------------------------------------*/
1094 /* aopOp - allocates an asmop for an operand  :                    */
1095 /*-----------------------------------------------------------------*/
1096 static void
1097 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1098 {
1099   asmop *aop;
1100   symbol *sym;
1101   int i;
1102
1103   if (!op)
1104     return;
1105
1106   /* if this a literal */
1107   if (IS_OP_LITERAL (op))
1108     {
1109       op->aop = aop = newAsmop (AOP_LIT);
1110       aop->aopu.aop_lit = op->operand.valOperand;
1111       aop->size = getSize (operandType (op));
1112       return;
1113     }
1114
1115   /* if already has a asmop then continue */
1116   if (op->aop)
1117     {
1118       if ((op->aop->type == AOP_DPTR && useDP2)
1119           || (op->aop->type == AOP_DPTR2 && !useDP2))
1120         op->aop = NULL;
1121       else
1122         {
1123           op->aop->allocated++;
1124           return;
1125         }
1126     }
1127
1128   /* if the underlying symbol has a aop */
1129   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1130     {
1131       op->aop = OP_SYMBOL (op)->aop;
1132       if ((op->aop->type == AOP_DPTR && useDP2)
1133           || (op->aop->type == AOP_DPTR2 && !useDP2))
1134         op->aop = NULL;
1135       else
1136         {
1137           op->aop->allocated++;
1138           return;
1139         }
1140     }
1141
1142   /* if this is a true symbol */
1143   if (IS_TRUE_SYMOP (op))
1144     {
1145       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1146       return;
1147     }
1148
1149   /* this is a temporary : this has
1150      only five choices :
1151      a) register
1152      b) spillocation
1153      c) rematerialize
1154      d) conditional
1155      e) can be a return use only */
1156
1157   sym = OP_SYMBOL (op);
1158
1159   /* if the type is a conditional */
1160   if (sym->regType == REG_CND)
1161     {
1162       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1163       aop->size = 0;
1164       return;
1165     }
1166
1167   /* if it is spilt then two situations
1168      a) is rematerialize
1169      b) has a spill location */
1170   if (sym->isspilt || sym->nRegs == 0)
1171     {
1172
1173       /* rematerialize it NOW */
1174       if (sym->remat)
1175         {
1176           sym->aop = op->aop = aop =
1177             aopForRemat (sym);
1178           aop->size = getSize (sym->type);
1179           return;
1180         }
1181
1182       if (sym->accuse)
1183         {
1184           int i;
1185           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1186           aop->size = getSize (sym->type);
1187           for (i = 0; i < 2; i++)
1188             aop->aopu.aop_str[i] = accUse[i];
1189           return;
1190         }
1191
1192       if (sym->ruonly)
1193         {
1194           unsigned i;
1195
1196           if (useDP2)
1197             {
1198               /* a AOP_STR uses DPTR, but DPTR is already in use;
1199                * we're just hosed.
1200                */
1201                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1202             }
1203
1204           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1205           aop->size = getSize (sym->type);
1206           for (i = 0; i < fReturnSizeDS390; i++)
1207             aop->aopu.aop_str[i] = fReturn[i];
1208           return;
1209         }
1210
1211       if (sym->dptr) { /* has been allocated to a DPTRn */
1212           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1213           aop->size = getSize (sym->type);
1214           aop->aopu.dptr = sym->dptr;
1215           return ;
1216       }
1217
1218       if (sym->usl.spillLoc)
1219         {
1220           asmop *oldAsmOp = NULL;
1221
1222           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1223             {
1224               /* force a new aop if sizes differ */
1225               oldAsmOp = sym->usl.spillLoc->aop;
1226               sym->usl.spillLoc->aop = NULL;
1227             }
1228           sym->aop = op->aop = aop =
1229                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1230           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1231             {
1232               /* Don't reuse the new aop, go with the last one */
1233               sym->usl.spillLoc->aop = oldAsmOp;
1234             }
1235           aop->size = getSize (sym->type);
1236           return;
1237         }
1238
1239       /* else must be a dummy iTemp */
1240       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1241       aop->size = getSize (sym->type);
1242       return;
1243     }
1244
1245   /* if the type is a bit register */
1246   if (sym->regType == REG_BIT)
1247     {
1248       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1249       aop->size = sym->nRegs;//1???
1250       aop->aopu.aop_reg[0] = sym->regs[0];
1251       aop->aopu.aop_dir = sym->regs[0]->name;
1252       return;
1253     }
1254
1255   /* must be in a register */
1256   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1257   aop->size = sym->nRegs;
1258   for (i = 0; i < sym->nRegs; i++)
1259     aop->aopu.aop_reg[i] = sym->regs[i];
1260 }
1261
1262 /*-----------------------------------------------------------------*/
1263 /* freeAsmop - free up the asmop given to an operand               */
1264 /*----------------------------------------------------------------*/
1265 static void
1266 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1267 {
1268   asmop *aop;
1269
1270   if (!op)
1271     aop = aaop;
1272   else
1273     aop = op->aop;
1274
1275   if (!aop)
1276     return;
1277
1278   aop->allocated--;
1279
1280   if (aop->allocated)
1281     goto dealloc;
1282
1283   /* depending on the asmop type only three cases need work
1284      AOP_R0, AOP_R1 & AOP_STK */
1285   switch (aop->type)
1286     {
1287     case AOP_R0:
1288       if (_G.r0Pushed)
1289         {
1290           if (pop)
1291             {
1292               emitcode ("pop", "ar0");
1293               _G.r0Pushed--;
1294             }
1295         }
1296       bitVectUnSetBit (ic->rUsed, R0_IDX);
1297       break;
1298
1299     case AOP_R1:
1300       if (_G.r1Pushed)
1301         {
1302           if (pop)
1303             {
1304               emitcode ("pop", "ar1");
1305               _G.r1Pushed--;
1306             }
1307         }
1308       bitVectUnSetBit (ic->rUsed, R1_IDX);
1309       break;
1310
1311     case AOP_STK:
1312       {
1313         int sz = aop->size;
1314         int stk = aop->aopu.aop_stk + aop->size;
1315         bitVectUnSetBit (ic->rUsed, R0_IDX);
1316         bitVectUnSetBit (ic->rUsed, R1_IDX);
1317
1318         getFreePtr (ic, &aop, FALSE);
1319
1320         if (options.stack10bit)
1321           {
1322             /* I'm not sure what to do here yet... */
1323             /* #STUB */
1324             fprintf (stderr,
1325                      "*** Warning: probably generating bad code for "
1326                      "10 bit stack mode.\n");
1327           }
1328
1329         if (stk)
1330           {
1331             emitcode ("mov", "a,_bp");
1332             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1333             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1334           }
1335         else
1336           {
1337             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1338           }
1339
1340         while (sz--)
1341           {
1342             emitcode ("pop", "acc");
1343             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1344             if (!sz)
1345               break;
1346             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1347           }
1348         op->aop = aop;
1349         freeAsmop (op, NULL, ic, TRUE);
1350         if (_G.r1Pushed)
1351           {
1352             emitcode ("pop", "ar1");
1353             _G.r1Pushed--;
1354           }
1355         if (_G.r0Pushed)
1356           {
1357             emitcode ("pop", "ar0");
1358             _G.r0Pushed--;
1359           }
1360       }
1361     case AOP_DPTR2:
1362         if (_G.dptr1InUse) {
1363             emitcode ("pop","dpx1");
1364             emitcode ("pop","dph1");
1365             emitcode ("pop","dpl1");
1366         }
1367         break;
1368     case AOP_DPTR:
1369         if (_G.dptrInUse) {
1370             emitcode ("pop","dpx");
1371             emitcode ("pop","dph");
1372             emitcode ("pop","dpl");
1373         }
1374         break;
1375     }
1376
1377 dealloc:
1378   /* all other cases just dealloc */
1379   if (op)
1380     {
1381       op->aop = NULL;
1382       if (IS_SYMOP (op))
1383         {
1384           OP_SYMBOL (op)->aop = NULL;
1385           /* if the symbol has a spill */
1386           if (SPIL_LOC (op))
1387             SPIL_LOC (op)->aop = NULL;
1388         }
1389     }
1390 }
1391
1392 #define DEFAULT_ACC_WARNING 0
1393 static int saveAccWarn = DEFAULT_ACC_WARNING;
1394
1395
1396 /*-----------------------------------------------------------------*/
1397 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1398 /*                 clobber the accumulator                         */
1399 /*-----------------------------------------------------------------*/
1400 static bool
1401 aopGetUsesAcc (operand * oper, int offset)
1402 {
1403   asmop * aop = AOP (oper);
1404
1405   if (offset > (aop->size - 1))
1406     return FALSE;
1407
1408   switch (aop->type)
1409     {
1410
1411     case AOP_R0:
1412     case AOP_R1:
1413       if (aop->paged)
1414         return TRUE;
1415       return FALSE;
1416     case AOP_DPTR:
1417     case AOP_DPTR2:
1418     case AOP_DPTRn:
1419       return TRUE;
1420     case AOP_IMMD:
1421       return FALSE;
1422     case AOP_DIR:
1423       return FALSE;
1424     case AOP_REG:
1425       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1426       return FALSE;
1427     case AOP_CRY:
1428       return TRUE;
1429     case AOP_ACC:
1430       if (offset)
1431         return FALSE;
1432       return TRUE;
1433     case AOP_LIT:
1434       return FALSE;
1435     case AOP_STR:
1436       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1437         return TRUE;
1438       return FALSE;
1439     case AOP_DUMMY:
1440       return FALSE;
1441     default:
1442       /* Error case --- will have been caught already */
1443       wassert(0);
1444       return FALSE;
1445     }
1446 }
1447
1448 /*-------------------------------------------------------------------*/
1449 /* aopGet - for fetching value of the aop                            */
1450 /*                                                                   */
1451 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1452 /* in the accumulator. Set it to the name of a free register         */
1453 /* if acc must be preserved; the register will be used to preserve   */
1454 /* acc temporarily and to return the result byte.                    */
1455 /*-------------------------------------------------------------------*/
1456 static char *
1457 aopGet (operand * oper,
1458         int   offset,
1459         bool  bit16,
1460         bool  dname,
1461         char  *saveAcc)
1462 {
1463   asmop * aop = AOP (oper);
1464
1465   /* offset is greater than
1466      size then zero */
1467   if (offset > (aop->size - 1) &&
1468       aop->type != AOP_LIT)
1469     return zero;
1470
1471   /* depending on type */
1472   switch (aop->type)
1473     {
1474     case AOP_DUMMY:
1475       return zero;
1476
1477     case AOP_R0:
1478     case AOP_R1:
1479       /* if we need to increment it */
1480       while (offset > aop->coff)
1481         {
1482           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1483           aop->coff++;
1484         }
1485
1486       while (offset < aop->coff)
1487         {
1488           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1489           aop->coff--;
1490         }
1491
1492       aop->coff = offset;
1493       if (aop->paged)
1494         {
1495           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1496           return (dname ? "acc" : "a");
1497         }
1498       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1499       return Safe_strdup(buffer);
1500
1501     case AOP_DPTRn:
1502         assert(offset <= 3);
1503         return dptrn[aop->aopu.dptr][offset];
1504
1505     case AOP_DPTR:
1506     case AOP_DPTR2:
1507
1508       if (aop->type == AOP_DPTR2)
1509         {
1510           genSetDPTR (1);
1511         }
1512
1513       if (saveAcc)
1514         {
1515             TR_AP("#1");
1516 //          if (aop->type != AOP_DPTR2)
1517 //          {
1518 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1519 //              emitcode(";", "spanky: saveAcc for DPTR");
1520 //          }
1521
1522             emitcode ("xch", "a, %s", saveAcc);
1523         }
1524
1525       _flushLazyDPS ();
1526
1527       while (offset > aop->coff)
1528         {
1529           emitcode ("inc", "dptr");
1530           aop->coff++;
1531         }
1532
1533       while (offset < aop->coff)
1534         {
1535           emitcode ("lcall", "__decdptr");
1536           aop->coff--;
1537         }
1538
1539       aop->coff = offset;
1540       if (aop->code)
1541         {
1542           emitcode ("clr", "a");
1543           emitcode ("movc", "a,@a+dptr");
1544         }
1545       else
1546         {
1547           emitcode ("movx", "a,@dptr");
1548         }
1549
1550       if (aop->type == AOP_DPTR2)
1551         {
1552           genSetDPTR (0);
1553         }
1554
1555       if (saveAcc)
1556         {
1557           TR_AP("#2");
1558           emitcode ("xch", "a, %s", saveAcc);
1559 //        if (strcmp(saveAcc, "_ap"))
1560 //          {
1561 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1562 //          }
1563
1564           return saveAcc;
1565         }
1566       return (dname ? "acc" : "a");
1567
1568     case AOP_IMMD:
1569       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1570         {
1571           SNPRINTF(buffer, sizeof(buffer),
1572                    "%s",aop->aopu.aop_immd.aop_immd2);
1573         }
1574       else if (bit16)
1575         {
1576           SNPRINTF(buffer, sizeof(buffer),
1577                    "#%s", aop->aopu.aop_immd.aop_immd1);
1578         }
1579       else if (offset)
1580         {
1581           switch (offset) {
1582           case 1:
1583               tsprintf(buffer, sizeof(buffer),
1584                        "#!his",aop->aopu.aop_immd.aop_immd1);
1585               break;
1586           case 2:
1587               tsprintf(buffer, sizeof(buffer),
1588                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1589               break;
1590           case 3:
1591               tsprintf(buffer, sizeof(buffer),
1592                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1593               break;
1594           default: /* should not need this (just in case) */
1595               SNPRINTF (buffer, sizeof(buffer),
1596                         "#(%s >> %d)",
1597                        aop->aopu.aop_immd.aop_immd1,
1598                        offset * 8);
1599           }
1600         }
1601       else
1602         {
1603           SNPRINTF (buffer, sizeof(buffer),
1604                     "#%s",
1605                     aop->aopu.aop_immd.aop_immd1);
1606         }
1607       return Safe_strdup(buffer);
1608
1609     case AOP_DIR:
1610       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1611         {
1612           SNPRINTF (buffer, sizeof(buffer),
1613                     "(%s >> %d)",
1614                     aop->aopu.aop_dir, offset * 8);
1615         }
1616       else if (offset)
1617         {
1618           SNPRINTF (buffer, sizeof(buffer),
1619                     "(%s + %d)",
1620                    aop->aopu.aop_dir,
1621                    offset);
1622         }
1623       else
1624         {
1625           SNPRINTF (buffer, sizeof(buffer),
1626                     "%s",
1627                     aop->aopu.aop_dir);
1628         }
1629
1630       return Safe_strdup(buffer);
1631
1632     case AOP_REG:
1633       if (dname)
1634         return aop->aopu.aop_reg[offset]->dname;
1635       else
1636         return aop->aopu.aop_reg[offset]->name;
1637
1638     case AOP_CRY:
1639       emitcode ("clr", "a");
1640       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1641       emitcode ("rlc", "a");
1642       return (dname ? "acc" : "a");
1643
1644     case AOP_ACC:
1645       if (!offset && dname)
1646         return "acc";
1647       return aop->aopu.aop_str[offset];
1648
1649     case AOP_LIT:
1650       return aopLiteral (aop->aopu.aop_lit, offset);
1651
1652     case AOP_STR:
1653       aop->coff = offset;
1654       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1655           dname)
1656         return "acc";
1657
1658       return aop->aopu.aop_str[offset];
1659
1660     }
1661
1662   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1663           "aopget got unsupported aop->type");
1664   exit (1);
1665
1666   return NULL;  // not reached, but makes compiler happy.
1667 }
1668
1669 /*-----------------------------------------------------------------*/
1670 /* aopPut - puts a string for a aop and indicates if acc is in use */
1671 /*-----------------------------------------------------------------*/
1672 static bool
1673 aopPut (operand * result, const char *s, int offset)
1674 {
1675   bool bvolatile = isOperandVolatile (result, FALSE);
1676   bool accuse = FALSE;
1677   asmop * aop = AOP (result);
1678
1679   if (aop->size && offset > (aop->size - 1))
1680     {
1681       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1682               "aopPut got offset > aop->size");
1683       exit (1);
1684     }
1685
1686   /* will assign value to value */
1687   /* depending on where it is ofcourse */
1688   switch (aop->type)
1689     {
1690     case AOP_DUMMY:
1691       MOVA (s);         /* read s in case it was volatile */
1692       accuse = TRUE;
1693       break;
1694
1695     case AOP_DIR:
1696       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1697         {
1698           SNPRINTF (buffer, sizeof(buffer),
1699                     "(%s >> %d)",
1700                     aop->aopu.aop_dir, offset * 8);
1701         }
1702       else if (offset)
1703         {
1704           SNPRINTF (buffer, sizeof(buffer),
1705                     "(%s + %d)",
1706                     aop->aopu.aop_dir, offset);
1707         }
1708       else
1709         {
1710           SNPRINTF (buffer, sizeof(buffer),
1711                     "%s",
1712                     aop->aopu.aop_dir);
1713         }
1714
1715       if (strcmp (buffer, s) || bvolatile)
1716         {
1717           emitcode ("mov", "%s,%s", buffer, s);
1718         }
1719       if (!strcmp (buffer, "acc"))
1720         {
1721           accuse = TRUE;
1722         }
1723       break;
1724
1725     case AOP_REG:
1726       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1727           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1728         {
1729           if (*s == '@' ||
1730               strcmp (s, "r0") == 0 ||
1731               strcmp (s, "r1") == 0 ||
1732               strcmp (s, "r2") == 0 ||
1733               strcmp (s, "r3") == 0 ||
1734               strcmp (s, "r4") == 0 ||
1735               strcmp (s, "r5") == 0 ||
1736               strcmp (s, "r6") == 0 ||
1737               strcmp (s, "r7") == 0)
1738             {
1739               emitcode ("mov", "%s,%s",
1740                         aop->aopu.aop_reg[offset]->dname, s);
1741             }
1742             else
1743             {
1744               emitcode ("mov", "%s,%s",
1745                         aop->aopu.aop_reg[offset]->name, s);
1746             }
1747         }
1748       break;
1749
1750     case AOP_DPTRn:
1751         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1752         break;
1753
1754     case AOP_DPTR:
1755     case AOP_DPTR2:
1756
1757       if (aop->type == AOP_DPTR2)
1758         {
1759           genSetDPTR (1);
1760         }
1761       _flushLazyDPS ();
1762
1763       if (aop->code)
1764         {
1765           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1766                   "aopPut writing to code space");
1767           exit (1);
1768         }
1769
1770       while (offset > aop->coff)
1771         {
1772           aop->coff++;
1773           emitcode ("inc", "dptr");
1774         }
1775
1776       while (offset < aop->coff)
1777         {
1778           aop->coff--;
1779           emitcode ("lcall", "__decdptr");
1780         }
1781
1782       aop->coff = offset;
1783
1784       /* if not in accumulator */
1785       MOVA (s);
1786
1787       emitcode ("movx", "@dptr,a");
1788
1789       if (aop->type == AOP_DPTR2)
1790         {
1791           genSetDPTR (0);
1792         }
1793       break;
1794
1795     case AOP_R0:
1796     case AOP_R1:
1797       while (offset > aop->coff)
1798         {
1799           aop->coff++;
1800           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1801         }
1802       while (offset < aop->coff)
1803         {
1804           aop->coff--;
1805           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1806         }
1807       aop->coff = offset;
1808
1809       if (aop->paged)
1810         {
1811           MOVA (s);
1812           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1813         }
1814       else if (*s == '@')
1815         {
1816           MOVA (s);
1817           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1818         }
1819       else if (strcmp (s, "r0") == 0 ||
1820                strcmp (s, "r1") == 0 ||
1821                strcmp (s, "r2") == 0 ||
1822                strcmp (s, "r3") == 0 ||
1823                strcmp (s, "r4") == 0 ||
1824                strcmp (s, "r5") == 0 ||
1825                strcmp (s, "r6") == 0 ||
1826                strcmp (s, "r7") == 0)
1827         {
1828           char buffer[10];
1829           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1830           emitcode ("mov", "@%s,%s",
1831                     aop->aopu.aop_ptr->name, buffer);
1832         }
1833         else
1834         {
1835             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1836         }
1837       break;
1838
1839     case AOP_STK:
1840       if (strcmp (s, "a") == 0)
1841         emitcode ("push", "acc");
1842       else
1843         if (*s=='@') {
1844           MOVA(s);
1845           emitcode ("push", "acc");
1846         } else {
1847           emitcode ("push", s);
1848         }
1849
1850       break;
1851
1852     case AOP_CRY:
1853       /* if not bit variable */
1854       if (!aop->aopu.aop_dir)
1855         {
1856           /* inefficient: move carry into A and use jz/jnz */
1857           emitcode ("clr", "a");
1858           emitcode ("rlc", "a");
1859           accuse = TRUE;
1860         }
1861       else
1862         {
1863           if (s == zero)
1864             emitcode ("clr", "%s", aop->aopu.aop_dir);
1865           else if (s == one)
1866             emitcode ("setb", "%s", aop->aopu.aop_dir);
1867           else if (!strcmp (s, "c"))
1868             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1869           else if (strcmp (s, aop->aopu.aop_dir))
1870             {
1871               MOVA (s);
1872               /* set C, if a >= 1 */
1873               emitcode ("add", "a,#!constbyte",0xff);
1874               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1875             }
1876         }
1877       break;
1878
1879     case AOP_STR:
1880       aop->coff = offset;
1881       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1882         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1883       break;
1884
1885     case AOP_ACC:
1886       accuse = TRUE;
1887       aop->coff = offset;
1888       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1889         break;
1890
1891       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1892         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1893       break;
1894
1895     default:
1896       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1897               "aopPut got unsupported aop->type");
1898       exit (1);
1899     }
1900
1901     return accuse;
1902 }
1903
1904
1905 /*--------------------------------------------------------------------*/
1906 /* reAdjustPreg - points a register back to where it should (coff==0) */
1907 /*--------------------------------------------------------------------*/
1908 static void
1909 reAdjustPreg (asmop * aop)
1910 {
1911   if ((aop->coff==0) || (aop->size <= 1))
1912     return;
1913
1914   switch (aop->type)
1915     {
1916     case AOP_R0:
1917     case AOP_R1:
1918       while (aop->coff--)
1919         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1920       break;
1921     case AOP_DPTR:
1922     case AOP_DPTR2:
1923       if (aop->type == AOP_DPTR2)
1924         {
1925           genSetDPTR (1);
1926           _flushLazyDPS ();
1927         }
1928       while (aop->coff--)
1929         {
1930           emitcode ("lcall", "__decdptr");
1931         }
1932
1933       if (aop->type == AOP_DPTR2)
1934         {
1935           genSetDPTR (0);
1936         }
1937       break;
1938     }
1939   aop->coff = 0;
1940 }
1941
1942 /*-----------------------------------------------------------------*/
1943 /* opIsGptr: returns non-zero if the passed operand is       */
1944 /* a generic pointer type.             */
1945 /*-----------------------------------------------------------------*/
1946 static int
1947 opIsGptr (operand * op)
1948 {
1949   sym_link *type = operandType (op);
1950
1951   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1952     {
1953       return 1;
1954     }
1955   return 0;
1956 }
1957
1958 /*-----------------------------------------------------------------*/
1959 /* getDataSize - get the operand data size                         */
1960 /*-----------------------------------------------------------------*/
1961 static int
1962 getDataSize (operand * op)
1963 {
1964   int size;
1965   size = AOP_SIZE (op);
1966   if (size == GPTRSIZE)
1967     {
1968       sym_link *type = operandType (op);
1969       if (IS_GENPTR (type))
1970         {
1971           /* generic pointer; arithmetic operations
1972            * should ignore the high byte (pointer type).
1973            */
1974           size--;
1975         }
1976     }
1977   return size;
1978 }
1979
1980 /*-----------------------------------------------------------------*/
1981 /* outAcc - output Acc                                             */
1982 /*-----------------------------------------------------------------*/
1983 static void
1984 outAcc (operand * result)
1985 {
1986   int size, offset;
1987   size = getDataSize (result);
1988   if (size)
1989     {
1990       aopPut (result, "a", 0);
1991       size--;
1992       offset = 1;
1993       /* unsigned or positive */
1994       while (size--)
1995         {
1996           aopPut (result, zero, offset++);
1997         }
1998     }
1999 }
2000
2001 /*-----------------------------------------------------------------*/
2002 /* outBitC - output a bit C                                        */
2003 /*-----------------------------------------------------------------*/
2004 static void
2005 outBitC (operand * result)
2006 {
2007   /* if the result is bit */
2008   if (AOP_TYPE (result) == AOP_CRY)
2009     {
2010       aopPut (result, "c", 0);
2011     }
2012   else
2013     {
2014       emitcode ("clr", "a");
2015       emitcode ("rlc", "a");
2016       outAcc (result);
2017     }
2018 }
2019
2020 /*-----------------------------------------------------------------*/
2021 /* toBoolean - emit code for orl a,operator(sizeop)                */
2022 /*-----------------------------------------------------------------*/
2023 static void
2024 toBoolean (operand * oper)
2025 {
2026   int  size = AOP_SIZE (oper) - 1;
2027   int  offset = 1;
2028   bool pushedB;
2029
2030   /* The generic part of a generic pointer should
2031    * not participate in it's truth value.
2032    *
2033    * i.e. 0x10000000 is zero.
2034    */
2035   if (opIsGptr (oper))
2036     {
2037       D (emitcode (";", "toBoolean: generic ptr special case."));
2038       size--;
2039     }
2040
2041   _startLazyDPSEvaluation ();
2042   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2043   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2044     {
2045       pushedB = pushB ();
2046       emitcode("mov", "b,a");
2047       while (--size)
2048         {
2049           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2050           emitcode ("orl", "b,a");
2051         }
2052       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2053       emitcode ("orl", "a,b");
2054       popB (pushedB);
2055     }
2056   else
2057     {
2058       while (size--)
2059         {
2060           emitcode ("orl", "a,%s",
2061                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2062         }
2063     }
2064   _endLazyDPSEvaluation ();
2065 }
2066
2067
2068 /*-----------------------------------------------------------------*/
2069 /* genNot - generate code for ! operation                          */
2070 /*-----------------------------------------------------------------*/
2071 static void
2072 genNot (iCode * ic)
2073 {
2074   symbol *tlbl;
2075
2076   D (emitcode (";", "genNot"));
2077
2078   /* assign asmOps to operand & result */
2079   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2080   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2081
2082   /* if in bit space then a special case */
2083   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2084     {
2085       /* if left==result then cpl bit */
2086       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2087         {
2088           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2089         }
2090       else
2091         {
2092           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2093           emitcode ("cpl", "c");
2094           outBitC (IC_RESULT (ic));
2095         }
2096       goto release;
2097     }
2098
2099   toBoolean (IC_LEFT (ic));
2100
2101   /* set C, if a == 0 */
2102   tlbl = newiTempLabel (NULL);
2103   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2104   emitLabel (tlbl);
2105   outBitC (IC_RESULT (ic));
2106
2107 release:
2108   /* release the aops */
2109   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2110   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2111 }
2112
2113
2114 /*-----------------------------------------------------------------*/
2115 /* genCpl - generate code for complement                           */
2116 /*-----------------------------------------------------------------*/
2117 static void
2118 genCpl (iCode * ic)
2119 {
2120   int offset = 0;
2121   int size;
2122   symbol *tlbl;
2123   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2124
2125   D(emitcode (";", "genCpl"));
2126
2127   /* assign asmOps to operand & result */
2128   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2129   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2130
2131   /* special case if in bit space */
2132   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2133     {
2134       char *l;
2135
2136       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2137           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2138         {
2139           /* promotion rules are responsible for this strange result:
2140              bit -> int -> ~int -> bit
2141              uchar -> int -> ~int -> bit
2142           */
2143           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2144           goto release;
2145         }
2146
2147       tlbl=newiTempLabel(NULL);
2148       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2149       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2150           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2151           IS_AOP_PREG (IC_LEFT (ic)))
2152         {
2153           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2154         }
2155       else
2156         {
2157           MOVA (l);
2158           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2159         }
2160       emitLabel (tlbl);
2161       outBitC (IC_RESULT(ic));
2162       goto release;
2163     }
2164
2165   size = AOP_SIZE (IC_RESULT (ic));
2166   _startLazyDPSEvaluation ();
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2170       MOVA (l);
2171       emitcode ("cpl", "a");
2172       aopPut (IC_RESULT (ic), "a", offset++);
2173     }
2174   _endLazyDPSEvaluation ();
2175
2176
2177 release:
2178   /* release the aops */
2179   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2180   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2181 }
2182
2183 /*-----------------------------------------------------------------*/
2184 /* genUminusFloat - unary minus for floating points                */
2185 /*-----------------------------------------------------------------*/
2186 static void
2187 genUminusFloat (operand * op, operand * result)
2188 {
2189   int size, offset = 0;
2190   char *l;
2191
2192   D (emitcode (";", "genUminusFloat"));
2193
2194   /* for this we just copy and then flip the bit */
2195
2196   _startLazyDPSEvaluation ();
2197   size = AOP_SIZE (op) - 1;
2198
2199   while (size--)
2200     {
2201       aopPut (result,
2202               aopGet (op, offset, FALSE, FALSE, NULL),
2203               offset);
2204       offset++;
2205     }
2206
2207   l = aopGet (op, offset, FALSE, FALSE, NULL);
2208   MOVA (l);
2209
2210   emitcode ("cpl", "acc.7");
2211   aopPut (result, "a", offset);
2212   _endLazyDPSEvaluation ();
2213 }
2214
2215 /*-----------------------------------------------------------------*/
2216 /* genUminus - unary minus code generation                         */
2217 /*-----------------------------------------------------------------*/
2218 static void
2219 genUminus (iCode * ic)
2220 {
2221   int offset, size;
2222   sym_link *optype;
2223
2224   D (emitcode (";", "genUminus"));
2225
2226   /* assign asmops */
2227   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2228   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2229
2230   /* if both in bit space then special
2231      case */
2232   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2233       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2234     {
2235
2236       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2237       emitcode ("cpl", "c");
2238       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2239       goto release;
2240     }
2241
2242   optype = operandType (IC_LEFT (ic));
2243
2244   /* if float then do float stuff */
2245   if (IS_FLOAT (optype))
2246     {
2247       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2248       goto release;
2249     }
2250
2251   /* otherwise subtract from zero */
2252   size = AOP_SIZE (IC_LEFT (ic));
2253   offset = 0;
2254   _startLazyDPSEvaluation ();
2255   while (size--)
2256     {
2257       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2258       if (!strcmp (l, "a"))
2259         {
2260           if (offset == 0)
2261             SETC;
2262           emitcode ("cpl", "a");
2263           emitcode ("addc", "a,#0");
2264         }
2265       else
2266         {
2267           if (offset == 0)
2268             CLRC;
2269           emitcode ("clr", "a");
2270           emitcode ("subb", "a,%s", l);
2271         }
2272       aopPut (IC_RESULT (ic), "a", offset++);
2273     }
2274   _endLazyDPSEvaluation ();
2275
2276   /* if any remaining bytes in the result */
2277   /* we just need to propagate the sign   */
2278   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2279     {
2280       emitcode ("rlc", "a");
2281       emitcode ("subb", "a,acc");
2282       while (size--)
2283         aopPut (IC_RESULT (ic), "a", offset++);
2284     }
2285
2286 release:
2287   /* release the aops */
2288   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2289   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2290 }
2291
2292 /*-----------------------------------------------------------------*/
2293 /* savermask - saves registers in the mask                         */
2294 /*-----------------------------------------------------------------*/
2295 static void savermask(bitVect *rs_mask)
2296 {
2297   int i;
2298
2299   if (options.useXstack)
2300     {
2301       if (bitVectBitValue (rs_mask, R0_IDX))
2302           emitcode ("mov", "b,r0");
2303       emitcode ("mov", "r0,%s", spname);
2304       for (i = 0; i < ds390_nRegs; i++)
2305         {
2306           if (bitVectBitValue (rs_mask, i))
2307             {
2308               if (i == R0_IDX)
2309                   emitcode ("mov", "a,b");
2310               else
2311                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2312               emitcode ("movx", "@r0,a");
2313               emitcode ("inc", "r0");
2314             }
2315         }
2316       emitcode ("mov", "%s,r0", spname);
2317       if (bitVectBitValue (rs_mask, R0_IDX))
2318           emitcode ("mov", "r0,b");
2319     }
2320   else
2321     {
2322       bool bits_pushed = FALSE;
2323       for (i = 0; i < ds390_nRegs; i++)
2324         {
2325           if (bitVectBitValue (rs_mask, i))
2326             {
2327               bits_pushed = pushReg (i, bits_pushed);
2328             }
2329         }
2330     }
2331 }
2332
2333 /*-----------------------------------------------------------------*/
2334 /* saveRegisters - will look for a call and save the registers     */
2335 /*-----------------------------------------------------------------*/
2336 static void
2337 saveRegisters (iCode * lic)
2338 {
2339   iCode *ic;
2340   bitVect *rsave;
2341
2342   /* look for call */
2343   for (ic = lic; ic; ic = ic->next)
2344     if (ic->op == CALL || ic->op == PCALL)
2345       break;
2346
2347   if (!ic)
2348     {
2349       fprintf (stderr, "found parameter push with no function call\n");
2350       return;
2351     }
2352
2353   /* if the registers have been saved already or don't need to be then
2354      do nothing */
2355   if (ic->regsSaved
2356       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2357     return;
2358
2359   /* special case if DPTR alive across a function call then must save it
2360      even though callee saves */
2361   if (IS_SYMOP(IC_LEFT(ic)) &&
2362       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2363     {
2364       int i;
2365       rsave = newBitVect(ic->rMask->size);
2366       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2367           if (bitVectBitValue(ic->rMask,i))
2368               rsave = bitVectSetBit(rsave,i);
2369       }
2370       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2371     }
2372   else
2373     {
2374       /* save the registers in use at this time but skip the
2375          ones for the result */
2376       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2377                              ds390_rUmaskForOp (IC_RESULT(ic)));
2378     }
2379   ic->regsSaved = 1;
2380   savermask(rsave);
2381 }
2382
2383 /*-----------------------------------------------------------------*/
2384 /* usavermask - restore registers with mask                        */
2385 /*-----------------------------------------------------------------*/
2386 static void unsavermask(bitVect *rs_mask)
2387 {
2388   int i;
2389
2390   if (options.useXstack)
2391     {
2392       emitcode ("mov", "r0,%s", spname);
2393       for (i = ds390_nRegs; i >= 0; i--)
2394         {
2395           if (bitVectBitValue (rs_mask, i))
2396             {
2397               regs * reg = REG_WITH_INDEX (i);
2398               emitcode ("dec", "r0");
2399               emitcode ("movx", "a,@r0");
2400               if (i == R0_IDX)
2401                 {
2402                   emitcode ("push", "acc");
2403                 }
2404               else
2405                 {
2406                   emitcode ("mov", "%s,a", reg->name);
2407                 }
2408             }
2409         }
2410       emitcode ("mov", "%s,r0", spname);
2411       if (bitVectBitValue (rs_mask, R0_IDX))
2412         {
2413           emitcode ("pop", "ar0");
2414         }
2415     }
2416   else
2417     {
2418       bool bits_popped = FALSE;
2419       for (i = ds390_nRegs; i >= 0; i--)
2420         {
2421           if (bitVectBitValue (rs_mask, i))
2422             {
2423               bits_popped = popReg (i, bits_popped);
2424             }
2425         }
2426     }
2427 }
2428
2429 /*-----------------------------------------------------------------*/
2430 /* unsaveRegisters - pop the pushed registers                      */
2431 /*-----------------------------------------------------------------*/
2432 static void
2433 unsaveRegisters (iCode * ic)
2434 {
2435   bitVect *rsave;
2436
2437   if (IS_SYMOP(IC_LEFT (ic)) &&
2438       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2439       int i;
2440       rsave = newBitVect(ic->rMask->size);
2441       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2442           if (bitVectBitValue(ic->rMask,i))
2443               rsave = bitVectSetBit(rsave,i);
2444       }
2445       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2446   } else {
2447     /* restore the registers in use at this time but skip the
2448        ones for the result */
2449     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2450                            ds390_rUmaskForOp (IC_RESULT(ic)));
2451   }
2452   unsavermask(rsave);
2453 }
2454
2455
2456 /*-----------------------------------------------------------------*/
2457 /* pushSide -                */
2458 /*-----------------------------------------------------------------*/
2459 static void
2460 pushSide (operand * oper, int size)
2461 {
2462   int offset = 0;
2463   _startLazyDPSEvaluation ();
2464   while (size--)
2465     {
2466       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2467       if (AOP_TYPE (oper) != AOP_REG &&
2468           AOP_TYPE (oper) != AOP_DIR &&
2469           strcmp (l, "a"))
2470         {
2471           MOVA (l);
2472           emitcode ("push", "acc");
2473         }
2474       else
2475         {
2476           emitcode ("push", "%s", l);
2477         }
2478     }
2479   _endLazyDPSEvaluation ();
2480 }
2481
2482 /*-----------------------------------------------------------------*/
2483 /* assignResultValue - also indicates if acc is in use afterwards  */
2484 /*-----------------------------------------------------------------*/
2485 static bool
2486 assignResultValue (operand * oper, operand * func)
2487 {
2488   int offset = 0;
2489   unsigned size = AOP_SIZE (oper);
2490   bool accuse = FALSE;
2491   bool pushedA = FALSE;
2492
2493   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2494     {
2495       outBitC (oper);
2496       return FALSE;
2497     }
2498
2499   if (size == fReturnSizeDS390)
2500   {
2501       /* I don't think this case can ever happen... */
2502       /* ACC is the last part of this. If writing the result
2503        * uses ACC, we must preserve it.
2504        */
2505       if (AOP_NEEDSACC(oper))
2506       {
2507           emitcode(";", "assignResultValue special case for ACC.");
2508           emitcode("push", "acc");
2509           pushedA = TRUE;
2510           size--;
2511       }
2512   }
2513
2514   _startLazyDPSEvaluation ();
2515   while (size--)
2516     {
2517       accuse |= aopPut (oper, fReturn[offset], offset);
2518       offset++;
2519     }
2520   _endLazyDPSEvaluation ();
2521
2522   if (pushedA)
2523     {
2524         emitcode ("pop", "acc");
2525         accuse |= aopPut (oper, "a", offset);
2526     }
2527   return accuse;
2528 }
2529
2530
2531 /*-----------------------------------------------------------------*/
2532 /* genXpush - pushes onto the external stack                       */
2533 /*-----------------------------------------------------------------*/
2534 static void
2535 genXpush (iCode * ic)
2536 {
2537   asmop *aop = newAsmop (0);
2538   regs *r;
2539   int size, offset = 0;
2540
2541   D (emitcode (";", "genXpush"));
2542
2543   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2544   r = getFreePtr (ic, &aop, FALSE);
2545
2546   size = AOP_SIZE (IC_LEFT (ic));
2547
2548   if (size == 1)
2549     {
2550       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2551       emitcode ("mov", "%s,_spx", r->name);
2552       emitcode ("inc", "_spx"); // allocate space first
2553       emitcode ("movx", "@%s,a", r->name);
2554     }
2555   else
2556     {
2557       // allocate space first
2558       emitcode ("mov", "%s,_spx", r->name);
2559       MOVA (r->name);
2560       emitcode ("add", "a,#%d", size);
2561       emitcode ("mov", "_spx,a");
2562
2563       _startLazyDPSEvaluation ();
2564       while (size--)
2565         {
2566           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2567           emitcode ("movx", "@%s,a", r->name);
2568           emitcode ("inc", "%s", r->name);
2569         }
2570       _endLazyDPSEvaluation ();
2571     }
2572
2573   freeAsmop (NULL, aop, ic, TRUE);
2574   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2575 }
2576
2577 /*-----------------------------------------------------------------*/
2578 /* genIpush - generate code for pushing this gets a little complex  */
2579 /*-----------------------------------------------------------------*/
2580 static void
2581 genIpush (iCode * ic)
2582 {
2583   int size, offset = 0;
2584   char *l;
2585   char *prev = "";
2586
2587   D (emitcode (";", "genIpush"));
2588
2589   /* if this is not a parm push : ie. it is spill push
2590      and spill push is always done on the local stack */
2591   if (!ic->parmPush)
2592     {
2593
2594       /* and the item is spilt then do nothing */
2595       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2596         return;
2597
2598       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2599       size = AOP_SIZE (IC_LEFT (ic));
2600       /* push it on the stack */
2601       _startLazyDPSEvaluation ();
2602       while (size--)
2603         {
2604           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2605           if (*l == '#')
2606             {
2607               MOVA (l);
2608               l = "acc";
2609             }
2610           emitcode ("push", "%s", l);
2611         }
2612       _endLazyDPSEvaluation ();
2613       return;
2614     }
2615
2616   /* this is a parameter push: in this case we call
2617      the routine to find the call and save those
2618      registers that need to be saved */
2619   saveRegisters (ic);
2620
2621   /* if use external stack then call the external
2622      stack pushing routine */
2623   if (options.useXstack)
2624     {
2625       genXpush (ic);
2626       return;
2627     }
2628
2629   /* then do the push */
2630   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2631
2632   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2633   size = AOP_SIZE (IC_LEFT (ic));
2634
2635   _startLazyDPSEvaluation ();
2636   while (size--)
2637     {
2638       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2639       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2640           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2641           strcmp (l, "acc"))
2642         {
2643           if (strcmp (l, prev) || *l == '@')
2644             MOVA (l);
2645           emitcode ("push", "acc");
2646         }
2647       else
2648         {
2649             emitcode ("push", "%s", l);
2650         }
2651       prev = l;
2652     }
2653   _endLazyDPSEvaluation ();
2654
2655   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2656 }
2657
2658 /*-----------------------------------------------------------------*/
2659 /* genIpop - recover the registers: can happen only for spilling   */
2660 /*-----------------------------------------------------------------*/
2661 static void
2662 genIpop (iCode * ic)
2663 {
2664   int size, offset;
2665
2666   D (emitcode (";", "genIpop"));
2667
2668   /* if the temp was not pushed then */
2669   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2670     return;
2671
2672   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2673   size = AOP_SIZE (IC_LEFT (ic));
2674   offset = (size - 1);
2675   _startLazyDPSEvaluation ();
2676   while (size--)
2677     {
2678       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2679                                      FALSE, TRUE, NULL));
2680     }
2681   _endLazyDPSEvaluation ();
2682
2683   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2684 }
2685
2686 /*-----------------------------------------------------------------*/
2687 /* saveRBank - saves an entire register bank on the stack          */
2688 /*-----------------------------------------------------------------*/
2689 static void
2690 saveRBank (int bank, iCode * ic, bool pushPsw)
2691 {
2692   int i;
2693   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2694   asmop *aop = NULL;
2695   regs *r = NULL;
2696
2697   if (options.useXstack)
2698     {
2699       if (!ic)
2700         {
2701           /* Assume r0 is available for use. */
2702           r = REG_WITH_INDEX (R0_IDX);;
2703         }
2704       else
2705         {
2706           aop = newAsmop (0);
2707           r = getFreePtr (ic, &aop, FALSE);
2708         }
2709       // allocate space first
2710       emitcode ("mov", "%s,_spx", r->name);
2711       MOVA (r->name);
2712       emitcode ("add", "a,#%d", count);
2713       emitcode ("mov", "_spx,a");
2714     }
2715
2716   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2717     {
2718       if (options.useXstack)
2719         {
2720           emitcode ("mov", "a,(%s+%d)",
2721                     regs390[i].base, 8 * bank + regs390[i].offset);
2722           emitcode ("movx", "@%s,a", r->name);
2723           if (--count)
2724             emitcode ("inc", "%s", r->name);
2725         }
2726       else
2727         emitcode ("push", "(%s+%d)",
2728                   regs390[i].base, 8 * bank + regs390[i].offset);
2729     }
2730
2731   if (ds390_nBitRegs > 0)
2732     {
2733       if (options.useXstack)
2734         {
2735           emitcode ("mov", "a,bits");
2736           emitcode ("movx", "@%s,a", r->name);
2737           if (--count)
2738             emitcode ("inc", "%s", r->name);
2739         }
2740       else
2741         {
2742           emitcode ("push", "bits");
2743         }
2744       BitBankUsed = 1;
2745     }
2746
2747   if (pushPsw)
2748     {
2749       if (options.useXstack)
2750         {
2751           emitcode ("mov", "a,psw");
2752           emitcode ("movx", "@%s,a", r->name);
2753         }
2754       else
2755       {
2756         emitcode ("push", "psw");
2757       }
2758
2759       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2760     }
2761
2762   if (aop)
2763     {
2764       freeAsmop (NULL, aop, ic, TRUE);
2765     }
2766
2767   if (ic)
2768   {
2769     ic->bankSaved = 1;
2770   }
2771 }
2772
2773 /*-----------------------------------------------------------------*/
2774 /* unsaveRBank - restores the register bank from stack             */
2775 /*-----------------------------------------------------------------*/
2776 static void
2777 unsaveRBank (int bank, iCode * ic, bool popPsw)
2778 {
2779   int i;
2780   asmop *aop = NULL;
2781   regs *r = NULL;
2782
2783   if (options.useXstack)
2784     {
2785       if (!ic)
2786         {
2787           /* Assume r0 is available for use. */
2788           r = REG_WITH_INDEX (R0_IDX);;
2789         }
2790       else
2791         {
2792           aop = newAsmop (0);
2793           r = getFreePtr (ic, &aop, FALSE);
2794         }
2795       emitcode ("mov", "%s,_spx", r->name);
2796     }
2797
2798   if (popPsw)
2799     {
2800       if (options.useXstack)
2801         {
2802           emitcode ("dec", "%s", r->name);
2803           emitcode ("movx", "a,@%s", r->name);
2804           emitcode ("mov", "psw,a");
2805         }
2806       else
2807       {
2808         emitcode ("pop", "psw");
2809       }
2810     }
2811
2812   if (ds390_nBitRegs > 0)
2813     {
2814       if (options.useXstack)
2815         {
2816           emitcode ("dec", "%s", r->name);
2817           emitcode ("movx", "a,@%s", r->name);
2818           emitcode ("mov", "bits,a");
2819         }
2820       else
2821         {
2822           emitcode ("pop", "bits");
2823         }
2824     }
2825
2826   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2827     {
2828       if (options.useXstack)
2829         {
2830           emitcode ("dec", "%s", r->name);
2831           emitcode ("movx", "a,@%s", r->name);
2832           emitcode ("mov", "(%s+%d),a",
2833                     regs390[i].base, 8 * bank + regs390[i].offset);
2834         }
2835       else
2836         {
2837           emitcode ("pop", "(%s+%d)",
2838                     regs390[i].base, 8 * bank + regs390[i].offset);
2839         }
2840     }
2841
2842   if (options.useXstack)
2843     {
2844       emitcode ("mov", "_spx,%s", r->name);
2845     }
2846
2847   if (aop)
2848     {
2849       freeAsmop (NULL, aop, ic, TRUE);
2850     }
2851 }
2852
2853 /*-----------------------------------------------------------------*/
2854 /* genSend - gen code for SEND                                     */
2855 /*-----------------------------------------------------------------*/
2856 static void genSend(set *sendSet)
2857 {
2858   iCode *sic;
2859   int bit_count = 0;
2860   int sendCount = 0 ;
2861   static int rb1_count = 0;
2862
2863   /* first we do all bit parameters */
2864   for (sic = setFirstItem (sendSet); sic;
2865        sic = setNextItem (sendSet))
2866     {
2867       if (sic->argreg > 12)
2868         {
2869           int bit = sic->argreg-13;
2870
2871           aopOp (IC_LEFT (sic), sic, FALSE,
2872                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2873
2874           /* if left is a literal then
2875              we know what the value is */
2876           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2877             {
2878               if (((int) operandLitValue (IC_LEFT (sic))))
2879                   emitcode ("setb", "b[%d]", bit);
2880               else
2881                   emitcode ("clr", "b[%d]", bit);
2882             }
2883           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2884             {
2885               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2886                 if (strcmp (l, "c"))
2887                     emitcode ("mov", "c,%s", l);
2888                 emitcode ("mov", "b[%d],c", bit);
2889             }
2890           else
2891             {
2892               /* we need to or */
2893               toBoolean (IC_LEFT (sic));
2894               /* set C, if a >= 1 */
2895               emitcode ("add", "a,#0xff");
2896               emitcode ("mov", "b[%d],c", bit);
2897             }
2898           bit_count++;
2899           BitBankUsed = 1;
2900
2901           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2902         }
2903     }
2904
2905   if (bit_count)
2906     {
2907       saveRegisters (setFirstItem (sendSet));
2908       emitcode ("mov", "bits,b");
2909     }
2910
2911   /* then we do all other parameters */
2912   for (sic = setFirstItem (sendSet); sic;
2913        sic = setNextItem (sendSet))
2914     {
2915       if (sic->argreg <= 12)
2916       {
2917         int size, offset = 0;
2918
2919         size = getSize (operandType (IC_LEFT (sic)));
2920         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2921         if (sendCount == 0) { /* first parameter */
2922             // we know that dpl(hxb) is the result, so
2923             rb1_count = 0 ;
2924             _startLazyDPSEvaluation ();
2925             if (size>1) {
2926                 aopOp (IC_LEFT (sic), sic, FALSE,
2927                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2928             } else {
2929                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2930             }
2931             while (size--)
2932               {
2933                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2934                 if (strcmp (l, fReturn[offset]))
2935                   {
2936                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2937                   }
2938                 offset++;
2939               }
2940             _endLazyDPSEvaluation ();
2941             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2942             rb1_count =0;
2943         } else { /* if more parameter in registers */
2944             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2945             while (size--) {
2946                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2947                                                                 FALSE, FALSE, NULL));
2948             }
2949             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2950         }
2951         sendCount++;
2952       }
2953     }
2954 }
2955
2956 static void
2957 adjustEsp(const char *reg)
2958 {
2959     emitcode ("anl","%s,#3", reg);
2960     if (TARGET_IS_DS400)
2961     {
2962         emitcode ("orl","%s,#!constbyte",
2963                   reg,
2964                   (options.stack_loc >> 8) & 0xff);
2965     }
2966 }
2967
2968 /*-----------------------------------------------------------------*/
2969 /* selectRegBank - emit code to select the register bank           */
2970 /*-----------------------------------------------------------------*/
2971 static void
2972 selectRegBank (short bank, bool keepFlags)
2973 {
2974   /* if f.e. result is in carry */
2975   if (keepFlags)
2976     {
2977       emitcode ("anl", "psw,#0xE7");
2978       if (bank)
2979         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2980     }
2981   else
2982     {
2983       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2984     }
2985 }
2986
2987 /*-----------------------------------------------------------------*/
2988 /* genCall - generates a call statement                            */
2989 /*-----------------------------------------------------------------*/
2990 static void
2991 genCall (iCode * ic)
2992 {
2993   sym_link *dtype;
2994   sym_link *etype;
2995   bool restoreBank = FALSE;
2996   bool swapBanks = FALSE;
2997   bool accuse = FALSE;
2998   bool accPushed = FALSE;
2999   bool resultInF0 = FALSE;
3000   bool assignResultGenerated = FALSE;
3001
3002   D (emitcode (";", "genCall"));
3003
3004   /* if we are calling a not _naked function that is not using
3005      the same register bank then we need to save the
3006      destination registers on the stack */
3007   dtype = operandType (IC_LEFT (ic));
3008   etype = getSpec(dtype);
3009   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3010       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3011       IFFUNC_ISISR (currFunc->type))
3012   {
3013       if (!ic->bankSaved)
3014       {
3015            /* This is unexpected; the bank should have been saved in
3016             * genFunction.
3017             */
3018            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3019            restoreBank = TRUE;
3020       }
3021       swapBanks = TRUE;
3022   }
3023
3024   /* if caller saves & we have not saved then */
3025   if (!ic->regsSaved)
3026       saveRegisters (ic);
3027
3028   /* if send set is not empty then assign */
3029   /* We've saved all the registers we care about;
3030   * therefore, we may clobber any register not used
3031   * in the calling convention (i.e. anything not in
3032   * fReturn.
3033   */
3034   if (_G.sendSet)
3035     {
3036         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3037             genSend(reverseSet(_G.sendSet));
3038         } else {
3039             genSend(_G.sendSet);
3040         }
3041       _G.sendSet = NULL;
3042     }
3043
3044   if (swapBanks)
3045     {
3046       emitcode ("mov", "psw,#!constbyte",
3047          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3048     }
3049
3050   /* make the call */
3051   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3052                             OP_SYMBOL (IC_LEFT (ic))->rname :
3053                             OP_SYMBOL (IC_LEFT (ic))->name));
3054
3055   if (swapBanks)
3056     {
3057       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3058     }
3059
3060   /* if we need assign a result value */
3061   if ((IS_ITEMP (IC_RESULT (ic)) &&
3062        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3063        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3064         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3065         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3066       IS_TRUE_SYMOP (IC_RESULT (ic)))
3067     {
3068       if (isOperandInFarSpace (IC_RESULT (ic))
3069           && getSize (operandType (IC_RESULT (ic))) <= 2)
3070         {
3071           int size = getSize (operandType (IC_RESULT (ic)));
3072           bool pushedB = FALSE;
3073
3074           /* Special case for 1 or 2 byte return in far space. */
3075           MOVA (fReturn[0]);
3076           if (size > 1)
3077             {
3078               pushedB = pushB ();
3079               emitcode ("mov", "b,%s", fReturn[1]);
3080             }
3081
3082           _G.accInUse++;
3083           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3084           _G.accInUse--;
3085
3086           popB (pushedB);
3087
3088           aopPut (IC_RESULT (ic), "a", 0);
3089
3090           if (size > 1)
3091             {
3092               aopPut (IC_RESULT (ic), "b", 1);
3093             }
3094           assignResultGenerated = TRUE;
3095           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3096         }
3097       else
3098         {
3099           bool pushedB = pushB ();
3100           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3101           popB (pushedB);
3102
3103           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3104           assignResultGenerated = TRUE;
3105           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3106         }
3107     }
3108
3109   /* adjust the stack for parameters if required */
3110   if (ic->parmBytes)
3111     {
3112       int i;
3113       if (options.stack10bit) {
3114           if (ic->parmBytes <= 10) {
3115               emitcode(";","stack adjustment for parms");
3116               for (i=0; i < ic->parmBytes ; i++) {
3117                   emitcode("pop","acc");
3118               }
3119           } else {
3120               PROTECT_SP;
3121               emitcode ("clr","c");
3122               emitcode ("mov","a,sp");
3123               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3124               emitcode ("mov","sp,a");
3125               emitcode ("mov","a,esp");
3126               adjustEsp("a");
3127               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3128               emitcode ("mov","esp,a");
3129               UNPROTECT_SP;
3130           }
3131       } else {
3132           if (ic->parmBytes > 3)
3133             {
3134               if (accuse)
3135                 {
3136                   emitcode ("push", "acc");
3137                   accPushed = TRUE;
3138                 }
3139               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3140                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3141                   !assignResultGenerated)
3142                 {
3143                   emitcode ("mov", "F0,c");
3144                   resultInF0 = TRUE;
3145                 }
3146
3147               emitcode ("mov", "a,%s", spname);
3148               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3149               emitcode ("mov", "%s,a", spname);
3150
3151               /* unsaveRegisters from xstack needs acc, but */
3152               /* unsaveRegisters from stack needs this popped */
3153               if (accPushed && !options.useXstack)
3154                 {
3155                   emitcode ("pop", "acc");
3156                   accPushed = FALSE;
3157                 }
3158             }
3159           else
3160               for (i = 0; i < ic->parmBytes; i++)
3161                   emitcode ("dec", "%s", spname);
3162       }
3163   }
3164
3165   /* if we had saved some registers then unsave them */
3166   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3167     {
3168       if (accuse && !accPushed && options.useXstack)
3169         {
3170           /* xstack needs acc, but doesn't touch normal stack */
3171           emitcode ("push", "acc");
3172           accPushed = TRUE;
3173         }
3174       unsaveRegisters (ic);
3175     }
3176
3177   /* if register bank was saved then pop them */
3178   if (restoreBank)
3179     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3180
3181   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3182     {
3183       if (resultInF0)
3184           emitcode ("mov", "c,F0");
3185
3186       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3187       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3188       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3189     }
3190
3191   if (accPushed)
3192     emitcode ("pop", "acc");
3193 }
3194
3195 /*-----------------------------------------------------------------*/
3196 /* genPcall - generates a call by pointer statement                */
3197 /*-----------------------------------------------------------------*/
3198 static void
3199 genPcall (iCode * ic)
3200 {
3201   sym_link *dtype;
3202   sym_link *etype;
3203   symbol *rlbl = newiTempLabel (NULL);
3204   bool restoreBank=FALSE;
3205   bool resultInF0 = FALSE;
3206
3207   D (emitcode (";", "genPcall"));
3208
3209   dtype = operandType (IC_LEFT (ic))->next;
3210   etype = getSpec(dtype);
3211   /* if caller saves & we have not saved then */
3212   if (!ic->regsSaved)
3213     saveRegisters (ic);
3214
3215   /* if we are calling a not _naked function that is not using
3216      the same register bank then we need to save the
3217      destination registers on the stack */
3218   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3219       IFFUNC_ISISR (currFunc->type) &&
3220       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3221     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3222     restoreBank=TRUE;
3223   }
3224
3225   /* push the return address on to the stack */
3226   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3227   emitcode ("push", "acc");
3228   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3229   emitcode ("push", "acc");
3230
3231   if (options.model == MODEL_FLAT24)
3232     {
3233       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3234       emitcode ("push", "acc");
3235     }
3236
3237   /* now push the calling address */
3238   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3239
3240   pushSide (IC_LEFT (ic), FPTRSIZE);
3241
3242   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3243
3244   /* if send set is not empty the assign */
3245   if (_G.sendSet)
3246     {
3247         genSend(reverseSet(_G.sendSet));
3248         _G.sendSet = NULL;
3249     }
3250
3251   /* make the call */
3252   emitcode ("ret", "");
3253   emitLabel (rlbl);
3254
3255
3256   /* if we need assign a result value */
3257   if ((IS_ITEMP (IC_RESULT (ic)) &&
3258        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3259        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3260         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3261       IS_TRUE_SYMOP (IC_RESULT (ic)))
3262     {
3263
3264       _G.accInUse++;
3265       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3266       _G.accInUse--;
3267
3268       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3269
3270       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3271     }
3272
3273   /* adjust the stack for parameters if required */
3274   if (ic->parmBytes)
3275     {
3276       int i;
3277       if (options.stack10bit) {
3278           if (ic->parmBytes <= 10) {
3279               emitcode(";","stack adjustment for parms");
3280               for (i=0; i < ic->parmBytes ; i++) {
3281                   emitcode("pop","acc");
3282               }
3283           } else {
3284               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3285                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3286                 {
3287                   emitcode ("mov", "F0,c");
3288                   resultInF0 = TRUE;
3289                 }
3290
3291               PROTECT_SP;
3292               emitcode ("clr","c");
3293               emitcode ("mov","a,sp");
3294               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3295               emitcode ("mov","sp,a");
3296               emitcode ("mov","a,esp");
3297               adjustEsp("a");
3298               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3299               emitcode ("mov","esp,a");
3300               UNPROTECT_SP;
3301           }
3302       } else {
3303           if (ic->parmBytes > 3) {
3304               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3305                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3306                 {
3307                   emitcode ("mov", "F0,c");
3308                   resultInF0 = TRUE;
3309                 }
3310
3311               emitcode ("mov", "a,%s", spname);
3312               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3313               emitcode ("mov", "%s,a", spname);
3314           }
3315           else
3316               for (i = 0; i < ic->parmBytes; i++)
3317                   emitcode ("dec", "%s", spname);
3318       }
3319     }
3320   /* if register bank was saved then unsave them */
3321   if (restoreBank)
3322     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3323
3324   /* if we had saved some registers then unsave them */
3325   if (ic->regsSaved)
3326     unsaveRegisters (ic);
3327
3328   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3329     {
3330       if (resultInF0)
3331           emitcode ("mov", "c,F0");
3332
3333       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3334       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3335       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3336     }
3337 }
3338
3339 /*-----------------------------------------------------------------*/
3340 /* resultRemat - result  is rematerializable                       */
3341 /*-----------------------------------------------------------------*/
3342 static int
3343 resultRemat (iCode * ic)
3344 {
3345   if (SKIP_IC (ic) || ic->op == IFX)
3346     return 0;
3347
3348   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3349     {
3350       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3351       if (sym->remat && !POINTER_SET (ic))
3352         return 1;
3353     }
3354
3355   return 0;
3356 }
3357
3358 /*-----------------------------------------------------------------*/
3359 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3360 /*-----------------------------------------------------------------*/
3361 static int
3362 regsCmp(void *p1, void *p2)
3363 {
3364   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3365 }
3366
3367 static bool
3368 inExcludeList (char *s)
3369 {
3370   const char *p = setFirstItem(options.excludeRegsSet);
3371
3372   if (p == NULL || STRCASECMP(p, "none") == 0)
3373     return FALSE;
3374
3375
3376   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3377 }
3378
3379 /*-----------------------------------------------------------------*/
3380 /* genFunction - generated code for function entry                 */
3381 /*-----------------------------------------------------------------*/
3382 static void
3383 genFunction (iCode * ic)
3384 {
3385   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3386   sym_link *ftype;
3387   bool     switchedPSW = FALSE;
3388   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3389
3390   D (emitcode (";", "genFunction"));
3391
3392   _G.nRegsSaved = 0;
3393   /* create the function header */
3394   emitcode (";", "-----------------------------------------");
3395   emitcode (";", " function %s", sym->name);
3396   emitcode (";", "-----------------------------------------");
3397
3398   emitcode ("", "%s:", sym->rname);
3399   lineCurr->isLabel = 1;
3400   ftype = operandType (IC_LEFT (ic));
3401   _G.currentFunc = sym;
3402
3403   if (IFFUNC_ISNAKED(ftype))
3404   {
3405       emitcode(";", "naked function: no prologue.");
3406       return;
3407   }
3408
3409   if (options.stack_probe)
3410       emitcode ("lcall","__stack_probe");
3411
3412   /* here we need to generate the equates for the
3413      register bank if required */
3414   if (FUNC_REGBANK (ftype) != rbank)
3415     {
3416       int i;
3417
3418       rbank = FUNC_REGBANK (ftype);
3419       for (i = 0; i < ds390_nRegs; i++)
3420         {
3421           if (regs390[i].print) {
3422               if (strcmp (regs390[i].base, "0") == 0)
3423                   emitcode ("", "%s !equ !constbyte",
3424                             regs390[i].dname,
3425                             8 * rbank + regs390[i].offset);
3426               else
3427                   emitcode ("", "%s !equ %s + !constbyte",
3428                             regs390[i].dname,
3429                             regs390[i].base,
3430                             8 * rbank + regs390[i].offset);
3431           }
3432         }
3433     }
3434
3435   /* if this is an interrupt service routine then
3436      save acc, b, dpl, dph  */
3437   if (IFFUNC_ISISR (sym->type))
3438       { /* is ISR */
3439       if (!inExcludeList ("acc"))
3440         emitcode ("push", "acc");
3441       if (!inExcludeList ("b"))
3442         emitcode ("push", "b");
3443       if (!inExcludeList ("dpl"))
3444         emitcode ("push", "dpl");
3445       if (!inExcludeList ("dph"))
3446         emitcode ("push", "dph");
3447       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3448         {
3449           emitcode ("push", "dpx");
3450           /* Make sure we're using standard DPTR */
3451           emitcode ("push", "dps");
3452           emitcode ("mov", "dps,#0");
3453           if (options.stack10bit)
3454             {
3455               /* This ISR could conceivably use DPTR2. Better save it. */
3456               emitcode ("push", "dpl1");
3457               emitcode ("push", "dph1");
3458               emitcode ("push", "dpx1");
3459               emitcode ("push",  DP2_RESULT_REG);
3460             }
3461         }
3462       /* if this isr has no bank i.e. is going to
3463          run with bank 0 , then we need to save more
3464          registers :-) */
3465       if (!FUNC_REGBANK (sym->type))
3466         {
3467             int i;
3468
3469           /* if this function does not call any other
3470              function then we can be economical and
3471              save only those registers that are used */
3472           if (!IFFUNC_HASFCALL(sym->type))
3473             {
3474               /* if any registers used */
3475               if (sym->regsUsed)
3476                 {
3477                   bool bits_pushed = FALSE;
3478                   /* save the registers used */
3479                   for (i = 0; i < sym->regsUsed->size; i++)
3480                     {
3481                       if (bitVectBitValue (sym->regsUsed, i))
3482                         bits_pushed = pushReg (i, bits_pushed);
3483                     }
3484                 }
3485             }
3486           else
3487             {
3488               /* this function has a function call. We cannot
3489                  determine register usage so we will have to push the
3490                  entire bank */
3491               saveRBank (0, ic, FALSE);
3492               if (options.parms_in_bank1) {
3493                   for (i=0; i < 8 ; i++ ) {
3494                       emitcode ("push","%s",rb1regs[i]);
3495                   }
3496               }
3497             }
3498         }
3499         else
3500         {
3501             /* This ISR uses a non-zero bank.
3502              *
3503              * We assume that the bank is available for our
3504              * exclusive use.
3505              *
3506              * However, if this ISR calls a function which uses some
3507              * other bank, we must save that bank entirely.
3508              */
3509             unsigned long banksToSave = 0;
3510
3511             if (IFFUNC_HASFCALL(sym->type))
3512             {
3513
3514 #define MAX_REGISTER_BANKS 4
3515
3516                 iCode *i;
3517                 int ix;
3518
3519                 for (i = ic; i; i = i->next)
3520                 {
3521                     if (i->op == ENDFUNCTION)
3522                     {
3523                         /* we got to the end OK. */
3524                         break;
3525                     }
3526
3527                     if (i->op == CALL)
3528                     {
3529                         sym_link *dtype;
3530
3531                         dtype = operandType (IC_LEFT(i));
3532                         if (dtype
3533                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3534                         {
3535                              /* Mark this bank for saving. */
3536                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3537                              {
3538                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3539                              }
3540                              else
3541                              {
3542                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3543                              }
3544
3545                              /* And note that we don't need to do it in
3546                               * genCall.
3547                               */
3548                              i->bankSaved = 1;
3549                         }
3550                     }
3551                     if (i->op == PCALL)
3552                     {
3553                         /* This is a mess; we have no idea what
3554                          * register bank the called function might
3555                          * use.
3556                          *
3557                          * The only thing I can think of to do is
3558                          * throw a warning and hope.
3559                          */
3560                         werror(W_FUNCPTR_IN_USING_ISR);
3561                     }
3562                 }
3563
3564                 if (banksToSave && options.useXstack)
3565                 {
3566                     /* Since we aren't passing it an ic,
3567                      * saveRBank will assume r0 is available to abuse.
3568                      *
3569                      * So switch to our (trashable) bank now, so
3570                      * the caller's R0 isn't trashed.
3571                      */
3572                     emitcode ("push", "psw");
3573                     emitcode ("mov", "psw,#!constbyte",
3574                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3575                     switchedPSW = TRUE;
3576                 }
3577
3578                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3579                 {
3580                      if (banksToSave & (1 << ix))
3581                      {
3582                          saveRBank(ix, NULL, FALSE);
3583                      }
3584                 }
3585             }
3586             // TODO: this needs a closer look
3587             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3588         }
3589     }
3590   else
3591     {
3592       /* if callee-save to be used for this function
3593          then save the registers being used in this function */
3594       if (IFFUNC_CALLEESAVES(sym->type))
3595         {
3596           int i;
3597
3598           /* if any registers used */
3599           if (sym->regsUsed)
3600             {
3601               bool bits_pushed = FALSE;
3602               /* save the registers used */
3603               for (i = 0; i < sym->regsUsed->size; i++)
3604                 {
3605                   if (bitVectBitValue (sym->regsUsed, i))
3606                     {
3607                       bits_pushed = pushReg (i, bits_pushed);
3608                       _G.nRegsSaved++;
3609                     }
3610                 }
3611             }
3612         }
3613     }
3614
3615   /* set the register bank to the desired value */
3616   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3617    && !switchedPSW)
3618     {
3619       emitcode ("push", "psw");
3620       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3621     }
3622
3623   if (fReentrant &&
3624        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3625       if (options.stack10bit) {
3626           emitcode ("push","_bpx");
3627           emitcode ("push","_bpx+1");
3628           emitcode ("mov","_bpx,%s",spname);
3629           emitcode ("mov","_bpx+1,esp");
3630           adjustEsp("_bpx+1");
3631       } else {
3632           if (options.useXstack)
3633           {
3634               emitcode ("mov", "r0,%s", spname);
3635               emitcode ("mov", "a,_bp");
3636               emitcode ("movx", "@r0,a");
3637               emitcode ("inc", "%s", spname);
3638           } else {
3639               /* set up the stack */
3640               emitcode ("push", "_bp"); /* save the callers stack  */
3641           }
3642           emitcode ("mov", "_bp,%s", spname);
3643       }
3644   }
3645
3646   /* adjust the stack for the function */
3647   if (sym->stack) {
3648       int i = sym->stack;
3649       if (options.stack10bit) {
3650           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3651           assert (sym->recvSize <= 4);
3652           if (sym->stack <= 8) {
3653               while (i--) emitcode ("push","acc");
3654           } else {
3655               PROTECT_SP;
3656               emitcode ("mov","a,sp");
3657               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3658               emitcode ("mov","sp,a");
3659               emitcode ("mov","a,esp");
3660               adjustEsp("a");
3661               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3662               emitcode ("mov","esp,a");
3663               UNPROTECT_SP;
3664           }
3665       } else {
3666           if (i > 256)
3667               werror (W_STACK_OVERFLOW, sym->name);
3668
3669           if (i > 3 && sym->recvSize < 4) {
3670
3671               emitcode ("mov", "a,sp");
3672               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3673               emitcode ("mov", "sp,a");
3674
3675           } else
3676               while (i--)
3677                   emitcode ("inc", "sp");
3678       }
3679   }
3680
3681   if (sym->xstack)
3682     {
3683
3684       emitcode ("mov", "a,_spx");
3685       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3686       emitcode ("mov", "_spx,a");
3687     }
3688
3689   /* if critical function then turn interrupts off */
3690   if (IFFUNC_ISCRITICAL (ftype))
3691     {
3692       symbol *tlbl = newiTempLabel (NULL);
3693       emitcode ("setb", "c");
3694       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3695       emitcode ("clr", "c");
3696       emitLabel (tlbl);
3697       emitcode ("push", "psw"); /* save old ea via c in psw */
3698     }
3699 }
3700
3701 /*-----------------------------------------------------------------*/
3702 /* genEndFunction - generates epilogue for functions               */
3703 /*-----------------------------------------------------------------*/
3704 static void
3705 genEndFunction (iCode * ic)
3706 {
3707   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3708   lineNode *lnp = lineCurr;
3709   bitVect *regsUsed;
3710   bitVect *regsUsedPrologue;
3711   bitVect *regsUnneeded;
3712   int idx;
3713
3714   D (emitcode (";", "genEndFunction"));
3715
3716   _G.currentFunc = NULL;
3717   if (IFFUNC_ISNAKED(sym->type))
3718   {
3719       emitcode(";", "naked function: no epilogue.");
3720       if (options.debug && currFunc)
3721         debugFile->writeEndFunction (currFunc, ic, 0);
3722       return;
3723   }
3724
3725   if (IFFUNC_ISCRITICAL (sym->type))
3726     {
3727       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3728         {
3729           emitcode ("rlc", "a");   /* save c in a */
3730           emitcode ("pop", "psw"); /* restore ea via c in psw */
3731           emitcode ("mov", "ea,c");
3732           emitcode ("rrc", "a");   /* restore c from a */
3733         }
3734       else
3735         {
3736           emitcode ("pop", "psw"); /* restore ea via c in psw */
3737           emitcode ("mov", "ea,c");
3738         }
3739     }
3740
3741   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3742        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3743
3744       if (options.stack10bit) {
3745           PROTECT_SP;
3746           emitcode ("mov", "sp,_bpx", spname);
3747           emitcode ("mov", "esp,_bpx+1", spname);
3748           UNPROTECT_SP;
3749       } else {
3750           emitcode ("mov", "%s,_bp", spname);
3751       }
3752   }
3753
3754   /* if use external stack but some variables were
3755      added to the local stack then decrement the
3756      local stack */
3757   if (options.useXstack && sym->stack) {
3758       emitcode ("mov", "a,sp");
3759       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3760       emitcode ("mov", "sp,a");
3761   }
3762
3763
3764   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3765        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3766
3767       if (options.useXstack) {
3768           emitcode ("mov", "r0,%s", spname);
3769           emitcode ("movx", "a,@r0");
3770           emitcode ("mov", "_bp,a");
3771           emitcode ("dec", "%s", spname);
3772       } else {
3773           if (options.stack10bit) {
3774               emitcode ("pop", "_bpx+1");
3775               emitcode ("pop", "_bpx");
3776           } else {
3777               emitcode ("pop", "_bp");
3778           }
3779       }
3780   }
3781
3782   /* restore the register bank  */
3783   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3784   {
3785     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3786      || !options.useXstack)
3787     {
3788         /* Special case of ISR using non-zero bank with useXstack
3789          * is handled below.
3790          */
3791         emitcode ("pop", "psw");
3792     }
3793   }
3794
3795   if (IFFUNC_ISISR (sym->type))
3796     { /* is ISR */
3797
3798       /* now we need to restore the registers */
3799       /* if this isr has no bank i.e. is going to
3800          run with bank 0 , then we need to save more
3801          registers :-) */
3802       if (!FUNC_REGBANK (sym->type))
3803         {
3804           int i;
3805           /* if this function does not call any other
3806              function then we can be economical and
3807              save only those registers that are used */
3808           if (!IFFUNC_HASFCALL(sym->type))
3809             {
3810               /* if any registers used */
3811               if (sym->regsUsed)
3812                 {
3813                   bool bits_popped = FALSE;
3814                   /* save the registers used */
3815                   for (i = sym->regsUsed->size; i >= 0; i--)
3816                     {
3817                       if (bitVectBitValue (sym->regsUsed, i))
3818                         bits_popped = popReg (i, bits_popped);
3819                     }
3820                 }
3821             }
3822           else
3823             {
3824               /* this function has a function call. We cannot
3825                  determine register usage so we will have to pop the
3826                  entire bank */
3827               if (options.parms_in_bank1) {
3828                   for (i = 7 ; i >= 0 ; i-- ) {
3829                       emitcode ("pop","%s",rb1regs[i]);
3830                   }
3831               }
3832               unsaveRBank (0, ic, FALSE);
3833             }
3834         }
3835       else
3836         {
3837             /* This ISR uses a non-zero bank.
3838              *
3839              * Restore any register banks saved by genFunction
3840              * in reverse order.
3841              */
3842             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3843             int ix;
3844
3845             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3846             {
3847                 if (savedBanks & (1 << ix))
3848                 {
3849                     unsaveRBank(ix, NULL, FALSE);
3850                 }
3851             }
3852
3853             if (options.useXstack)
3854             {
3855                 /* Restore bank AFTER calling unsaveRBank,
3856                  * since it can trash r0.
3857                  */
3858                 emitcode ("pop", "psw");
3859             }
3860         }
3861
3862       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3863         {
3864           if (options.stack10bit)
3865             {
3866               emitcode ("pop", DP2_RESULT_REG);
3867               emitcode ("pop", "dpx1");
3868               emitcode ("pop", "dph1");
3869               emitcode ("pop", "dpl1");
3870             }
3871           emitcode ("pop", "dps");
3872           emitcode ("pop", "dpx");
3873         }
3874       if (!inExcludeList ("dph"))
3875         emitcode ("pop", "dph");
3876       if (!inExcludeList ("dpl"))
3877         emitcode ("pop", "dpl");
3878       if (!inExcludeList ("b"))
3879         emitcode ("pop", "b");
3880       if (!inExcludeList ("acc"))
3881         emitcode ("pop", "acc");
3882
3883       /* if debug then send end of function */
3884       if (options.debug && currFunc)
3885         {
3886           debugFile->writeEndFunction (currFunc, ic, 1);
3887         }
3888
3889       emitcode ("reti", "");
3890     }
3891   else
3892     {
3893       if (IFFUNC_CALLEESAVES(sym->type))
3894         {
3895           int i;
3896
3897           /* if any registers used */
3898           if (sym->regsUsed)
3899             {
3900               /* save the registers used */
3901               for (i = sym->regsUsed->size; i >= 0; i--)
3902                 {
3903                   if (bitVectBitValue (sym->regsUsed, i))
3904                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3905                 }
3906             }
3907         }
3908
3909       /* if debug then send end of function */
3910       if (options.debug && currFunc)
3911         {
3912           debugFile->writeEndFunction (currFunc, ic, 1);
3913         }
3914
3915       emitcode ("ret", "");
3916     }
3917
3918   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3919     return;
3920
3921   /* If this was an interrupt handler using bank 0 that called another */
3922   /* function, then all registers must be saved; nothing to optimized. */
3923   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3924       && !FUNC_REGBANK(sym->type))
3925     return;
3926
3927   /* There are no push/pops to optimize if not callee-saves or ISR */
3928   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3929     return;
3930
3931   /* If there were stack parameters, we cannot optimize without also    */
3932   /* fixing all of the stack offsets; this is too dificult to consider. */
3933   if (FUNC_HASSTACKPARM(sym->type))
3934     return;
3935
3936   /* Compute the registers actually used */
3937   regsUsed = newBitVect (ds390_nRegs);
3938   regsUsedPrologue = newBitVect (ds390_nRegs);
3939   while (lnp)
3940     {
3941       if (lnp->ic && lnp->ic->op == FUNCTION)
3942         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3943       else
3944         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3945
3946       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3947           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3948         break;
3949       if (!lnp->prev)
3950         break;
3951       lnp = lnp->prev;
3952     }
3953
3954   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3955       && !bitVectBitValue (regsUsed, DPS_IDX))
3956     {
3957       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3958     }
3959
3960   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3961       && !bitVectBitValue (regsUsed, CND_IDX))
3962     {
3963       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3964       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3965           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3966         bitVectUnSetBit (regsUsed, CND_IDX);
3967     }
3968   else
3969     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3970
3971   /* If this was an interrupt handler that called another function */
3972   /* function, then assume working registers may be modified by it. */
3973   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3974     {
3975       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3976       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3986     }
3987
3988   /* Remove the unneeded push/pops */
3989   regsUnneeded = newBitVect (ds390_nRegs);
3990   while (lnp)
3991     {
3992       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3993         {
3994           if (!strncmp(lnp->line, "push", 4))
3995             {
3996               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3997               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3998                 {
3999                   connectLine (lnp->prev, lnp->next);
4000                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4001                 }
4002             }
4003           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4004             {
4005               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4006               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4007                 {
4008                   connectLine (lnp->prev, lnp->next);
4009                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4010                 }
4011             }
4012         }
4013       lnp = lnp->next;
4014     }
4015
4016   for (idx = 0; idx < regsUnneeded->size; idx++)
4017     if (bitVectBitValue (regsUnneeded, idx))
4018       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4019
4020   freeBitVect (regsUnneeded);
4021   freeBitVect (regsUsed);
4022   freeBitVect (regsUsedPrologue);
4023 }
4024
4025 /*-----------------------------------------------------------------*/
4026 /* genJavaNativeRet - generate code for return JavaNative          */
4027 /*-----------------------------------------------------------------*/
4028 static void genJavaNativeRet(iCode *ic)
4029 {
4030     int i, size;
4031
4032     aopOp (IC_LEFT (ic), ic, FALSE,
4033            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4034     size = AOP_SIZE (IC_LEFT (ic));
4035
4036     assert (size <= 4);
4037
4038     /* it is assigned to GPR0-R3 then push them */
4039     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4040         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4041         for (i = 0 ; i < size ; i++ ) {
4042             emitcode ("push","%s",
4043                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4044         }
4045         for (i = (size-1) ; i >= 0 ; i--) {
4046             emitcode ("pop","a%s",javaRet[i]);
4047         }
4048     } else {
4049         for (i = 0 ; i < size ; i++)
4050             emitcode ("mov","%s,%s",javaRet[i],
4051                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4052     }
4053     for (i = size ; i < 4 ; i++ )
4054             emitcode ("mov","%s,#0",javaRet[i]);
4055     return;
4056 }
4057
4058 /*-----------------------------------------------------------------*/
4059 /* genRet - generate code for return statement                     */
4060 /*-----------------------------------------------------------------*/
4061 static void
4062 genRet (iCode * ic)
4063 {
4064   int size, offset = 0, pushed = 0;
4065
4066   D (emitcode (";", "genRet"));
4067
4068   /* if we have no return value then
4069      just generate the "ret" */
4070   if (!IC_LEFT (ic))
4071     goto jumpret;
4072
4073   /* if this is a JavaNative function then return
4074      value in different register */
4075   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4076       genJavaNativeRet(ic);
4077       goto jumpret;
4078   }
4079   /* we have something to return then
4080      move the return value into place */
4081   aopOp (IC_LEFT (ic), ic, FALSE,
4082          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4083   size = AOP_SIZE (IC_LEFT (ic));
4084
4085   _startLazyDPSEvaluation ();
4086
4087   if (IS_BIT(_G.currentFunc->etype))
4088     {
4089       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4090       size = 0;
4091     }
4092
4093   while (size--)
4094     {
4095       char *l;
4096       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4097         {
4098           l = aopGet (IC_LEFT (ic), offset++,
4099                       FALSE, TRUE, NULL);
4100           emitcode ("push", "%s", l);
4101           pushed++;
4102         }
4103       else
4104         {
4105           /* Since A is the last element of fReturn,
4106            * it is OK to clobber it in the aopGet.
4107            */
4108           l = aopGet (IC_LEFT (ic), offset,
4109                       FALSE, FALSE, NULL);
4110           if (strcmp (fReturn[offset], l))
4111             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4112         }
4113     }
4114   _endLazyDPSEvaluation ();
4115
4116   while (pushed)
4117     {
4118       pushed--;
4119       if (strcmp (fReturn[pushed], "a"))
4120         emitcode ("pop", fReturn[pushed]);
4121       else
4122         emitcode ("pop", "acc");
4123     }
4124   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4125
4126 jumpret:
4127   /* generate a jump to the return label
4128      if the next is not the return statement */
4129   if (!(ic->next && ic->next->op == LABEL &&
4130         IC_LABEL (ic->next) == returnLabel))
4131
4132     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4133
4134 }
4135
4136 /*-----------------------------------------------------------------*/
4137 /* genLabel - generates a label                                    */
4138 /*-----------------------------------------------------------------*/
4139 static void
4140 genLabel (iCode * ic)
4141 {
4142   /* special case never generate */
4143   if (IC_LABEL (ic) == entryLabel)
4144     return;
4145
4146   D (emitcode (";", "genLabel"));
4147
4148   emitLabel (IC_LABEL (ic));
4149 }
4150
4151 /*-----------------------------------------------------------------*/
4152 /* genGoto - generates a ljmp                                      */
4153 /*-----------------------------------------------------------------*/
4154 static void
4155 genGoto (iCode * ic)
4156 {
4157   D (emitcode (";", "genGoto"));
4158
4159   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4160 }
4161
4162 /*-----------------------------------------------------------------*/
4163 /* findLabelBackwards: walks back through the iCode chain looking  */
4164 /* for the given label. Returns number of iCode instructions     */
4165 /* between that label and given ic.          */
4166 /* Returns zero if label not found.          */
4167 /*-----------------------------------------------------------------*/
4168 static int
4169 findLabelBackwards (iCode * ic, int key)
4170 {
4171   int count = 0;
4172
4173   while (ic->prev)
4174     {
4175       ic = ic->prev;
4176       count++;
4177
4178       /* If we have any pushes or pops, we cannot predict the distance.
4179          I don't like this at all, this should be dealt with in the
4180          back-end */
4181       if (ic->op == IPUSH || ic->op == IPOP) {
4182         return 0;
4183       }
4184
4185       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4186         {
4187           /* printf("findLabelBackwards = %d\n", count); */
4188           return count;
4189         }
4190     }
4191
4192   return 0;
4193 }
4194
4195 /*-----------------------------------------------------------------*/
4196 /* genPlusIncr :- does addition with increment if possible         */
4197 /*-----------------------------------------------------------------*/
4198 static bool
4199 genPlusIncr (iCode * ic)
4200 {
4201   unsigned int icount;
4202   unsigned int size = getDataSize (IC_RESULT (ic));
4203
4204   /* will try to generate an increment */
4205   /* if the right side is not a literal
4206      we cannot */
4207   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4208     return FALSE;
4209
4210   /* if the literal value of the right hand side
4211      is greater than 4 then it is not worth it */
4212   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4213     return FALSE;
4214
4215   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4216       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4217       while (icount--) {
4218           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4219       }
4220       return TRUE;
4221   }
4222   /* if increment 16 bits in register */
4223   if (
4224        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4225        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4226        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4227        (size > 1) &&
4228        (icount == 1))
4229     {
4230       symbol  *tlbl;
4231       int     emitTlbl;
4232       int     labelRange;
4233       char    *l;
4234
4235       /* If the next instruction is a goto and the goto target
4236        * is <= 5 instructions previous to this, we can generate
4237        * jumps straight to that target.
4238        */
4239       if (ic->next && ic->next->op == GOTO
4240           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4241           && labelRange <= 5)
4242         {
4243           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4244           tlbl = IC_LABEL (ic->next);
4245           emitTlbl = 0;
4246         }
4247       else
4248         {
4249           tlbl = newiTempLabel (NULL);
4250           emitTlbl = 1;
4251         }
4252       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4253       emitcode ("inc", "%s", l);
4254
4255       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4256           IS_AOP_PREG (IC_RESULT (ic)))
4257         {
4258           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4259         }
4260       else
4261         {
4262           emitcode ("clr", "a");
4263           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4264         }
4265
4266       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4267       emitcode ("inc", "%s", l);
4268       if (size > 2)
4269         {
4270           if (!strcmp(l, "acc"))
4271             {
4272                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4273             }
4274           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4275                    IS_AOP_PREG (IC_RESULT (ic)))
4276             {
4277                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4278             }
4279           else
4280             {
4281                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4282             }
4283
4284           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4285           emitcode ("inc", "%s", l);
4286         }
4287       if (size > 3)
4288         {
4289           if (!strcmp(l, "acc"))
4290             {
4291                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4292             }
4293           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4294                    IS_AOP_PREG (IC_RESULT (ic)))
4295             {
4296                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4297             }
4298           else
4299             {
4300                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4301             }
4302
4303           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4304           emitcode ("inc", "%s", l);
4305         }
4306
4307       if (emitTlbl)
4308         {
4309           emitLabel (tlbl);
4310         }
4311       return TRUE;
4312     }
4313
4314   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4315       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4316       options.model == MODEL_FLAT24 )
4317     {
4318       if (IC_RESULT(ic)->isGptr)
4319         {
4320           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4321         }
4322       switch (size) {
4323       case 3:
4324           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4325       case 2:
4326           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4327       case 1:
4328           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4329           break;
4330       }
4331       while (icount--)
4332         emitcode ("inc", "dptr");
4333       return TRUE;
4334   }
4335
4336   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4337       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4338       icount <= 5 ) {
4339       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4340       while (icount--)
4341         emitcode ("inc", "dptr");
4342       emitcode ("mov", "dps,#0");
4343       return TRUE;
4344   }
4345
4346   /* if the sizes are greater than 1 then we cannot */
4347   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4348       AOP_SIZE (IC_LEFT (ic)) > 1)
4349     return FALSE;
4350
4351   /* we can if the aops of the left & result match or
4352      if they are in registers and the registers are the
4353      same */
4354   if (
4355        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4356        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4357        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4358     {
4359       if (icount > 3)
4360         {
4361           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4362           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4363           aopPut (IC_RESULT (ic), "a", 0);
4364         }
4365       else
4366         {
4367           _startLazyDPSEvaluation ();
4368           while (icount--)
4369             {
4370               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4371             }
4372           _endLazyDPSEvaluation ();
4373         }
4374
4375       return TRUE;
4376     }
4377
4378   return FALSE;
4379 }
4380
4381 /*-----------------------------------------------------------------*/
4382 /* outBitAcc - output a bit in acc                                 */
4383 /*-----------------------------------------------------------------*/
4384 static void
4385 outBitAcc (operand * result)
4386 {
4387   symbol *tlbl = newiTempLabel (NULL);
4388   /* if the result is a bit */
4389   if (AOP_TYPE (result) == AOP_CRY)
4390     {
4391       aopPut (result, "a", 0);
4392     }
4393   else
4394     {
4395       emitcode ("jz", "!tlabel", tlbl->key + 100);
4396       emitcode ("mov", "a,%s", one);
4397       emitLabel (tlbl);
4398       outAcc (result);
4399     }
4400 }
4401
4402 /*-----------------------------------------------------------------*/
4403 /* genPlusBits - generates code for addition of two bits           */
4404 /*-----------------------------------------------------------------*/
4405 static void
4406 genPlusBits (iCode * ic)
4407 {
4408   D (emitcode (";", "genPlusBits"));
4409
4410   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4411     {
4412       symbol *lbl = newiTempLabel (NULL);
4413       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4414       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4415       emitcode ("cpl", "c");
4416       emitLabel (lbl);
4417       outBitC (IC_RESULT (ic));
4418     }
4419   else
4420     {
4421       emitcode ("clr", "a");
4422       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4423       emitcode ("rlc", "a");
4424       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4425       emitcode ("addc", "a,%s", zero);
4426       outAcc (IC_RESULT (ic));
4427     }
4428 }
4429
4430 static void
4431 adjustArithmeticResult (iCode * ic)
4432 {
4433   if (opIsGptr (IC_RESULT (ic)) &&
4434       opIsGptr (IC_LEFT (ic)) &&
4435       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4436     {
4437       aopPut (IC_RESULT (ic),
4438               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4439               GPTRSIZE - 1);
4440     }
4441
4442   if (opIsGptr (IC_RESULT (ic)) &&
4443       opIsGptr (IC_RIGHT (ic)) &&
4444       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4445     {
4446       aopPut (IC_RESULT (ic),
4447               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4448               GPTRSIZE - 1);
4449     }
4450
4451   if (opIsGptr (IC_RESULT (ic)) &&
4452       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4453       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4454       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4455       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4456     {
4457       char buffer[5];
4458       SNPRINTF (buffer, sizeof(buffer),
4459                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4460       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4461     }
4462 }
4463
4464 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4465 // generates the result if possible. If result is generated, returns TRUE; otherwise
4466 // returns false and caller must deal with fact that result isn't aopOp'd.
4467 bool aopOp3(iCode * ic)
4468 {
4469     bool dp1InUse, dp2InUse;
4470     bool useDp2;
4471
4472     // First, generate the right opcode. DPTR may be used if neither left nor result are
4473     // of type AOP_STR.
4474
4475 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4476 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4477 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4478 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4479 //      );
4480 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4481 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4482 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4483 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4484 //      );
4485
4486     // Right uses DPTR unless left or result is an AOP_STR; however,
4487     // if right is an AOP_STR, it must use DPTR regardless.
4488     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4489      && !AOP_IS_STR (IC_RIGHT (ic)))
4490     {
4491         useDp2 = TRUE;
4492     }
4493     else
4494     {
4495         useDp2 = FALSE;
4496     }
4497
4498     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4499
4500     // if the right used DPTR, left MUST use DPTR2.
4501     // if the right used DPTR2, left MUST use DPTR.
4502     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4503     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4504     // enabling us to assign DPTR to result.
4505
4506     if (AOP_USESDPTR (IC_RIGHT (ic)))
4507     {
4508         useDp2 = TRUE;
4509     }
4510     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4511     {
4512         useDp2 = FALSE;
4513     }
4514     else
4515     {
4516         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4517         {
4518             useDp2 = TRUE;
4519         }
4520         else
4521         {
4522             useDp2 = FALSE;
4523         }
4524     }
4525
4526     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4527
4528
4529     // We've op'd the left & right. So, if left or right are the same operand as result,
4530     // we know aopOp will succeed, and we can just do it & bail.
4531     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4532       {
4533         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4534         return TRUE;
4535       }
4536     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4537       {
4538 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4539         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4540         return TRUE;
4541       }
4542
4543     // Operands may be equivalent (but not equal) if they share a spill location. If
4544     // so, use the same DPTR or DPTR2.
4545     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4546       {
4547         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4548         return TRUE;
4549       }
4550     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4551       {
4552         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4553         return TRUE;
4554       }
4555
4556     // Note which dptrs are currently in use.
4557     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4558     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4559
4560     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4561     // generate it.
4562     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4563     {
4564         return FALSE;
4565     }
4566
4567     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4568     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4569     {
4570         return FALSE;
4571     }
4572
4573     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4574     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4575     {
4576         return FALSE;
4577     }
4578
4579     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4580
4581     // Some sanity checking...
4582     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4583     {
4584         fprintf(stderr,
4585                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4586                 __FILE__, __LINE__, ic->filename, ic->lineno);
4587         emitcode(";", ">>> unexpected DPTR here.");
4588     }
4589
4590     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4591     {
4592         fprintf(stderr,
4593                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4594                 __FILE__, __LINE__, ic->filename, ic->lineno);
4595         emitcode(";", ">>> unexpected DPTR2 here.");
4596     }
4597
4598     return TRUE;
4599 }
4600
4601 // Macro to aopOp all three operands of an ic. If this cannot be done,
4602 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4603 // will be set TRUE. The caller must then handle the case specially, noting
4604 // that the IC_RESULT operand is not aopOp'd.
4605 //
4606 #define AOP_OP_3_NOFATAL(ic, rc) \
4607             do { rc = !aopOp3(ic); } while (0)
4608
4609 // aopOp the left & right operands of an ic.
4610 #define AOP_OP_2(ic) \
4611     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4612     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4613
4614 // convienience macro.
4615 #define AOP_SET_LOCALS(ic) \
4616     left = IC_LEFT(ic); \
4617     right = IC_RIGHT(ic); \
4618     result = IC_RESULT(ic);
4619
4620
4621 // Given an integer value of pushedSize bytes on the stack,
4622 // adjust it to be resultSize bytes, either by discarding
4623 // the most significant bytes or by zero-padding.
4624 //
4625 // On exit from this macro, pushedSize will have been adjusted to
4626 // equal resultSize, and ACC may be trashed.
4627 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4628       /* If the pushed data is bigger than the result,          \
4629        * simply discard unused bytes. Icky, but works.          \
4630        */                                                       \
4631       while (pushedSize > resultSize)                           \
4632       {                                                         \
4633           D (emitcode (";", "discarding unused result byte.")); \
4634           emitcode ("pop", "acc");                              \
4635           pushedSize--;                                         \
4636       }                                                         \
4637       if (pushedSize < resultSize)                              \
4638       {                                                         \
4639           emitcode ("clr", "a");                                \
4640           /* Conversly, we haven't pushed enough here.          \
4641            * just zero-pad, and all is well.                    \
4642            */                                                   \
4643           while (pushedSize < resultSize)                       \
4644           {                                                     \
4645               emitcode("push", "acc");                          \
4646               pushedSize++;                                     \
4647           }                                                     \
4648       }                                                         \
4649       assert(pushedSize == resultSize);
4650
4651 /*-----------------------------------------------------------------*/
4652 /* genPlus - generates code for addition                           */
4653 /*-----------------------------------------------------------------*/
4654 static void
4655 genPlus (iCode * ic)
4656 {
4657   int size, offset = 0;
4658   bool pushResult;
4659   int rSize;
4660   bool swappedLR = FALSE;
4661
4662   D (emitcode (";", "genPlus"));
4663
4664   /* special cases :- */
4665   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4666       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4667       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4668       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4669       if (size <= 9) {
4670           while (size--) emitcode ("inc","dptr");
4671       } else {
4672           emitcode ("mov", "a,dpl");
4673           emitcode ("add", "a,#!constbyte", size & 0xff);
4674           emitcode ("mov", "dpl,a");
4675           emitcode ("mov", "a,dph");
4676           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4677           emitcode ("mov", "dph,a");
4678           emitcode ("mov", "a,dpx");
4679           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4680           emitcode ("mov", "dpx,a");
4681       }
4682       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4683       return ;
4684   }
4685   if ( IS_SYMOP (IC_LEFT (ic)) &&
4686        OP_SYMBOL (IC_LEFT (ic))->remat &&
4687        isOperandInFarSpace (IC_RIGHT (ic))) {
4688       operand *op = IC_RIGHT(ic);
4689       IC_RIGHT(ic) = IC_LEFT(ic);
4690       IC_LEFT(ic) = op;
4691   }
4692
4693   AOP_OP_3_NOFATAL (ic, pushResult);
4694
4695   if (pushResult)
4696     {
4697       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4698     }
4699
4700   if (!pushResult)
4701     {
4702       /* if literal, literal on the right or
4703          if left requires ACC or right is already
4704          in ACC */
4705       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4706           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4707           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4708         {
4709           operand *t = IC_RIGHT (ic);
4710           IC_RIGHT (ic) = IC_LEFT (ic);
4711           IC_LEFT (ic) = t;
4712           swappedLR = TRUE;
4713           D (emitcode (";", "Swapped plus args."));
4714         }
4715
4716       /* if both left & right are in bit
4717          space */
4718       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4719           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4720         {
4721           genPlusBits (ic);
4722           goto release;
4723         }
4724
4725       /* if left in bit space & right literal */
4726       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4727           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4728         {
4729           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4730           /* if result in bit space */
4731           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4732             {
4733               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4734                 emitcode ("cpl", "c");
4735               outBitC (IC_RESULT (ic));
4736             }
4737           else
4738             {
4739               size = getDataSize (IC_RESULT (ic));
4740               _startLazyDPSEvaluation ();
4741               while (size--)
4742                 {
4743                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4744                   emitcode ("addc", "a,%s", zero);
4745                   aopPut (IC_RESULT (ic), "a", offset++);
4746                 }
4747               _endLazyDPSEvaluation ();
4748             }
4749           goto release;
4750         }
4751
4752       /* if I can do an increment instead
4753          of add then GOOD for ME */
4754       if (genPlusIncr (ic) == TRUE)
4755         {
4756           D (emitcode (";", "did genPlusIncr"));
4757           goto release;
4758         }
4759
4760     }
4761   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4762
4763   _startLazyDPSEvaluation ();
4764   while (size--)
4765     {
4766       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4767         {
4768           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4769           if (offset == 0)
4770             emitcode ("add", "a,%s",
4771                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4772           else
4773             emitcode ("addc", "a,%s",
4774                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4775         }
4776       else
4777         {
4778           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4779           {
4780               /* right is going to use ACC or we would have taken the
4781                * above branch.
4782                */
4783               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4784               TR_AP("#3");
4785               D(emitcode(";", "+ AOP_ACC special case."););
4786               emitcode("xch", "a, %s", DP2_RESULT_REG);
4787           }
4788           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4789           if (offset == 0)
4790           {
4791             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4792             {
4793                 TR_AP("#4");
4794                 emitcode("add", "a, %s", DP2_RESULT_REG);
4795             }
4796             else
4797             {
4798                 emitcode ("add", "a,%s",
4799                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4800                                   DP2_RESULT_REG));
4801             }
4802           }
4803           else
4804           {
4805             emitcode ("addc", "a,%s",
4806                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4807                           DP2_RESULT_REG));
4808           }
4809         }
4810       if (!pushResult)
4811         {
4812           aopPut (IC_RESULT (ic), "a", offset);
4813         }
4814       else
4815         {
4816           emitcode ("push", "acc");
4817         }
4818       offset++;
4819     }
4820   _endLazyDPSEvaluation ();
4821
4822   if (pushResult)
4823     {
4824       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4825
4826       size = getDataSize (IC_LEFT (ic));
4827       rSize = getDataSize (IC_RESULT (ic));
4828
4829       ADJUST_PUSHED_RESULT(size, rSize);
4830
4831       _startLazyDPSEvaluation ();
4832       while (size--)
4833         {
4834           emitcode ("pop", "acc");
4835           aopPut (IC_RESULT (ic), "a", size);
4836         }
4837       _endLazyDPSEvaluation ();
4838     }
4839
4840   adjustArithmeticResult (ic);
4841
4842 release:
4843   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4844   if (!swappedLR)
4845     {
4846       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4847       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4848     }
4849   else
4850     {
4851       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4852       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4853     }
4854 }
4855
4856 /*-----------------------------------------------------------------*/
4857 /* genMinusDec :- does subtraction with decrement if possible      */
4858 /*-----------------------------------------------------------------*/
4859 static bool
4860 genMinusDec (iCode * ic)
4861 {
4862   unsigned int icount;
4863   unsigned int size = getDataSize (IC_RESULT (ic));
4864
4865   /* will try to generate an increment */
4866   /* if the right side is not a literal
4867      we cannot */
4868   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4869     return FALSE;
4870
4871   /* if the literal value of the right hand side
4872      is greater than 4 then it is not worth it */
4873   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4874     return FALSE;
4875
4876   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4877       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4878       while (icount--) {
4879           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4880       }
4881       return TRUE;
4882   }
4883   /* if decrement 16 bits in register */
4884   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4885       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4886       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4887       (size > 1) &&
4888       (icount == 1))
4889     {
4890       symbol *tlbl;
4891       int    emitTlbl;
4892       int    labelRange;
4893       char   *l;
4894
4895       /* If the next instruction is a goto and the goto target
4896          * is <= 5 instructions previous to this, we can generate
4897          * jumps straight to that target.
4898        */
4899       if (ic->next && ic->next->op == GOTO
4900           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4901           && labelRange <= 5)
4902         {
4903           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4904           tlbl = IC_LABEL (ic->next);
4905           emitTlbl = 0;
4906         }
4907       else
4908         {
4909           tlbl = newiTempLabel (NULL);
4910           emitTlbl = 1;
4911         }
4912
4913       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4914       emitcode ("dec", "%s", l);
4915
4916       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4917           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4918           IS_AOP_PREG (IC_RESULT (ic)))
4919       {
4920           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4921       }
4922       else
4923       {
4924           emitcode ("mov", "a,#!constbyte",0xff);
4925           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4926       }
4927       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4928       emitcode ("dec", "%s", l);
4929       if (size > 2)
4930         {
4931             if (!strcmp(l, "acc"))
4932             {
4933                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4934             }
4935             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4936                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4937                      IS_AOP_PREG (IC_RESULT (ic)))
4938             {
4939                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4940             }
4941             else
4942             {
4943                 emitcode ("mov", "a,#!constbyte",0xff);
4944                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4945             }
4946             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4947             emitcode ("dec", "%s", l);
4948         }
4949       if (size > 3)
4950         {
4951             if (!strcmp(l, "acc"))
4952             {
4953                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4954             }
4955             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4956                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4957                      IS_AOP_PREG (IC_RESULT (ic)))
4958             {
4959                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4960             }
4961             else
4962             {
4963                 emitcode ("mov", "a,#!constbyte",0xff);
4964                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4965             }
4966             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4967             emitcode ("dec", "%s", l);
4968         }
4969       if (emitTlbl)
4970         {
4971           emitLabel (tlbl);
4972         }
4973       return TRUE;
4974     }
4975
4976   /* if the sizes are greater than 1 then we cannot */
4977   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4978       AOP_SIZE (IC_LEFT (ic)) > 1)
4979     return FALSE;
4980
4981   /* we can if the aops of the left & result match or
4982      if they are in registers and the registers are the
4983      same */
4984   if (
4985        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4986        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4987        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4988     {
4989       char *l;
4990
4991       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4992         {
4993           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4994           l = "a";
4995         }
4996       else
4997         {
4998           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
4999         }
5000
5001       _startLazyDPSEvaluation ();
5002       while (icount--)
5003         {
5004           emitcode ("dec", "%s", l);
5005         }
5006       _endLazyDPSEvaluation ();
5007
5008       if (AOP_NEEDSACC (IC_RESULT (ic)))
5009         aopPut (IC_RESULT (ic), "a", 0);
5010
5011       return TRUE;
5012     }
5013
5014   return FALSE;
5015 }
5016
5017 /*-----------------------------------------------------------------*/
5018 /* addSign - complete with sign                                    */
5019 /*-----------------------------------------------------------------*/
5020 static void
5021 addSign (operand * result, int offset, int sign)
5022 {
5023   int size = (getDataSize (result) - offset);
5024   if (size > 0)
5025     {
5026       _startLazyDPSEvaluation();
5027       if (sign)
5028         {
5029           emitcode ("rlc", "a");
5030           emitcode ("subb", "a,acc");
5031           while (size--)
5032             {
5033               aopPut (result, "a", offset++);
5034             }
5035         }
5036       else
5037       {
5038         while (size--)
5039         {
5040           aopPut (result, zero, offset++);
5041         }
5042       }
5043       _endLazyDPSEvaluation();
5044     }
5045 }
5046
5047 /*-----------------------------------------------------------------*/
5048 /* genMinusBits - generates code for subtraction  of two bits      */
5049 /*-----------------------------------------------------------------*/
5050 static void
5051 genMinusBits (iCode * ic)
5052 {
5053   symbol *lbl = newiTempLabel (NULL);
5054
5055   D (emitcode (";", "genMinusBits"));
5056
5057   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5058     {
5059       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5060       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5061       emitcode ("cpl", "c");
5062       emitLabel (lbl);
5063       outBitC (IC_RESULT (ic));
5064     }
5065   else
5066     {
5067       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5068       emitcode ("subb", "a,acc");
5069       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5070       emitcode ("inc", "a");
5071       emitLabel (lbl);
5072       aopPut (IC_RESULT (ic), "a", 0);
5073       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5074     }
5075 }
5076
5077 /*-----------------------------------------------------------------*/
5078 /* genMinus - generates code for subtraction                       */
5079 /*-----------------------------------------------------------------*/
5080 static void
5081 genMinus (iCode * ic)
5082 {
5083     int size, offset = 0;
5084     int rSize;
5085     long lit = 0L;
5086     bool pushResult;
5087
5088     D (emitcode (";", "genMinus"));
5089
5090     AOP_OP_3_NOFATAL(ic, pushResult);
5091
5092     if (!pushResult)
5093     {
5094       /* special cases :- */
5095       /* if both left & right are in bit space */
5096       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5097           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5098         {
5099           genMinusBits (ic);
5100           goto release;
5101         }
5102
5103       /* if I can do an decrement instead
5104          of subtract then GOOD for ME */
5105       if (genMinusDec (ic) == TRUE)
5106         goto release;
5107
5108     }
5109
5110   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5111
5112   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5113     {
5114       CLRC;
5115     }
5116   else
5117     {
5118       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5119       lit = -lit;
5120     }
5121
5122
5123   /* if literal, add a,#-lit, else normal subb */
5124   _startLazyDPSEvaluation ();
5125   while (size--) {
5126       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5127           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5128               emitcode ("mov","b,%s",
5129                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5130               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5131               emitcode ("subb","a,b");
5132           } else {
5133               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5134               emitcode ("subb", "a,%s",
5135                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5136                                 DP2_RESULT_REG));
5137           }
5138       } else {
5139           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5140           /* first add without previous c */
5141           if (!offset) {
5142               if (!size && lit==-1) {
5143                   emitcode ("dec", "a");
5144               } else {
5145                   emitcode ("add", "a,#!constbyte",
5146                             (unsigned int) (lit & 0x0FFL));
5147               }
5148           } else {
5149               emitcode ("addc", "a,#!constbyte",
5150                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5151           }
5152       }
5153
5154       if (pushResult) {
5155           emitcode ("push", "acc");
5156       } else {
5157           aopPut (IC_RESULT (ic), "a", offset);
5158       }
5159       offset++;
5160   }
5161   _endLazyDPSEvaluation ();
5162
5163   if (pushResult)
5164     {
5165       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5166
5167       size = getDataSize (IC_LEFT (ic));
5168       rSize = getDataSize (IC_RESULT (ic));
5169
5170       ADJUST_PUSHED_RESULT(size, rSize);
5171
5172       _startLazyDPSEvaluation ();
5173       while (size--)
5174         {
5175           emitcode ("pop", "acc");
5176           aopPut (IC_RESULT (ic), "a", size);
5177         }
5178       _endLazyDPSEvaluation ();
5179     }
5180
5181   adjustArithmeticResult (ic);
5182
5183 release:
5184   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5185   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5186   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5187 }
5188
5189
5190 /*-----------------------------------------------------------------*/
5191 /* genMultbits :- multiplication of bits                           */
5192 /*-----------------------------------------------------------------*/
5193 static void
5194 genMultbits (operand * left,
5195              operand * right,
5196              operand * result,
5197              iCode   * ic)
5198 {
5199   D (emitcode (";", "genMultbits"));
5200
5201   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5202   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5203   aopOp(result, ic, TRUE, FALSE);
5204   outBitC (result);
5205 }
5206
5207 /*-----------------------------------------------------------------*/
5208 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5209 /*-----------------------------------------------------------------*/
5210 static void
5211 genMultOneByte (operand * left,
5212                 operand * right,
5213                 operand * result,
5214                 iCode   * ic)
5215 {
5216   symbol *lbl;
5217   int size;
5218   bool runtimeSign, compiletimeSign;
5219   bool lUnsigned, rUnsigned, pushedB;
5220
5221   /* (if two literals: the value is computed before) */
5222   /* if one literal, literal on the right */
5223   if (AOP_TYPE (left) == AOP_LIT)
5224     {
5225       operand *t = right;
5226       right = left;
5227       left = t;
5228       /* emitcode (";", "swapped left and right"); */
5229     }
5230   /* if no literal, unsigned on the right: shorter code */
5231   if (   AOP_TYPE (right) != AOP_LIT
5232       && SPEC_USIGN (getSpec (operandType (left))))
5233     {
5234       operand *t = right;
5235       right = left;
5236       left = t;
5237     }
5238
5239   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5240   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5241
5242   pushedB = pushB ();
5243
5244   if ((lUnsigned && rUnsigned)
5245 /* sorry, I don't know how to get size
5246    without calling aopOp (result,...);
5247    see Feature Request  */
5248       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5249                    no need to take care about the signedness! */
5250     {
5251       /* just an unsigned 8 * 8 = 8 multiply
5252          or 8u * 8u = 16u */
5253       /* emitcode (";","unsigned"); */
5254       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5255       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5256       emitcode ("mul", "ab");
5257
5258       _G.accInUse++;
5259       aopOp (result, ic, TRUE, FALSE);
5260       size = AOP_SIZE (result);
5261
5262       if (size < 1 || size > 2)
5263         {
5264           /* this should never happen */
5265           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5266                    size, __FILE__, lineno);
5267           exit (1);
5268         }
5269
5270       aopPut (result, "a", 0);
5271       _G.accInUse--;
5272       if (size == 2)
5273         aopPut (result, "b", 1);
5274
5275       popB (pushedB);
5276       return;
5277     }
5278
5279   /* we have to do a signed multiply */
5280   /* emitcode (";", "signed"); */
5281
5282   /* now sign adjust for both left & right */
5283
5284   /* let's see what's needed: */
5285   /* apply negative sign during runtime */
5286   runtimeSign = FALSE;
5287   /* negative sign from literals */
5288   compiletimeSign = FALSE;
5289
5290   if (!lUnsigned)
5291     {
5292       if (AOP_TYPE(left) == AOP_LIT)
5293         {
5294           /* signed literal */
5295           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5296           if (val < 0)
5297             compiletimeSign = TRUE;
5298         }
5299       else
5300         /* signed but not literal */
5301         runtimeSign = TRUE;
5302     }
5303
5304   if (!rUnsigned)
5305     {
5306       if (AOP_TYPE(right) == AOP_LIT)
5307         {
5308           /* signed literal */
5309           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5310           if (val < 0)
5311             compiletimeSign ^= TRUE;
5312         }
5313       else
5314         /* signed but not literal */
5315         runtimeSign = TRUE;
5316     }
5317
5318   /* initialize F0, which stores the runtime sign */
5319   if (runtimeSign)
5320     {
5321       if (compiletimeSign)
5322         emitcode ("setb", "F0"); /* set sign flag */
5323       else
5324         emitcode ("clr", "F0"); /* reset sign flag */
5325     }
5326
5327   /* save the signs of the operands */
5328   if (AOP_TYPE(right) == AOP_LIT)
5329     {
5330       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5331
5332       if (!rUnsigned && val < 0)
5333         emitcode ("mov", "b,#!constbyte", -val);
5334       else
5335         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5336     }
5337   else /* ! literal */
5338     {
5339       if (rUnsigned)  /* emitcode (";", "signed"); */
5340         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5341       else
5342         {
5343           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5344           lbl = newiTempLabel (NULL);
5345           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5346           emitcode ("cpl", "F0"); /* complement sign flag */
5347           emitcode ("cpl", "a");  /* 2's complement */
5348           emitcode ("inc", "a");
5349           emitLabel (lbl);
5350           emitcode ("mov", "b,a");
5351         }
5352     }
5353
5354   if (AOP_TYPE(left) == AOP_LIT)
5355     {
5356       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5357
5358       if (!lUnsigned && val < 0)
5359         emitcode ("mov", "a,#!constbyte", -val);
5360       else
5361         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5362     }
5363   else /* ! literal */
5364     {
5365       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5366
5367       if (!lUnsigned)  /* emitcode (";", "signed"); */
5368         {
5369           lbl = newiTempLabel (NULL);
5370           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5371           emitcode ("cpl", "F0"); /* complement sign flag */
5372           emitcode ("cpl", "a");  /* 2's complement */
5373           emitcode ("inc", "a");
5374           emitLabel (lbl);
5375         }
5376     }
5377
5378   /* now the multiplication */
5379   emitcode ("mul", "ab");
5380   _G.accInUse++;
5381   aopOp(result, ic, TRUE, FALSE);
5382   size = AOP_SIZE (result);
5383
5384   if (size < 1 || size > 2)
5385     {
5386       /* this should never happen */
5387       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5388                size, __FILE__, lineno);
5389       exit (1);
5390     }
5391
5392   if (runtimeSign || compiletimeSign)
5393     {
5394       lbl = newiTempLabel (NULL);
5395       if (runtimeSign)
5396         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5397       emitcode ("cpl", "a"); /* lsb 2's complement */
5398       if (size != 2)
5399         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5400       else
5401         {
5402           emitcode ("add", "a,#1"); /* this sets carry flag */
5403           emitcode ("xch", "a,b");
5404           emitcode ("cpl", "a"); /* msb 2's complement */
5405           emitcode ("addc", "a,#0");
5406           emitcode ("xch", "a,b");
5407         }
5408       emitLabel (lbl);
5409     }
5410   aopPut (result, "a", 0);
5411   _G.accInUse--;
5412   if (size == 2)
5413     aopPut (result, "b", 1);
5414
5415   popB (pushedB);
5416 }
5417
5418 /*-----------------------------------------------------------------*/
5419 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5420 /*-----------------------------------------------------------------*/
5421 static void genMultTwoByte (operand *left, operand *right,
5422                             operand *result, iCode *ic)
5423 {
5424         sym_link *retype = getSpec(operandType(right));
5425         sym_link *letype = getSpec(operandType(left));
5426         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5427         symbol *lbl;
5428
5429         if (AOP_TYPE (left) == AOP_LIT) {
5430                 operand *t = right;
5431                 right = left;
5432                 left = t;
5433         }
5434         /* save EA bit in F1 */
5435         lbl = newiTempLabel(NULL);
5436         emitcode ("setb","F1");
5437         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5438         emitcode ("clr","F1");
5439         emitLabel (lbl);
5440
5441         /* load up MB with right */
5442         if (!umult) {
5443                 emitcode("clr","F0");
5444                 if (AOP_TYPE(right) == AOP_LIT) {
5445                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5446                         if (val < 0) {
5447                                 emitcode("setb","F0");
5448                                 val = -val;
5449                         }
5450                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5451                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5452                 } else {
5453                         lbl = newiTempLabel(NULL);
5454                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5455                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5456                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5457                         emitcode ("xch", "a,b");
5458                         emitcode ("cpl","a");
5459                         emitcode ("add", "a,#1");
5460                         emitcode ("xch", "a,b");
5461                         emitcode ("cpl", "a"); // msb
5462                         emitcode ("addc", "a,#0");
5463                         emitcode ("setb","F0");
5464                         emitLabel (lbl);
5465                         emitcode ("mov","mb,b");
5466                         emitcode ("mov","mb,a");
5467                 }
5468         } else {
5469                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5470                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5471         }
5472         /* load up MA with left */
5473         if (!umult) {
5474                 lbl = newiTempLabel(NULL);
5475                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5476                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5477                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5478                 emitcode ("xch", "a,b");
5479                 emitcode ("cpl","a");
5480                 emitcode ("add", "a,#1");
5481                 emitcode ("xch", "a,b");
5482                 emitcode ("cpl", "a"); // msb
5483                 emitcode ("addc","a,#0");
5484                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5485                 emitcode ("setb","F0");
5486                 emitLabel (lbl);
5487                 emitcode ("mov","ma,b");
5488                 emitcode ("mov","ma,a");
5489         } else {
5490                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5491                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5492         }
5493         /* wait for multiplication to finish */
5494         lbl = newiTempLabel(NULL);
5495         emitLabel (lbl);
5496         emitcode("mov","a,mcnt1");
5497         emitcode("anl","a,#!constbyte",0x80);
5498         emitcode("jnz","!tlabel",lbl->key+100);
5499
5500         freeAsmop (left, NULL, ic, TRUE);
5501         freeAsmop (right, NULL, ic,TRUE);
5502         aopOp(result, ic, TRUE, FALSE);
5503
5504         /* if unsigned then simple */
5505         if (umult) {
5506                 emitcode ("mov","a,ma");
5507                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5508                 emitcode ("mov","a,ma");
5509                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5510                 aopPut(result,"ma",1);
5511                 aopPut(result,"ma",0);
5512         } else {
5513                 emitcode("push","ma");
5514                 emitcode("push","ma");
5515                 emitcode("push","ma");
5516                 MOVA("ma");
5517                 /* negate result if needed */
5518                 lbl = newiTempLabel(NULL);
5519                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5520                 emitcode("cpl","a");
5521                 emitcode("add","a,#1");
5522                 emitLabel (lbl);
5523                 if (AOP_TYPE(result) == AOP_ACC)
5524                 {
5525                     D (emitcode(";", "ACC special case."));
5526                     /* We know result is the only live aop, and
5527                      * it's obviously not a DPTR2, so AP is available.
5528                      */
5529                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5530                 }
5531                 else
5532                 {
5533                     aopPut(result,"a",0);
5534                 }
5535
5536                 emitcode("pop","acc");
5537                 lbl = newiTempLabel(NULL);
5538                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5539                 emitcode("cpl","a");
5540                 emitcode("addc","a,#0");
5541                 emitLabel (lbl);
5542                 aopPut(result,"a",1);
5543                 emitcode("pop","acc");
5544                 if (AOP_SIZE(result) >= 3) {
5545                         lbl = newiTempLabel(NULL);
5546                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5547                         emitcode("cpl","a");
5548                         emitcode("addc","a,#0");
5549                         emitLabel (lbl);
5550                         aopPut(result,"a",2);
5551                 }
5552                 emitcode("pop","acc");
5553                 if (AOP_SIZE(result) >= 4) {
5554                         lbl = newiTempLabel(NULL);
5555                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5556                         emitcode("cpl","a");
5557                         emitcode("addc","a,#0");
5558                         emitLabel (lbl);
5559                         aopPut(result,"a",3);
5560                 }
5561                 if (AOP_TYPE(result) == AOP_ACC)
5562                 {
5563                     /* We stashed the result away above. */
5564                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5565                 }
5566
5567         }
5568         freeAsmop (result, NULL, ic, TRUE);
5569
5570         /* restore EA bit in F1 */
5571         lbl = newiTempLabel(NULL);
5572         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5573         emitcode ("setb","EA");
5574         emitLabel (lbl);
5575         return ;
5576 }
5577
5578 /*-----------------------------------------------------------------*/
5579 /* genMult - generates code for multiplication                     */
5580 /*-----------------------------------------------------------------*/
5581 static void
5582 genMult (iCode * ic)
5583 {
5584   operand *left = IC_LEFT (ic);
5585   operand *right = IC_RIGHT (ic);
5586   operand *result = IC_RESULT (ic);
5587
5588   D (emitcode (";", "genMult"));
5589
5590   /* assign the asmops */
5591   AOP_OP_2 (ic);
5592
5593   /* special cases first */
5594   /* both are bits */
5595   if (AOP_TYPE (left) == AOP_CRY &&
5596       AOP_TYPE (right) == AOP_CRY)
5597     {
5598       genMultbits (left, right, result, ic);
5599       goto release;
5600     }
5601
5602   /* if both are of size == 1 */
5603   if (AOP_SIZE (left) == 1 &&
5604       AOP_SIZE (right) == 1)
5605     {
5606       genMultOneByte (left, right, result, ic);
5607       goto release;
5608     }
5609
5610   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5611           /* use the ds390 ARITHMETIC accel UNIT */
5612           genMultTwoByte (left, right, result, ic);
5613           return ;
5614   }
5615   /* should have been converted to function call */
5616   assert (0);
5617
5618 release:
5619   freeAsmop (result, NULL, ic, TRUE);
5620   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5621   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5622 }
5623
5624 /*-----------------------------------------------------------------*/
5625 /* genDivbits :- division of bits                                  */
5626 /*-----------------------------------------------------------------*/
5627 static void
5628 genDivbits (operand * left,
5629             operand * right,
5630             operand * result,
5631             iCode   * ic)
5632 {
5633   char *l;
5634   bool pushedB;
5635
5636   D(emitcode (";     genDivbits",""));
5637
5638   pushedB = pushB ();
5639
5640   /* the result must be bit */
5641   LOAD_AB_FOR_DIV (left, right, l);
5642   emitcode ("div", "ab");
5643   emitcode ("rrc", "a");
5644   aopOp(result, ic, TRUE, FALSE);
5645
5646   popB (pushedB);
5647
5648   aopPut (result, "c", 0);
5649 }
5650
5651 /*-----------------------------------------------------------------*/
5652 /* genDivOneByte : 8 bit division                                  */
5653 /*-----------------------------------------------------------------*/
5654 static void
5655 genDivOneByte (operand * left,
5656                operand * right,
5657                operand * result,
5658                iCode   * ic)
5659 {
5660   bool lUnsigned, rUnsigned, pushedB;
5661   bool runtimeSign, compiletimeSign;
5662   char *l;
5663   symbol *lbl;
5664   int size, offset;
5665
5666   D(emitcode (";     genDivOneByte",""));
5667
5668   offset = 1;
5669   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5670   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5671
5672   pushedB = pushB ();
5673
5674   /* signed or unsigned */
5675   if (lUnsigned && rUnsigned)
5676     {
5677       /* unsigned is easy */
5678       LOAD_AB_FOR_DIV (left, right, l);
5679       emitcode ("div", "ab");
5680
5681       _G.accInUse++;
5682       aopOp (result, ic, TRUE, FALSE);
5683       aopPut (result, "a", 0);
5684       _G.accInUse--;
5685
5686       size = AOP_SIZE (result) - 1;
5687
5688       while (size--)
5689         aopPut (result, zero, offset++);
5690
5691       popB (pushedB);
5692       return;
5693     }
5694
5695   /* signed is a little bit more difficult */
5696
5697   /* now sign adjust for both left & right */
5698
5699   /* let's see what's needed: */
5700   /* apply negative sign during runtime */
5701   runtimeSign = FALSE;
5702   /* negative sign from literals */
5703   compiletimeSign = FALSE;
5704
5705   if (!lUnsigned)
5706     {
5707       if (AOP_TYPE(left) == AOP_LIT)
5708         {
5709           /* signed literal */
5710           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5711           if (val < 0)
5712             compiletimeSign = TRUE;
5713         }
5714       else
5715         /* signed but not literal */
5716         runtimeSign = TRUE;
5717     }
5718
5719   if (!rUnsigned)
5720     {
5721       if (AOP_TYPE(right) == AOP_LIT)
5722         {
5723           /* signed literal */
5724           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5725           if (val < 0)
5726             compiletimeSign ^= TRUE;
5727         }
5728       else
5729         /* signed but not literal */
5730         runtimeSign = TRUE;
5731     }
5732
5733   /* initialize F0, which stores the runtime sign */
5734   if (runtimeSign)
5735     {
5736       if (compiletimeSign)
5737         emitcode ("setb", "F0"); /* set sign flag */
5738       else
5739         emitcode ("clr", "F0"); /* reset sign flag */
5740     }
5741
5742   /* save the signs of the operands */
5743   if (AOP_TYPE(right) == AOP_LIT)
5744     {
5745       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5746
5747       if (!rUnsigned && val < 0)
5748         emitcode ("mov", "b,#0x%02x", -val);
5749       else
5750         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5751     }
5752   else /* ! literal */
5753     {
5754       if (rUnsigned)
5755         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5756       else
5757         {
5758           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5759           lbl = newiTempLabel (NULL);
5760           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5761           emitcode ("cpl", "F0"); /* complement sign flag */
5762           emitcode ("cpl", "a");  /* 2's complement */
5763           emitcode ("inc", "a");
5764           emitLabel (lbl);
5765           emitcode ("mov", "b,a");
5766         }
5767     }
5768
5769   if (AOP_TYPE(left) == AOP_LIT)
5770     {
5771       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5772
5773       if (!lUnsigned && val < 0)
5774         emitcode ("mov", "a,#0x%02x", -val);
5775       else
5776         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5777     }
5778   else /* ! literal */
5779     {
5780       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5781
5782       if (!lUnsigned)
5783         {
5784           lbl = newiTempLabel (NULL);
5785           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5786           emitcode ("cpl", "F0"); /* complement sign flag */
5787           emitcode ("cpl", "a");  /* 2's complement */
5788           emitcode ("inc", "a");
5789           emitLabel (lbl);
5790         }
5791     }
5792
5793   /* now the division */
5794   emitcode ("nop", "; workaround for DS80C390 div bug.");
5795   emitcode ("div", "ab");
5796
5797   if (runtimeSign || compiletimeSign)
5798     {
5799       lbl = newiTempLabel (NULL);
5800       if (runtimeSign)
5801         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5802       emitcode ("cpl", "a"); /* lsb 2's complement */
5803       emitcode ("inc", "a");
5804       emitLabel (lbl);
5805
5806       _G.accInUse++;
5807       aopOp (result, ic, TRUE, FALSE);
5808       size = AOP_SIZE (result) - 1;
5809
5810       if (size > 0)
5811         {
5812           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5813              then the result will be in b, a */
5814           emitcode ("mov", "b,a"); /* 1 */
5815           /* msb is 0x00 or 0xff depending on the sign */
5816           if (runtimeSign)
5817             {
5818               emitcode ("mov",  "c,F0");
5819               emitcode ("subb", "a,acc");
5820               emitcode ("xch",  "a,b"); /* 2 */
5821               while (size--)
5822                 aopPut (result, "b", offset++); /* write msb's */
5823             }
5824           else /* compiletimeSign */
5825             while (size--)
5826               aopPut (result, "#0xff", offset++); /* write msb's */
5827         }
5828       aopPut (result, "a", 0); /* 3: write lsb */
5829     }
5830   else
5831     {
5832       _G.accInUse++;
5833       aopOp(result, ic, TRUE, FALSE);
5834       size = AOP_SIZE (result) - 1;
5835
5836       aopPut (result, "a", 0);
5837       while (size--)
5838         aopPut (result, zero, offset++);
5839     }
5840   _G.accInUse--;
5841   popB (pushedB);
5842 }
5843
5844 /*-----------------------------------------------------------------*/
5845 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5846 /*-----------------------------------------------------------------*/
5847 static void genDivTwoByte (operand *left, operand *right,
5848                             operand *result, iCode *ic)
5849 {
5850         sym_link *retype = getSpec(operandType(right));
5851         sym_link *letype = getSpec(operandType(left));
5852         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5853         symbol *lbl;
5854
5855         /* save EA bit in F1 */
5856         lbl = newiTempLabel(NULL);
5857         emitcode ("setb","F1");
5858         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5859         emitcode ("clr","F1");
5860         emitLabel (lbl);
5861
5862         /* load up MA with left */
5863         if (!umult) {
5864                 emitcode("clr","F0");
5865                 lbl = newiTempLabel(NULL);
5866                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5867                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5868                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5869                 emitcode ("xch", "a,b");
5870                 emitcode ("cpl","a");
5871                 emitcode ("add", "a,#1");
5872                 emitcode ("xch", "a,b");
5873                 emitcode ("cpl", "a"); // msb
5874                 emitcode ("addc","a,#0");
5875                 emitcode ("setb","F0");
5876                 emitLabel (lbl);
5877                 emitcode ("mov","ma,b");
5878                 emitcode ("mov","ma,a");
5879         } else {
5880                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5881                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5882         }
5883
5884         /* load up MB with right */
5885         if (!umult) {
5886                 if (AOP_TYPE(right) == AOP_LIT) {
5887                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5888                         if (val < 0) {
5889                                 lbl = newiTempLabel(NULL);
5890                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5891                                 emitcode("setb","F0");
5892                                 emitLabel (lbl);
5893                                 val = -val;
5894                         }
5895                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5896                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5897                 } else {
5898                         lbl = newiTempLabel(NULL);
5899                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5900                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5901                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5902                         emitcode ("xch", "a,b");
5903                         emitcode ("cpl","a");
5904                         emitcode ("add", "a,#1");
5905                         emitcode ("xch", "a,b");
5906                         emitcode ("cpl", "a"); // msb
5907                         emitcode ("addc", "a,#0");
5908                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5909                         emitcode ("setb","F0");
5910                         emitLabel (lbl);
5911                         emitcode ("mov","mb,b");
5912                         emitcode ("mov","mb,a");
5913                 }
5914         } else {
5915                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5916                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5917         }
5918
5919         /* wait for multiplication to finish */
5920         lbl = newiTempLabel(NULL);
5921         emitLabel (lbl);
5922         emitcode("mov","a,mcnt1");
5923         emitcode("anl","a,#!constbyte",0x80);
5924         emitcode("jnz","!tlabel",lbl->key+100);
5925
5926         freeAsmop (left, NULL, ic, TRUE);
5927         freeAsmop (right, NULL, ic,TRUE);
5928         aopOp(result, ic, TRUE, FALSE);
5929
5930         /* if unsigned then simple */
5931         if (umult) {
5932                 aopPut(result,"ma",1);
5933                 aopPut(result,"ma",0);
5934         } else {
5935                 emitcode("push","ma");
5936                 MOVA("ma");
5937                 /* negate result if needed */
5938                 lbl = newiTempLabel(NULL);
5939                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5940                 emitcode("cpl","a");
5941                 emitcode("add","a,#1");
5942                 emitLabel (lbl);
5943                 aopPut(result,"a",0);
5944                 emitcode("pop","acc");
5945                 lbl = newiTempLabel(NULL);
5946                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5947                 emitcode("cpl","a");
5948                 emitcode("addc","a,#0");
5949                 emitLabel (lbl);
5950                 aopPut(result,"a",1);
5951         }
5952         freeAsmop (result, NULL, ic, TRUE);
5953         /* restore EA bit in F1 */
5954         lbl = newiTempLabel(NULL);
5955         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5956         emitcode ("setb","EA");
5957         emitLabel (lbl);
5958         return ;
5959 }
5960
5961 /*-----------------------------------------------------------------*/
5962 /* genDiv - generates code for division                            */
5963 /*-----------------------------------------------------------------*/
5964 static void
5965 genDiv (iCode * ic)
5966 {
5967   operand *left = IC_LEFT (ic);
5968   operand *right = IC_RIGHT (ic);
5969   operand *result = IC_RESULT (ic);
5970
5971   D (emitcode (";", "genDiv"));
5972
5973   /* assign the amsops */
5974   AOP_OP_2 (ic);
5975
5976   /* special cases first */
5977   /* both are bits */
5978   if (AOP_TYPE (left) == AOP_CRY &&
5979       AOP_TYPE (right) == AOP_CRY)
5980     {
5981       genDivbits (left, right, result, ic);
5982       goto release;
5983     }
5984
5985   /* if both are of size == 1 */
5986   if (AOP_SIZE (left) == 1 &&
5987       AOP_SIZE (right) == 1)
5988     {
5989       genDivOneByte (left, right, result, ic);
5990       goto release;
5991     }
5992
5993   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5994           /* use the ds390 ARITHMETIC accel UNIT */
5995           genDivTwoByte (left, right, result, ic);
5996           return ;
5997   }
5998   /* should have been converted to function call */
5999   assert (0);
6000 release:
6001   freeAsmop (result, NULL, ic, TRUE);
6002   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6003   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6004 }
6005
6006 /*-----------------------------------------------------------------*/
6007 /* genModbits :- modulus of bits                                   */
6008 /*-----------------------------------------------------------------*/
6009 static void
6010 genModbits (operand * left,
6011             operand * right,
6012             operand * result,
6013             iCode   * ic)
6014 {
6015   char *l;
6016   bool pushedB;
6017
6018   D (emitcode (";", "genModbits"));
6019
6020   pushedB = pushB ();
6021
6022   /* the result must be bit */
6023   LOAD_AB_FOR_DIV (left, right, l);
6024   emitcode ("div", "ab");
6025   emitcode ("mov", "a,b");
6026   emitcode ("rrc", "a");
6027   aopOp(result, ic, TRUE, FALSE);
6028
6029   popB (pushedB);
6030
6031   aopPut (result, "c", 0);
6032 }
6033
6034 /*-----------------------------------------------------------------*/
6035 /* genModOneByte : 8 bit modulus                                   */
6036 /*-----------------------------------------------------------------*/
6037 static void
6038 genModOneByte (operand * left,
6039                operand * right,
6040                operand * result,
6041                iCode   * ic)
6042 {
6043   bool lUnsigned, rUnsigned, pushedB;
6044   bool runtimeSign, compiletimeSign;
6045   char *l;
6046   symbol *lbl;
6047   int size, offset;
6048
6049   D (emitcode (";", "genModOneByte"));
6050
6051   offset = 1;
6052   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6053   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6054
6055   pushedB = pushB ();
6056
6057   /* signed or unsigned */
6058   if (lUnsigned && rUnsigned)
6059     {
6060       /* unsigned is easy */
6061       LOAD_AB_FOR_DIV (left, right, l);
6062       emitcode ("div", "ab");
6063       aopOp (result, ic, TRUE, FALSE);
6064       aopPut (result, "b", 0);
6065
6066       for (size = AOP_SIZE (result) - 1; size--;)
6067         aopPut (result, zero, offset++);
6068
6069       popB (pushedB);
6070       return;
6071     }
6072
6073   /* signed is a little bit more difficult */
6074
6075   /* now sign adjust for both left & right */
6076
6077   /* modulus: sign of the right operand has no influence on the result! */
6078   if (AOP_TYPE(right) == AOP_LIT)
6079     {
6080       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6081
6082       if (!rUnsigned && val < 0)
6083         emitcode ("mov", "b,#0x%02x", -val);
6084       else
6085         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6086     }
6087   else /* not literal */
6088     {
6089       if (rUnsigned)
6090         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6091       else
6092         {
6093           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6094           lbl = newiTempLabel (NULL);
6095           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6096           emitcode ("cpl", "a");  /* 2's complement */
6097           emitcode ("inc", "a");
6098           emitLabel (lbl);
6099           emitcode ("mov", "b,a");
6100         }
6101     }
6102
6103   /* let's see what's needed: */
6104   /* apply negative sign during runtime */
6105   runtimeSign = FALSE;
6106   /* negative sign from literals */
6107   compiletimeSign = FALSE;
6108
6109   /* sign adjust left side */
6110   if (AOP_TYPE(left) == AOP_LIT)
6111     {
6112       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6113
6114       if (!lUnsigned && val < 0)
6115         {
6116           compiletimeSign = TRUE; /* set sign flag */
6117           emitcode ("mov", "a,#0x%02x", -val);
6118         }
6119       else
6120         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6121     }
6122   else /* ! literal */
6123     {
6124       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6125
6126       if (!lUnsigned)
6127         {
6128           runtimeSign = TRUE;
6129           emitcode ("clr", "F0"); /* clear sign flag */
6130
6131           lbl = newiTempLabel (NULL);
6132           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6133           emitcode ("setb", "F0"); /* set sign flag */
6134           emitcode ("cpl", "a");   /* 2's complement */
6135           emitcode ("inc", "a");
6136           emitLabel (lbl);
6137         }
6138     }
6139
6140   /* now the modulus */
6141   emitcode ("nop", "; workaround for DS80C390 div bug.");
6142   emitcode ("div", "ab");
6143
6144   if (runtimeSign || compiletimeSign)
6145     {
6146       emitcode ("mov", "a,b");
6147       lbl = newiTempLabel (NULL);
6148       if (runtimeSign)
6149         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6150       emitcode ("cpl", "a"); /* lsb 2's complement */
6151       emitcode ("inc", "a");
6152       emitLabel (lbl);
6153
6154       _G.accInUse++;
6155       aopOp (result, ic, TRUE, FALSE);
6156       size = AOP_SIZE (result) - 1;
6157
6158       if (size > 0)
6159         {
6160           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6161              then the result will be in b, a */
6162           emitcode ("mov", "b,a"); /* 1 */
6163           /* msb is 0x00 or 0xff depending on the sign */
6164           if (runtimeSign)
6165             {
6166               emitcode ("mov",  "c,F0");
6167               emitcode ("subb", "a,acc");
6168               emitcode ("xch",  "a,b"); /* 2 */
6169               while (size--)
6170                 aopPut (result, "b", offset++); /* write msb's */
6171             }
6172           else /* compiletimeSign */
6173             while (size--)
6174               aopPut (result, "#0xff", offset++); /* write msb's */
6175         }
6176       aopPut (result, "a", 0); /* 3: write lsb */
6177     }
6178   else
6179     {
6180       _G.accInUse++;
6181       aopOp(result, ic, TRUE, FALSE);
6182       size = AOP_SIZE (result) - 1;
6183
6184       aopPut (result, "b", 0);
6185       while (size--)
6186         aopPut (result, zero, offset++);
6187     }
6188   _G.accInUse--;
6189   popB (pushedB);
6190 }
6191
6192 /*-----------------------------------------------------------------*/
6193 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6194 /*-----------------------------------------------------------------*/
6195 static void genModTwoByte (operand *left, operand *right,
6196                             operand *result, iCode *ic)
6197 {
6198         sym_link *retype = getSpec(operandType(right));
6199         sym_link *letype = getSpec(operandType(left));
6200         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6201         symbol *lbl;
6202
6203         /* load up MA with left */
6204         /* save EA bit in F1 */
6205         lbl = newiTempLabel(NULL);
6206         emitcode ("setb","F1");
6207         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6208         emitcode ("clr","F1");
6209         emitLabel (lbl);
6210
6211         if (!umult) {
6212                 lbl = newiTempLabel(NULL);
6213                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6214                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6215                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6216                 emitcode ("xch", "a,b");
6217                 emitcode ("cpl","a");
6218                 emitcode ("add", "a,#1");
6219                 emitcode ("xch", "a,b");
6220                 emitcode ("cpl", "a"); // msb
6221                 emitcode ("addc","a,#0");
6222                 emitLabel (lbl);
6223                 emitcode ("mov","ma,b");
6224                 emitcode ("mov","ma,a");
6225         } else {
6226                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6227                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6228         }
6229
6230         /* load up MB with right */
6231         if (!umult) {
6232                 if (AOP_TYPE(right) == AOP_LIT) {
6233                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6234                         if (val < 0) {
6235                                 val = -val;
6236                         }
6237                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6238                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6239                 } else {
6240                         lbl = newiTempLabel(NULL);
6241                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6242                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6243                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6244                         emitcode ("xch", "a,b");
6245                         emitcode ("cpl","a");
6246                         emitcode ("add", "a,#1");
6247                         emitcode ("xch", "a,b");
6248                         emitcode ("cpl", "a"); // msb
6249                         emitcode ("addc", "a,#0");
6250                         emitLabel (lbl);
6251                         emitcode ("mov","mb,b");
6252                         emitcode ("mov","mb,a");
6253                 }
6254         } else {
6255                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6256                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6257         }
6258
6259         /* wait for multiplication to finish */
6260         lbl = newiTempLabel(NULL);
6261         emitLabel (lbl);
6262         emitcode("mov","a,mcnt1");
6263         emitcode("anl","a,#!constbyte",0x80);
6264         emitcode("jnz","!tlabel",lbl->key+100);
6265
6266         freeAsmop (left, NULL, ic, TRUE);
6267         freeAsmop (right, NULL, ic,TRUE);
6268         aopOp(result, ic, TRUE, FALSE);
6269
6270         aopPut(result,"mb",1);
6271         aopPut(result,"mb",0);
6272         freeAsmop (result, NULL, ic, TRUE);
6273
6274         /* restore EA bit in F1 */
6275         lbl = newiTempLabel(NULL);
6276         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6277         emitcode ("setb","EA");
6278         emitLabel (lbl);
6279 }
6280
6281 /*-----------------------------------------------------------------*/
6282 /* genMod - generates code for division                            */
6283 /*-----------------------------------------------------------------*/
6284 static void
6285 genMod (iCode * ic)
6286 {
6287   operand *left = IC_LEFT (ic);
6288   operand *right = IC_RIGHT (ic);
6289   operand *result = IC_RESULT (ic);
6290
6291   D (emitcode (";", "genMod"));
6292
6293   /* assign the asmops */
6294   AOP_OP_2 (ic);
6295
6296   /* special cases first */
6297   /* both are bits */
6298   if (AOP_TYPE (left) == AOP_CRY &&
6299       AOP_TYPE (right) == AOP_CRY)
6300     {
6301       genModbits (left, right, result, ic);
6302       goto release;
6303     }
6304
6305   /* if both are of size == 1 */
6306   if (AOP_SIZE (left) == 1 &&
6307       AOP_SIZE (right) == 1)
6308     {
6309       genModOneByte (left, right, result, ic);
6310       goto release;
6311     }
6312
6313   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6314           /* use the ds390 ARITHMETIC accel UNIT */
6315           genModTwoByte (left, right, result, ic);
6316           return ;
6317   }
6318
6319   /* should have been converted to function call */
6320   assert (0);
6321
6322 release:
6323   freeAsmop (result, NULL, ic, TRUE);
6324   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6325   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326 }
6327
6328 /*-----------------------------------------------------------------*/
6329 /* genIfxJump :- will create a jump depending on the ifx           */
6330 /*-----------------------------------------------------------------*/
6331 static void
6332 genIfxJump (iCode * ic, char *jval)
6333 {
6334   symbol *jlbl;
6335   symbol *tlbl = newiTempLabel (NULL);
6336   char *inst;
6337
6338   D (emitcode (";", "genIfxJump"));
6339
6340   /* if true label then we jump if condition
6341      supplied is true */
6342   if (IC_TRUE (ic))
6343     {
6344       jlbl = IC_TRUE (ic);
6345       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6346                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6347     }
6348   else
6349     {
6350       /* false label is present */
6351       jlbl = IC_FALSE (ic);
6352       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6353                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6354     }
6355   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6356     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6357   else
6358     emitcode (inst, "!tlabel", tlbl->key + 100);
6359   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6360   emitLabel (tlbl);
6361
6362   /* mark the icode as generated */
6363   ic->generated = 1;
6364 }
6365
6366 /*-----------------------------------------------------------------*/
6367 /* genCmp :- greater or less than comparison                       */
6368 /*-----------------------------------------------------------------*/
6369 static void
6370 genCmp (operand * left, operand * right,
6371         iCode * ic, iCode * ifx, int sign)
6372 {
6373   int size, offset = 0;
6374   unsigned long lit = 0L;
6375   operand *result;
6376
6377   D (emitcode (";", "genCmp"));
6378
6379   result = IC_RESULT (ic);
6380
6381   /* if left & right are bit variables */
6382   if (AOP_TYPE (left) == AOP_CRY &&
6383       AOP_TYPE (right) == AOP_CRY)
6384     {
6385       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6386       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6387     }
6388   else
6389     {
6390       /* subtract right from left if at the
6391          end the carry flag is set then we know that
6392          left is greater than right */
6393       size = max (AOP_SIZE (left), AOP_SIZE (right));
6394
6395       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6396       if ((size == 1) && !sign &&
6397           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6398         {
6399           symbol *lbl = newiTempLabel (NULL);
6400           emitcode ("cjne", "%s,%s,!tlabel",
6401                     aopGet (left, offset, FALSE, FALSE, NULL),
6402                     aopGet (right, offset, FALSE, FALSE, NULL),
6403                     lbl->key + 100);
6404           emitLabel (lbl);
6405         }
6406       else
6407         {
6408           if (AOP_TYPE (right) == AOP_LIT)
6409             {
6410               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6411               /* optimize if(x < 0) or if(x >= 0) */
6412               if (lit == 0L)
6413                 {
6414                   if (!sign)
6415                     {
6416                       CLRC;
6417                     }
6418                   else
6419                     {
6420                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6421
6422                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6423                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424
6425                       aopOp (result, ic, FALSE, FALSE);
6426
6427                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6428                         {
6429                           freeAsmop (result, NULL, ic, TRUE);
6430                           genIfxJump (ifx, "acc.7");
6431                           return;
6432                         }
6433                       else
6434                         {
6435                           emitcode ("rlc", "a");
6436                         }
6437                       goto release_freedLR;
6438                     }
6439                   goto release;
6440                 }
6441             }
6442           CLRC;
6443           while (size--)
6444             {
6445               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6446               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6447               // emitcode (";", "genCmp #2");
6448               if (sign && (size == 0))
6449                 {
6450                   // emitcode (";", "genCmp #3");
6451                   emitcode ("xrl", "a,#!constbyte",0x80);
6452                   if (AOP_TYPE (right) == AOP_LIT)
6453                     {
6454                       unsigned long lit = (unsigned long)
6455                       floatFromVal (AOP (right)->aopu.aop_lit);
6456                       // emitcode (";", "genCmp #3.1");
6457                       emitcode ("subb", "a,#!constbyte",
6458                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6459                     }
6460                   else
6461                     {
6462                       // emitcode (";", "genCmp #3.2");
6463                       saveAccWarn = 0;
6464                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6465                       saveAccWarn = DEFAULT_ACC_WARNING;
6466                       emitcode ("xrl", "b,#!constbyte",0x80);
6467                       emitcode ("subb", "a,b");
6468                     }
6469                 }
6470               else
6471                 {
6472                   const char *s;
6473
6474                   // emitcode (";", "genCmp #4");
6475                   saveAccWarn = 0;
6476                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6477                   saveAccWarn = DEFAULT_ACC_WARNING;
6478
6479                   emitcode ("subb", "a,%s", s);
6480                 }
6481             }
6482         }
6483     }
6484
6485 release:
6486 /* Don't need the left & right operands any more; do need the result. */
6487   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6488   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489
6490   aopOp (result, ic, FALSE, FALSE);
6491
6492 release_freedLR:
6493
6494   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6495     {
6496       outBitC (result);
6497     }
6498   else
6499     {
6500       /* if the result is used in the next
6501          ifx conditional branch then generate
6502          code a little differently */
6503       if (ifx)
6504         {
6505           genIfxJump (ifx, "c");
6506         }
6507       else
6508         {
6509           outBitC (result);
6510         }
6511       /* leave the result in acc */
6512     }
6513   freeAsmop (result, NULL, ic, TRUE);
6514 }
6515
6516 /*-----------------------------------------------------------------*/
6517 /* genCmpGt :- greater than comparison                             */
6518 /*-----------------------------------------------------------------*/
6519 static void
6520 genCmpGt (iCode * ic, iCode * ifx)
6521 {
6522   operand *left, *right;
6523   sym_link *letype, *retype;
6524   int sign;
6525
6526   D (emitcode (";", "genCmpGt"));
6527
6528   left = IC_LEFT (ic);
6529   right = IC_RIGHT (ic);
6530
6531   letype = getSpec (operandType (left));
6532   retype = getSpec (operandType (right));
6533   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6534
6535   /* assign the left & right amsops */
6536   AOP_OP_2 (ic);
6537
6538   genCmp (right, left, ic, ifx, sign);
6539 }
6540
6541 /*-----------------------------------------------------------------*/
6542 /* genCmpLt - less than comparisons                                */
6543 /*-----------------------------------------------------------------*/
6544 static void
6545 genCmpLt (iCode * ic, iCode * ifx)
6546 {
6547   operand *left, *right;
6548   sym_link *letype, *retype;
6549   int sign;
6550
6551   D (emitcode (";", "genCmpLt"));
6552
6553   left = IC_LEFT (ic);
6554   right = IC_RIGHT (ic);
6555
6556   letype = getSpec (operandType (left));
6557   retype = getSpec (operandType (right));
6558   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6559
6560   /* assign the left & right amsops */
6561   AOP_OP_2 (ic);
6562
6563   genCmp (left, right, ic, ifx, sign);
6564 }
6565
6566 /*-----------------------------------------------------------------*/
6567 /* gencjneshort - compare and jump if not equal                    */
6568 /*-----------------------------------------------------------------*/
6569 static void
6570 gencjneshort (operand * left, operand * right, symbol * lbl)
6571 {
6572   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6573   int offset = 0;
6574   unsigned long lit = 0L;
6575
6576   D (emitcode (";", "gencjneshort"));
6577
6578   /* if the left side is a literal or
6579      if the right is in a pointer register and left
6580      is not */
6581   if ((AOP_TYPE (left) == AOP_LIT) ||
6582       (AOP_TYPE (left) == AOP_IMMD) ||
6583       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6584     {
6585       operand *t = right;
6586       right = left;
6587       left = t;
6588     }
6589
6590   if (AOP_TYPE (right) == AOP_LIT)
6591     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6592
6593   if (opIsGptr (left) || opIsGptr (right))
6594     {
6595       /* We are comparing a generic pointer to something.
6596        * Exclude the generic type byte from the comparison.
6597        */
6598       size--;
6599       D (emitcode (";", "cjneshort: generic ptr special case."););
6600     }
6601
6602
6603   /* if the right side is a literal then anything goes */
6604   if (AOP_TYPE (right) == AOP_LIT &&
6605       AOP_TYPE (left) != AOP_DIR)
6606     {
6607       while (size--)
6608         {
6609           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6610           emitcode ("cjne", "a,%s,!tlabel",
6611                     aopGet (right, offset, FALSE, FALSE, NULL),
6612                     lbl->key + 100);
6613           offset++;
6614         }
6615     }
6616
6617   /* if the right side is in a register or in direct space or
6618      if the left is a pointer register & right is not */
6619   else if (AOP_TYPE (right) == AOP_REG ||
6620            AOP_TYPE (right) == AOP_DIR ||
6621            AOP_TYPE (right) == AOP_LIT ||
6622            AOP_TYPE (right) == AOP_IMMD ||
6623            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6624            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6625     {
6626       while (size--)
6627         {
6628           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6629           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6630               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6631             emitcode ("jnz", "!tlabel", lbl->key + 100);
6632           else
6633             emitcode ("cjne", "a,%s,!tlabel",
6634                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6635                       lbl->key + 100);
6636           offset++;
6637         }
6638     }
6639   else
6640     {
6641       /* right is a pointer reg need both a & b */
6642       while (size--)
6643         {
6644           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6645           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6646           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6647           offset++;
6648         }
6649     }
6650 }
6651
6652 /*-----------------------------------------------------------------*/
6653 /* gencjne - compare and jump if not equal                         */
6654 /*-----------------------------------------------------------------*/
6655 static void
6656 gencjne (operand * left, operand * right, symbol * lbl)
6657 {
6658   symbol *tlbl = newiTempLabel (NULL);
6659
6660   D (emitcode (";", "gencjne"));
6661
6662   gencjneshort (left, right, lbl);
6663
6664   emitcode ("mov", "a,%s", one);
6665   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6666   emitLabel (lbl);
6667   emitcode ("clr", "a");
6668   emitLabel (tlbl);
6669 }
6670
6671 /*-----------------------------------------------------------------*/
6672 /* genCmpEq - generates code for equal to                          */
6673 /*-----------------------------------------------------------------*/
6674 static void
6675 genCmpEq (iCode * ic, iCode * ifx)
6676 {
6677   operand *left, *right, *result;
6678
6679   D (emitcode (";", "genCmpEq"));
6680
6681   AOP_OP_2 (ic);
6682   AOP_SET_LOCALS (ic);
6683
6684   /* if literal, literal on the right or
6685      if the right is in a pointer register and left
6686      is not */
6687   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6688       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6689     {
6690       operand *t = IC_RIGHT (ic);
6691       IC_RIGHT (ic) = IC_LEFT (ic);
6692       IC_LEFT (ic) = t;
6693     }
6694
6695   if (ifx &&                    /* !AOP_SIZE(result) */
6696       OP_SYMBOL (result) &&
6697       OP_SYMBOL (result)->regType == REG_CND)
6698     {
6699       symbol *tlbl;
6700       /* if they are both bit variables */
6701       if (AOP_TYPE (left) == AOP_CRY &&
6702           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6703         {
6704           if (AOP_TYPE (right) == AOP_LIT)
6705             {
6706               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6707               if (lit == 0L)
6708                 {
6709                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6710                   emitcode ("cpl", "c");
6711                 }
6712               else if (lit == 1L)
6713                 {
6714                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6715                 }
6716               else
6717                 {
6718                   emitcode ("clr", "c");
6719                 }
6720               /* AOP_TYPE(right) == AOP_CRY */
6721             }
6722           else
6723             {
6724               symbol *lbl = newiTempLabel (NULL);
6725               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6726               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6727               emitcode ("cpl", "c");
6728               emitLabel (lbl);
6729             }
6730           /* if true label then we jump if condition
6731              supplied is true */
6732           tlbl = newiTempLabel (NULL);
6733           if (IC_TRUE (ifx))
6734             {
6735               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6736               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6737             }
6738           else
6739             {
6740               emitcode ("jc", "!tlabel", tlbl->key + 100);
6741               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6742             }
6743           emitLabel (tlbl);
6744         }
6745       else
6746         {
6747           tlbl = newiTempLabel (NULL);
6748           gencjneshort (left, right, tlbl);
6749           if (IC_TRUE (ifx))
6750             {
6751               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6752               emitLabel (tlbl);
6753             }
6754           else
6755             {
6756               symbol *lbl = newiTempLabel (NULL);
6757               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6758               emitLabel (tlbl);
6759               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6760               emitLabel (lbl);
6761             }
6762         }
6763       /* mark the icode as generated */
6764       ifx->generated = 1;
6765
6766       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6767       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6768       return;
6769     }
6770
6771   /* if they are both bit variables */
6772   if (AOP_TYPE (left) == AOP_CRY &&
6773       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6774     {
6775       if (AOP_TYPE (right) == AOP_LIT)
6776         {
6777           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6778           if (lit == 0L)
6779             {
6780               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6781               emitcode ("cpl", "c");
6782             }
6783           else if (lit == 1L)
6784             {
6785               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6786             }
6787           else
6788             {
6789               emitcode ("clr", "c");
6790             }
6791           /* AOP_TYPE(right) == AOP_CRY */
6792         }
6793       else
6794         {
6795           symbol *lbl = newiTempLabel (NULL);
6796           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6797           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6798           emitcode ("cpl", "c");
6799           emitLabel (lbl);
6800         }
6801
6802       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6803       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6804
6805       aopOp (result, ic, TRUE, FALSE);
6806
6807       /* c = 1 if egal */
6808       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6809         {
6810           outBitC (result);
6811           goto release;
6812         }
6813       if (ifx)
6814         {
6815           genIfxJump (ifx, "c");
6816           goto release;
6817         }
6818       /* if the result is used in an arithmetic operation
6819          then put the result in place */
6820       outBitC (result);
6821     }
6822   else
6823     {
6824       gencjne (left, right, newiTempLabel (NULL));
6825
6826       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6827       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828
6829       aopOp (result, ic, TRUE, FALSE);
6830
6831       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6832         {
6833           aopPut (result, "a", 0);
6834           goto release;
6835         }
6836       if (ifx)
6837         {
6838           genIfxJump (ifx, "a");
6839           goto release;
6840         }
6841       /* if the result is used in an arithmetic operation
6842          then put the result in place */
6843       if (AOP_TYPE (result) != AOP_CRY)
6844         outAcc (result);
6845       /* leave the result in acc */
6846     }
6847
6848 release:
6849   freeAsmop (result, NULL, ic, TRUE);
6850 }
6851
6852 /*-----------------------------------------------------------------*/
6853 /* ifxForOp - returns the icode containing the ifx for operand     */
6854 /*-----------------------------------------------------------------*/
6855 static iCode *
6856 ifxForOp (operand * op, iCode * ic)
6857 {
6858   /* if true symbol then needs to be assigned */
6859   if (IS_TRUE_SYMOP (op))
6860     return NULL;
6861
6862   /* if this has register type condition and
6863      the next instruction is ifx with the same operand
6864      and live to of the operand is upto the ifx only then */
6865   if (ic->next &&
6866       ic->next->op == IFX &&
6867       IC_COND (ic->next)->key == op->key &&
6868       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6869     return ic->next;
6870
6871   return NULL;
6872 }
6873
6874 /*-----------------------------------------------------------------*/
6875 /* hasInc - operand is incremented before any other use            */
6876 /*-----------------------------------------------------------------*/
6877 static iCode *
6878 hasInc (operand *op, iCode *ic, int osize)
6879 {
6880   sym_link *type = operandType(op);
6881   sym_link *retype = getSpec (type);
6882   iCode *lic = ic->next;
6883   int isize ;
6884
6885   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6886   if (!IS_SYMOP(op)) return NULL;
6887
6888   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6889   if (IS_AGGREGATE(type->next)) return NULL;
6890   if (osize != (isize = getSize(type->next))) return NULL;
6891
6892   while (lic) {
6893       /* if operand of the form op = op + <sizeof *op> */
6894       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6895           isOperandEqual(IC_RESULT(lic),op) &&
6896           isOperandLiteral(IC_RIGHT(lic)) &&
6897           operandLitValue(IC_RIGHT(lic)) == isize) {
6898           return lic;
6899       }
6900       /* if the operand used or deffed */
6901       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6902           return NULL;
6903       }
6904       /* if GOTO or IFX */
6905       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6906       lic = lic->next;
6907   }
6908   return NULL;
6909 }
6910
6911 /*-----------------------------------------------------------------*/
6912 /* genAndOp - for && operation                                     */
6913 /*-----------------------------------------------------------------*/
6914 static void
6915 genAndOp (iCode * ic)
6916 {
6917   operand *left, *right, *result;
6918   symbol *tlbl;
6919
6920   D (emitcode (";", "genAndOp"));
6921
6922   /* note here that && operations that are in an
6923      if statement are taken away by backPatchLabels
6924      only those used in arthmetic operations remain */
6925   AOP_OP_2 (ic);
6926   AOP_SET_LOCALS (ic);
6927
6928   /* if both are bit variables */
6929   if (AOP_TYPE (left) == AOP_CRY &&
6930       AOP_TYPE (right) == AOP_CRY)
6931     {
6932       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6933       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6934       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6935       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6936
6937       aopOp (result,ic,FALSE, FALSE);
6938       outBitC (result);
6939     }
6940   else
6941     {
6942       tlbl = newiTempLabel (NULL);
6943       toBoolean (left);
6944       emitcode ("jz", "!tlabel", tlbl->key + 100);
6945       toBoolean (right);
6946       emitLabel (tlbl);
6947       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6948       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6949
6950       aopOp (result,ic,FALSE, FALSE);
6951       outBitAcc (result);
6952     }
6953
6954     freeAsmop (result, NULL, ic, TRUE);
6955 }
6956
6957
6958 /*-----------------------------------------------------------------*/
6959 /* genOrOp - for || operation                                      */
6960 /*-----------------------------------------------------------------*/
6961 static void
6962 genOrOp (iCode * ic)
6963 {
6964   operand *left, *right, *result;
6965   symbol *tlbl;
6966
6967   D (emitcode (";", "genOrOp"));
6968
6969   /* note here that || operations that are in an
6970      if statement are taken away by backPatchLabels
6971      only those used in arthmetic operations remain */
6972   AOP_OP_2 (ic);
6973   AOP_SET_LOCALS (ic);
6974
6975   /* if both are bit variables */
6976   if (AOP_TYPE (left) == AOP_CRY &&
6977       AOP_TYPE (right) == AOP_CRY)
6978     {
6979       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6980       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6981       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6982       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6983
6984       aopOp (result,ic,FALSE, FALSE);
6985
6986       outBitC (result);
6987     }
6988   else
6989     {
6990       tlbl = newiTempLabel (NULL);
6991       toBoolean (left);
6992       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6993       toBoolean (right);
6994       emitLabel (tlbl);
6995       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6996       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6997
6998       aopOp (result,ic,FALSE, FALSE);
6999
7000       outBitAcc (result);
7001     }
7002
7003   freeAsmop (result, NULL, ic, TRUE);
7004 }
7005
7006 /*-----------------------------------------------------------------*/
7007 /* isLiteralBit - test if lit == 2^n                               */
7008 /*-----------------------------------------------------------------*/
7009 static int
7010 isLiteralBit (unsigned long lit)
7011 {
7012   unsigned long pw[32] =
7013   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7014    0x100L, 0x200L, 0x400L, 0x800L,
7015    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7016    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7017    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7018    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7019    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7020   int idx;
7021
7022   for (idx = 0; idx < 32; idx++)
7023     if (lit == pw[idx])
7024       return idx + 1;
7025   return 0;
7026 }
7027
7028 /*-----------------------------------------------------------------*/
7029 /* continueIfTrue -                                                */
7030 /*-----------------------------------------------------------------*/
7031 static void
7032 continueIfTrue (iCode * ic)
7033 {
7034   if (IC_TRUE (ic))
7035     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7036   ic->generated = 1;
7037 }
7038
7039 /*-----------------------------------------------------------------*/
7040 /* jmpIfTrue -                                                     */
7041 /*-----------------------------------------------------------------*/
7042 static void
7043 jumpIfTrue (iCode * ic)
7044 {
7045   if (!IC_TRUE (ic))
7046     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7047   ic->generated = 1;
7048 }
7049
7050 /*-----------------------------------------------------------------*/
7051 /* jmpTrueOrFalse -                                                */
7052 /*-----------------------------------------------------------------*/
7053 static void
7054 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7055 {
7056   // ugly but optimized by peephole
7057   if (IC_TRUE (ic))
7058     {
7059       symbol *nlbl = newiTempLabel (NULL);
7060       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7061       emitLabel (tlbl);
7062       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7063       emitLabel (nlbl);
7064     }
7065   else
7066     {
7067       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7068       emitLabel (tlbl);
7069     }
7070   ic->generated = 1;
7071 }
7072
7073 // Generate code to perform a bit-wise logic operation
7074 // on two operands in far space (assumed to already have been
7075 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7076 // in far space. This requires pushing the result on the stack
7077 // then popping it into the result.
7078 static void
7079 genFarFarLogicOp(iCode *ic, char *logicOp)
7080 {
7081       int size, resultSize, compSize;
7082       int offset = 0;
7083
7084       TR_AP("#5");
7085       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7086       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7087                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7088
7089       _startLazyDPSEvaluation();
7090       for (size = compSize; (size--); offset++)
7091       {
7092           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7093           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7094           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7095
7096           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7097           emitcode ("push", "acc");
7098       }
7099       _endLazyDPSEvaluation();
7100
7101       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7102       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7103       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7104
7105       resultSize = AOP_SIZE(IC_RESULT(ic));
7106
7107       ADJUST_PUSHED_RESULT(compSize, resultSize);
7108
7109       _startLazyDPSEvaluation();
7110       while (compSize--)
7111       {
7112           emitcode ("pop", "acc");
7113           aopPut (IC_RESULT (ic), "a", compSize);
7114       }
7115       _endLazyDPSEvaluation();
7116       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7117 }
7118
7119
7120 /*-----------------------------------------------------------------*/
7121 /* genAnd  - code for and                                          */
7122 /*-----------------------------------------------------------------*/
7123 static void
7124 genAnd (iCode * ic, iCode * ifx)
7125 {
7126   operand *left, *right, *result;
7127   int size, offset = 0;
7128   unsigned long lit = 0L;
7129   int bytelit = 0;
7130   char buffer[10];
7131   bool pushResult;
7132
7133   D (emitcode (";", "genAnd"));
7134
7135   AOP_OP_3_NOFATAL (ic, pushResult);
7136   AOP_SET_LOCALS (ic);
7137
7138   if (pushResult)
7139   {
7140       genFarFarLogicOp(ic, "anl");
7141       return;
7142   }
7143
7144 #ifdef DEBUG_TYPE
7145   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7146             AOP_TYPE (result),
7147             AOP_TYPE (left), AOP_TYPE (right));
7148   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7149             AOP_SIZE (result),
7150             AOP_SIZE (left), AOP_SIZE (right));
7151 #endif
7152
7153   /* if left is a literal & right is not then exchange them */
7154   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7155 #ifdef LOGIC_OPS_BROKEN
7156     ||  AOP_NEEDSACC (left)
7157 #endif
7158     )
7159     {
7160       operand *tmp = right;
7161       right = left;
7162       left = tmp;
7163     }
7164
7165   /* if result = right then exchange left and right */
7166   if (sameRegs (AOP (result), AOP (right)))
7167     {
7168       operand *tmp = right;
7169       right = left;
7170       left = tmp;
7171     }
7172
7173   /* if right is bit then exchange them */
7174   if (AOP_TYPE (right) == AOP_CRY &&
7175       AOP_TYPE (left) != AOP_CRY)
7176     {
7177       operand *tmp = right;
7178       right = left;
7179       left = tmp;
7180     }
7181   if (AOP_TYPE (right) == AOP_LIT)
7182     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7183
7184   size = AOP_SIZE (result);
7185
7186   // if(bit & yy)
7187   // result = bit & yy;
7188   if (AOP_TYPE (left) == AOP_CRY)
7189     {
7190       // c = bit & literal;
7191       if (AOP_TYPE (right) == AOP_LIT)
7192         {
7193           if (lit & 1)
7194             {
7195               if (size && sameRegs (AOP (result), AOP (left)))
7196                 // no change
7197                 goto release;
7198               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7199             }
7200           else
7201             {
7202               // bit(result) = 0;
7203               if (size && (AOP_TYPE (result) == AOP_CRY))
7204                 {
7205                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7206                   goto release;
7207                 }
7208               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7209                 {
7210                   jumpIfTrue (ifx);
7211                   goto release;
7212                 }
7213               emitcode ("clr", "c");
7214             }
7215         }
7216       else
7217         {
7218           if (AOP_TYPE (right) == AOP_CRY)
7219             {
7220               // c = bit & bit;
7221               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7222               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7223             }
7224           else
7225             {
7226               // c = bit & val;
7227               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7228               // c = lsb
7229               emitcode ("rrc", "a");
7230               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7231             }
7232         }
7233       // bit = c
7234       // val = c
7235       if (size)
7236         outBitC (result);
7237       // if(bit & ...)
7238       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7239         genIfxJump (ifx, "c");
7240       goto release;
7241     }
7242
7243   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7244   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7245   if ((AOP_TYPE (right) == AOP_LIT) &&
7246       (AOP_TYPE (result) == AOP_CRY) &&
7247       (AOP_TYPE (left) != AOP_CRY))
7248     {
7249       int posbit = isLiteralBit (lit);
7250       /* left &  2^n */
7251       if (posbit)
7252         {
7253           posbit--;
7254           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7255           // bit = left & 2^n
7256           if (size)
7257             {
7258               switch (posbit & 0x07)
7259                 {
7260                   case 0: emitcode ("rrc", "a");
7261                           break;
7262                   case 7: emitcode ("rlc", "a");
7263                           break;
7264                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7265                           break;
7266                 }
7267             }
7268           // if(left &  2^n)
7269           else
7270             {
7271               if (ifx)
7272                 {
7273                   SNPRINTF (buffer, sizeof(buffer),
7274                             "acc.%d", posbit & 0x07);
7275                   genIfxJump (ifx, buffer);
7276                 }
7277               else
7278                 {
7279                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7280                 }
7281               goto release;
7282             }
7283         }
7284       else
7285         {
7286           symbol *tlbl = newiTempLabel (NULL);
7287           int sizel = AOP_SIZE (left);
7288           if (size)
7289             emitcode ("setb", "c");
7290           while (sizel--)
7291             {
7292               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7293                 {
7294                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7295                   // byte ==  2^n ?
7296                   if ((posbit = isLiteralBit (bytelit)) != 0)
7297                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7298                   else
7299                     {
7300                       if (bytelit != 0x0FFL)
7301                         emitcode ("anl", "a,%s",
7302                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7303                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7304                     }
7305                 }
7306               offset++;
7307             }
7308           // bit = left & literal
7309           if (size)
7310             {
7311               emitcode ("clr", "c");
7312               emitLabel (tlbl);
7313             }
7314           // if(left & literal)
7315           else
7316             {
7317               if (ifx)
7318                 jmpTrueOrFalse (ifx, tlbl);
7319               else
7320                 emitLabel (tlbl);
7321               goto release;
7322             }
7323         }
7324       outBitC (result);
7325       goto release;
7326     }
7327
7328   /* if left is same as result */
7329   if (sameRegs (AOP (result), AOP (left)))
7330     {
7331       for (; size--; offset++)
7332         {
7333           if (AOP_TYPE (right) == AOP_LIT)
7334             {
7335               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7336               if (bytelit == 0x0FF)
7337                 {
7338                   /* dummy read of volatile operand */
7339                   if (isOperandVolatile (left, FALSE))
7340                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7341                   else
7342                     continue;
7343                 }
7344               else if (bytelit == 0)
7345                 {
7346                   aopPut (result, zero, offset);
7347                 }
7348               else if (IS_AOP_PREG (result))
7349                 {
7350                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7351                   emitcode ("anl", "a,%s",
7352                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7353                   aopPut (result, "a", offset);
7354                 }
7355               else
7356                 emitcode ("anl", "%s,%s",
7357                           aopGet (left, offset, FALSE, TRUE, NULL),
7358                           aopGet (right, offset, FALSE, FALSE, NULL));
7359             }
7360           else
7361             {
7362               if (AOP_TYPE (left) == AOP_ACC)
7363                 {
7364                   if (offset)
7365                     emitcode("mov", "a,b");
7366                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7367                 }
7368               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7369                 {
7370                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7371                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7372                   emitcode ("anl", "a,b");
7373                   aopPut (result, "a", offset);
7374                 }
7375               else if (aopGetUsesAcc (left, offset))
7376                 {
7377                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7378                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7379                   aopPut (result, "a", offset);
7380                 }
7381               else
7382                 {
7383                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7384                   if (IS_AOP_PREG (result))
7385                     {
7386                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7387                       aopPut (result, "a", offset);
7388                     }
7389                   else
7390                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7391                 }
7392             }
7393         }
7394     }
7395   else
7396     {
7397       // left & result in different registers
7398       if (AOP_TYPE (result) == AOP_CRY)
7399         {
7400           // result = bit
7401           // if(size), result in bit
7402           // if(!size && ifx), conditional oper: if(left & right)
7403           symbol *tlbl = newiTempLabel (NULL);
7404           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7405           if (size)
7406             emitcode ("setb", "c");
7407           while (sizer--)
7408             {
7409               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7410                   && AOP_TYPE(left)==AOP_ACC)
7411                 {
7412                   if (offset)
7413                     emitcode("mov", "a,b");
7414                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7415                 }
7416               else if (AOP_TYPE(left)==AOP_ACC)
7417                 {
7418                   if (!offset)
7419                     {
7420                       bool pushedB = pushB ();
7421                       emitcode("mov", "b,a");
7422                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7423                       emitcode("anl", "a,b");
7424                       popB (pushedB);
7425                     }
7426                   else
7427                     {
7428                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7429                       emitcode("anl", "a,b");
7430                     }
7431                 }
7432               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7433                 {
7434                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7435                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7436                   emitcode ("anl", "a,b");
7437                 }
7438               else if (aopGetUsesAcc (left, offset))
7439                 {
7440                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7441                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7442                 }
7443               else
7444                 {
7445                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7446                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7447                 }
7448
7449               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7450               offset++;
7451             }
7452           if (size)
7453             {
7454               CLRC;
7455               emitLabel (tlbl);
7456               outBitC (result);
7457             }
7458           else if (ifx)
7459             jmpTrueOrFalse (ifx, tlbl);
7460           else
7461             emitLabel (tlbl);
7462         }
7463       else
7464         {
7465           for (; (size--); offset++)
7466             {
7467               // normal case
7468               // result = left & right
7469               if (AOP_TYPE (right) == AOP_LIT)
7470                 {
7471                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7472                   if (bytelit == 0x0FF)
7473                     {
7474                       aopPut (result,
7475                               aopGet (left, offset, FALSE, FALSE, NULL),
7476                               offset);
7477                       continue;
7478                     }
7479                   else if (bytelit == 0)
7480                     {
7481                       /* dummy read of volatile operand */
7482                       if (isOperandVolatile (left, FALSE))
7483                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7484                       aopPut (result, zero, offset);
7485                       continue;
7486                     }
7487                   else if (AOP_TYPE (left) == AOP_ACC)
7488                     {
7489                       if (!offset)
7490                         {
7491                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7492                           aopPut (result, "a", offset);
7493                           continue;
7494                         }
7495                       else
7496                         {
7497                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7498                           aopPut (result, "b", offset);
7499                           continue;
7500                         }
7501                     }
7502                 }
7503               // faster than result <- left, anl result,right
7504               // and better if result is SFR
7505               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7506                   && AOP_TYPE(left)==AOP_ACC)
7507                 {
7508                   if (offset)
7509                     emitcode("mov", "a,b");
7510                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7511                 }
7512               else if (AOP_TYPE(left)==AOP_ACC)
7513                 {
7514                   if (!offset)
7515                     {
7516                       bool pushedB = pushB ();
7517                       emitcode("mov", "b,a");
7518                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7519                       emitcode("anl", "a,b");
7520                       popB (pushedB);
7521                     }
7522                   else
7523                     {
7524                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7525                       emitcode("anl", "a,b");
7526                     }
7527                 }
7528               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7529                 {
7530                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7531                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7532                   emitcode ("anl", "a,b");
7533                 }
7534               else if (aopGetUsesAcc (left, offset))
7535                 {
7536                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7537                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7538                 }
7539               else
7540                 {
7541                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7542                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7543                 }
7544               aopPut (result, "a", offset);
7545             }
7546         }
7547     }
7548
7549 release:
7550   freeAsmop (result, NULL, ic, TRUE);
7551   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7552   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7553 }
7554
7555 /*-----------------------------------------------------------------*/
7556 /* genOr  - code for or                                            */
7557 /*-----------------------------------------------------------------*/
7558 static void
7559 genOr (iCode * ic, iCode * ifx)
7560 {
7561   operand *left, *right, *result;
7562   int size, offset = 0;
7563   unsigned long lit = 0L;
7564   int bytelit = 0;
7565   bool     pushResult;
7566
7567   D (emitcode (";", "genOr"));
7568
7569   AOP_OP_3_NOFATAL (ic, pushResult);
7570   AOP_SET_LOCALS (ic);
7571
7572   if (pushResult)
7573   {
7574       genFarFarLogicOp(ic, "orl");
7575       return;
7576   }
7577
7578
7579 #ifdef DEBUG_TYPE
7580   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7581             AOP_TYPE (result),
7582             AOP_TYPE (left), AOP_TYPE (right));
7583   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7584             AOP_SIZE (result),
7585             AOP_SIZE (left), AOP_SIZE (right));
7586 #endif
7587
7588   /* if left is a literal & right is not then exchange them */
7589   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7590 #ifdef LOGIC_OPS_BROKEN
7591    || AOP_NEEDSACC (left) // I think this is a net loss now.
7592 #endif
7593       )
7594     {
7595       operand *tmp = right;
7596       right = left;
7597       left = tmp;
7598     }
7599
7600   /* if result = right then exchange them */
7601   if (sameRegs (AOP (result), AOP (right)))
7602     {
7603       operand *tmp = right;
7604       right = left;
7605       left = tmp;
7606     }
7607
7608   /* if right is bit then exchange them */
7609   if (AOP_TYPE (right) == AOP_CRY &&
7610       AOP_TYPE (left) != AOP_CRY)
7611     {
7612       operand *tmp = right;
7613       right = left;
7614       left = tmp;
7615     }
7616   if (AOP_TYPE (right) == AOP_LIT)
7617     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7618
7619   size = AOP_SIZE (result);
7620
7621   // if(bit | yy)
7622   // xx = bit | yy;
7623   if (AOP_TYPE (left) == AOP_CRY)
7624     {
7625       if (AOP_TYPE (right) == AOP_LIT)
7626         {
7627           // c = bit | literal;
7628           if (lit)
7629             {
7630               // lit != 0 => result = 1
7631               if (AOP_TYPE (result) == AOP_CRY)
7632                 {
7633                   if (size)
7634                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7635                   else if (ifx)
7636                     continueIfTrue (ifx);
7637                   goto release;
7638                 }
7639               emitcode ("setb", "c");
7640             }
7641           else
7642             {
7643               // lit == 0 => result = left
7644               if (size && sameRegs (AOP (result), AOP (left)))
7645                 goto release;
7646               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7647             }
7648         }
7649       else
7650         {
7651           if (AOP_TYPE (right) == AOP_CRY)
7652             {
7653               // c = bit | bit;
7654               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7655               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7656             }
7657           else
7658             {
7659               // c = bit | val;
7660               symbol *tlbl = newiTempLabel (NULL);
7661               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7662                 emitcode ("setb", "c");
7663               emitcode ("jb", "%s,!tlabel",
7664                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7665               toBoolean (right);
7666               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7667               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7668                 {
7669                   jmpTrueOrFalse (ifx, tlbl);
7670                   goto release;
7671                 }
7672               else
7673                 {
7674                   CLRC;
7675                   emitLabel (tlbl);
7676                 }
7677             }
7678         }
7679       // bit = c
7680       // val = c
7681       if (size)
7682         outBitC (result);
7683       // if(bit | ...)
7684       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7685            genIfxJump (ifx, "c");
7686       goto release;
7687     }
7688
7689   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7690   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7691   if ((AOP_TYPE (right) == AOP_LIT) &&
7692       (AOP_TYPE (result) == AOP_CRY) &&
7693       (AOP_TYPE (left) != AOP_CRY))
7694     {
7695       if (lit)
7696         {
7697           // result = 1
7698           if (size)
7699             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7700           else
7701             continueIfTrue (ifx);
7702           goto release;
7703         }
7704       else
7705         {
7706           // lit = 0, result = boolean(left)
7707           if (size)
7708             emitcode ("setb", "c");
7709           toBoolean (right);
7710           if (size)
7711             {
7712               symbol *tlbl = newiTempLabel (NULL);
7713               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7714               CLRC;
7715               emitLabel (tlbl);
7716             }
7717           else
7718             {
7719               genIfxJump (ifx, "a");
7720               goto release;
7721             }
7722         }
7723       outBitC (result);
7724       goto release;
7725     }
7726
7727   /* if left is same as result */
7728   if (sameRegs (AOP (result), AOP (left)))
7729     {
7730       for (; size--; offset++)
7731         {
7732           if (AOP_TYPE (right) == AOP_LIT)
7733             {
7734               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7735               if (bytelit == 0)
7736                 {
7737                   /* dummy read of volatile operand */
7738                   if (isOperandVolatile (left, FALSE))
7739                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7740                   else
7741                     continue;
7742                 }
7743               else if (bytelit == 0x0FF)
7744                 {
7745                   aopPut (result, "#0xFF", offset);
7746                 }
7747               else if (IS_AOP_PREG (left))
7748                 {
7749                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7750                   emitcode ("orl", "a,%s",
7751                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7752                   aopPut (result, "a", offset);
7753                 }
7754               else
7755                 {
7756                   emitcode ("orl", "%s,%s",
7757                             aopGet (left, offset, FALSE, TRUE, NULL),
7758                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7759                 }
7760             }
7761           else
7762             {
7763               if (AOP_TYPE (left) == AOP_ACC)
7764                 {
7765                   if (offset)
7766                     emitcode("mov", "a,b");
7767                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7768                 }
7769               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7770                 {
7771                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7772                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7773                   emitcode ("orl", "a,b");
7774                   aopPut (result, "a", offset);
7775                 }
7776               else if (aopGetUsesAcc (left, offset))
7777                 {
7778                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7779                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7780                   aopPut (result, "a", offset);
7781                 }
7782               else
7783                 {
7784                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7785                   if (IS_AOP_PREG (left))
7786                     {
7787                       emitcode ("orl", "a,%s",
7788                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7789                       aopPut (result, "a", offset);
7790                     }
7791                   else
7792                     {
7793                       emitcode ("orl", "%s,a",
7794                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7795                     }
7796                 }
7797             }
7798         }
7799     }
7800   else
7801     {
7802       // left & result in different registers
7803       if (AOP_TYPE (result) == AOP_CRY)
7804         {
7805           // result = bit
7806           // if(size), result in bit
7807           // if(!size && ifx), conditional oper: if(left | right)
7808           symbol *tlbl = newiTempLabel (NULL);
7809           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7810           if (size)
7811             emitcode ("setb", "c");
7812           while (sizer--)
7813             {
7814               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7815                   && AOP_TYPE(left)==AOP_ACC)
7816                 {
7817                   if (offset)
7818                     emitcode("mov", "a,b");
7819                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7820                 }
7821               else if (AOP_TYPE(left)==AOP_ACC)
7822                 {
7823                   if (!offset)
7824                     {
7825                       bool pushedB = pushB ();
7826                       emitcode("mov", "b,a");
7827                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7828                       emitcode("orl", "a,b");
7829                       popB (pushedB);
7830                     }
7831                   else
7832                     {
7833                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7834                       emitcode("orl", "a,b");
7835                     }
7836                 }
7837               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7838                 {
7839                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7840                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7841                   emitcode ("orl", "a,b");
7842                 }
7843               else if (aopGetUsesAcc (left, offset))
7844                 {
7845                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7846                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7847                 }
7848               else
7849                 {
7850                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7851                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7852               }
7853
7854               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7855               offset++;
7856             }
7857           if (size)
7858             {
7859               CLRC;
7860               emitLabel (tlbl);
7861               outBitC (result);
7862             }
7863           else if (ifx)
7864             jmpTrueOrFalse (ifx, tlbl);
7865           else
7866             emitLabel (tlbl);
7867         }
7868       else
7869         {
7870             _startLazyDPSEvaluation();
7871           for (; (size--); offset++)
7872             {
7873               // normal case
7874               // result = left | right
7875               if (AOP_TYPE (right) == AOP_LIT)
7876                 {
7877                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7878                   if (bytelit == 0)
7879                     {
7880                       aopPut (result,
7881                               aopGet (left, offset, FALSE, FALSE, NULL),
7882                               offset);
7883                       continue;
7884                     }
7885                   else if (bytelit == 0x0FF)
7886                     {
7887                       /* dummy read of volatile operand */
7888                       if (isOperandVolatile (left, FALSE))
7889                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7890                       aopPut (result, "#0xFF", offset);
7891                       continue;
7892                     }
7893                 }
7894               // faster than result <- left, orl result,right
7895               // and better if result is SFR
7896               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7897                   && AOP_TYPE(left)==AOP_ACC)
7898                 {
7899                   if (offset)
7900                     emitcode("mov", "a,b");
7901                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7902                 }
7903               else if (AOP_TYPE(left)==AOP_ACC)
7904                 {
7905                   if (!offset)
7906                     {
7907                       bool pushedB = pushB ();
7908                       emitcode("mov", "b,a");
7909                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7910                       emitcode("orl", "a,b");
7911                       popB (pushedB);
7912                     }
7913                   else
7914                     {
7915                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7916                       emitcode("orl", "a,b");
7917                     }
7918                 }
7919               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7920                 {
7921                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7922                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7923                   emitcode ("orl", "a,b");
7924                 }
7925               else if (aopGetUsesAcc (left, offset))
7926                 {
7927                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7928                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7929                 }
7930               else
7931                 {
7932                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7933                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7934                 }
7935               aopPut (result, "a", offset);
7936             }
7937             _endLazyDPSEvaluation();
7938         }
7939     }
7940
7941 release:
7942   freeAsmop (result, NULL, ic, TRUE);
7943   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7944   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7945 }
7946
7947 /*-----------------------------------------------------------------*/
7948 /* genXor - code for xclusive or                                   */
7949 /*-----------------------------------------------------------------*/
7950 static void
7951 genXor (iCode * ic, iCode * ifx)
7952 {
7953   operand *left, *right, *result;
7954   int size, offset = 0;
7955   unsigned long lit = 0L;
7956   int bytelit = 0;
7957   bool pushResult;
7958
7959   D (emitcode (";", "genXor"));
7960
7961   AOP_OP_3_NOFATAL (ic, pushResult);
7962   AOP_SET_LOCALS (ic);
7963
7964   if (pushResult)
7965   {
7966       genFarFarLogicOp(ic, "xrl");
7967       return;
7968   }
7969
7970 #ifdef DEBUG_TYPE
7971   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7972             AOP_TYPE (result),
7973             AOP_TYPE (left), AOP_TYPE (right));
7974   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7975             AOP_SIZE (result),
7976             AOP_SIZE (left), AOP_SIZE (right));
7977 #endif
7978
7979   /* if left is a literal & right is not ||
7980      if left needs acc & right does not */
7981   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7982 #ifdef LOGIC_OPS_BROKEN
7983       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7984 #endif
7985      )
7986     {
7987       operand *tmp = right;
7988       right = left;
7989       left = tmp;
7990     }
7991
7992   /* if result = right then exchange them */
7993   if (sameRegs (AOP (result), AOP (right)))
7994     {
7995       operand *tmp = right;
7996       right = left;
7997       left = tmp;
7998     }
7999
8000   /* if right is bit then exchange them */
8001   if (AOP_TYPE (right) == AOP_CRY &&
8002       AOP_TYPE (left) != AOP_CRY)
8003     {
8004       operand *tmp = right;
8005       right = left;
8006       left = tmp;
8007     }
8008   if (AOP_TYPE (right) == AOP_LIT)
8009     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8010
8011   size = AOP_SIZE (result);
8012
8013   // if(bit ^ yy)
8014   // xx = bit ^ yy;
8015   if (AOP_TYPE (left) == AOP_CRY)
8016     {
8017       if (AOP_TYPE (right) == AOP_LIT)
8018         {
8019           // c = bit & literal;
8020           if (lit >> 1)
8021             {
8022               // lit>>1  != 0 => result = 1
8023               if (AOP_TYPE (result) == AOP_CRY)
8024                 {
8025                   if (size)
8026                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8027                   else if (ifx)
8028                     continueIfTrue (ifx);
8029                   goto release;
8030                 }
8031               emitcode ("setb", "c");
8032             }
8033           else
8034             {
8035               // lit == (0 or 1)
8036               if (lit == 0)
8037                 {
8038                   // lit == 0, result = left
8039                   if (size && sameRegs (AOP (result), AOP (left)))
8040                     goto release;
8041                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8042                 }
8043               else
8044                 {
8045                   // lit == 1, result = not(left)
8046                   if (size && sameRegs (AOP (result), AOP (left)))
8047                     {
8048                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8049                       goto release;
8050                     }
8051                   else
8052                     {
8053                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8054                       emitcode ("cpl", "c");
8055                     }
8056                 }
8057             }
8058         }
8059       else
8060         {
8061           // right != literal
8062           symbol *tlbl = newiTempLabel (NULL);
8063           if (AOP_TYPE (right) == AOP_CRY)
8064             {
8065               // c = bit ^ bit;
8066               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8067             }
8068           else
8069             {
8070               int sizer = AOP_SIZE (right);
8071               // c = bit ^ val
8072               // if val>>1 != 0, result = 1
8073               emitcode ("setb", "c");
8074               while (sizer)
8075                 {
8076                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8077                   if (sizer == 1)
8078                     // test the msb of the lsb
8079                     emitcode ("anl", "a,#!constbyte",0xfe);
8080                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8081                   sizer--;
8082                 }
8083               // val = (0,1)
8084               emitcode ("rrc", "a");
8085             }
8086           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8087           emitcode ("cpl", "c");
8088           emitLabel (tlbl);
8089         }
8090       // bit = c
8091       // val = c
8092       if (size)
8093         outBitC (result);
8094       // if(bit | ...)
8095       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8096         genIfxJump (ifx, "c");
8097       goto release;
8098     }
8099
8100   /* if left is same as result */
8101   if (sameRegs (AOP (result), AOP (left)))
8102     {
8103       for (; size--; offset++)
8104         {
8105           if (AOP_TYPE (right) == AOP_LIT)
8106             {
8107               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8108               if (bytelit == 0)
8109                 {
8110                   /* dummy read of volatile operand */
8111                   if (isOperandVolatile (left, FALSE))
8112                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8113                   else
8114                     continue;
8115                 }
8116               else if (IS_AOP_PREG (left))
8117                 {
8118                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8119                   emitcode ("xrl", "a,%s",
8120                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8121                   aopPut (result, "a", offset);
8122                 }
8123               else
8124                 {
8125                   emitcode ("xrl", "%s,%s",
8126                             aopGet (left, offset, FALSE, TRUE, NULL),
8127                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8128                 }
8129             }
8130           else
8131             {
8132               if (AOP_TYPE (left) == AOP_ACC)
8133                 {
8134                   if (offset)
8135                     emitcode("mov", "a,b");
8136                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8137                 }
8138               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8139                 {
8140                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8141                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8142                   emitcode ("xrl", "a,b");
8143                   aopPut (result, "a", offset);
8144                 }
8145               else if (aopGetUsesAcc (left, offset))
8146                 {
8147                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8148                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8149                   aopPut (result, "a", offset);
8150                 }
8151               else
8152                 {
8153                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8154                   if (IS_AOP_PREG (left))
8155                     {
8156                       emitcode ("xrl", "a,%s",
8157                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8158                       aopPut (result, "a", offset);
8159                     }
8160                   else
8161                     emitcode ("xrl", "%s,a",
8162                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8163                 }
8164             }
8165         }
8166     }
8167   else
8168     {
8169       // left & result in different registers
8170       if (AOP_TYPE (result) == AOP_CRY)
8171         {
8172           // result = bit
8173           // if(size), result in bit
8174           // if(!size && ifx), conditional oper: if(left ^ right)
8175           symbol *tlbl = newiTempLabel (NULL);
8176           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8177
8178           if (size)
8179             emitcode ("setb", "c");
8180           while (sizer--)
8181             {
8182               if ((AOP_TYPE (right) == AOP_LIT) &&
8183                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8184                 {
8185                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8186                 }
8187               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8188                   && AOP_TYPE(left)==AOP_ACC)
8189                 {
8190                   if (offset)
8191                     emitcode("mov", "a,b");
8192                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8193                 }
8194               else if (AOP_TYPE(left)==AOP_ACC)
8195                 {
8196                   if (!offset)
8197                     {
8198                       bool pushedB = pushB ();
8199                       emitcode("mov", "b,a");
8200                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8201                       emitcode("xrl", "a,b");
8202                       popB (pushedB);
8203                     }
8204                   else
8205                     {
8206                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8207                       emitcode("xrl", "a,b");
8208                     }
8209                 }
8210               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8211                 {
8212                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8213                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8214                   emitcode ("xrl", "a,b");
8215                 }
8216               else if (aopGetUsesAcc (left, offset))
8217                 {
8218                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8219                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8220                 }
8221               else
8222                 {
8223                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8224                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8225                 }
8226
8227               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8228               offset++;
8229             }
8230           if (size)
8231             {
8232               CLRC;
8233               emitLabel (tlbl);
8234               outBitC (result);
8235             }
8236           else if (ifx)
8237             jmpTrueOrFalse (ifx, tlbl);
8238         }
8239       else
8240         {
8241         for (; (size--); offset++)
8242           {
8243             // normal case
8244             // result = left ^ right
8245             if (AOP_TYPE (right) == AOP_LIT)
8246               {
8247                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8248                 if (bytelit == 0)
8249                   {
8250                     aopPut (result,
8251                             aopGet (left, offset, FALSE, FALSE, NULL),
8252                             offset);
8253                     continue;
8254                   }
8255                 D (emitcode (";", "better literal XOR."));
8256                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8257                 emitcode ("xrl", "a, %s",
8258                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8259               }
8260             else
8261               {
8262                 // faster than result <- left, anl result,right
8263                 // and better if result is SFR
8264                 if (AOP_TYPE (left) == AOP_ACC)
8265                   {
8266                     emitcode ("xrl", "a,%s",
8267                               aopGet (right, offset,
8268                                       FALSE, FALSE, DP2_RESULT_REG));
8269                   }
8270                 else
8271                   {
8272                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8273                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8274                       {
8275                           emitcode("mov", "b,a");
8276                           rOp = "b";
8277                       }
8278
8279                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8280                       emitcode ("xrl", "a,%s", rOp);
8281                   }
8282               }
8283             aopPut (result, "a", offset);
8284           }
8285         }
8286     }
8287
8288 release:
8289   freeAsmop (result, NULL, ic, TRUE);
8290   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8291   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8292 }
8293
8294 /*-----------------------------------------------------------------*/
8295 /* genInline - write the inline code out                           */
8296 /*-----------------------------------------------------------------*/
8297 static void
8298 genInline (iCode * ic)
8299 {
8300   char *buffer, *bp, *bp1;
8301
8302   D (emitcode (";", "genInline"));
8303
8304   _G.inLine += (!options.asmpeep);
8305
8306   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8307
8308   /* emit each line as a code */
8309   while (*bp)
8310     {
8311       if (*bp == '\n')
8312         {
8313           *bp++ = '\0';
8314           emitcode (bp1, "");
8315           bp1 = bp;
8316         }
8317       else
8318         {
8319           /* Add \n for labels, not dirs such as c:\mydir */
8320           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8321             {
8322               bp++;
8323               *bp = '\0';
8324               bp++;
8325               emitcode (bp1, "");
8326               bp1 = bp;
8327             }
8328           else
8329             bp++;
8330         }
8331     }
8332   if (bp1 != bp)
8333     emitcode (bp1, "");
8334   /*     emitcode("",buffer); */
8335   _G.inLine -= (!options.asmpeep);
8336 }
8337
8338 /*-----------------------------------------------------------------*/
8339 /* genRRC - rotate right with carry                                */
8340 /*-----------------------------------------------------------------*/
8341 static void
8342 genRRC (iCode * ic)
8343 {
8344   operand *left, *result;
8345   int     size, offset;
8346   char *l;
8347
8348   D (emitcode (";", "genRRC"));
8349
8350   /* rotate right with carry */
8351   left = IC_LEFT (ic);
8352   result = IC_RESULT (ic);
8353   aopOp (left, ic, FALSE, FALSE);
8354   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8355
8356   /* move it to the result */
8357   size = AOP_SIZE (result);
8358   offset = size - 1;
8359   CLRC;
8360
8361   _startLazyDPSEvaluation ();
8362   while (size--)
8363     {
8364       l = aopGet (left, offset, FALSE, FALSE, NULL);
8365       MOVA (l);
8366       emitcode ("rrc", "a");
8367       if (AOP_SIZE (result) > 1)
8368         aopPut (result, "a", offset--);
8369     }
8370   _endLazyDPSEvaluation ();
8371
8372   /* now we need to put the carry into the
8373      highest order byte of the result */
8374   if (AOP_SIZE (result) > 1)
8375     {
8376       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8377       MOVA (l);
8378     }
8379   emitcode ("mov", "acc.7,c");
8380   aopPut (result, "a", AOP_SIZE (result) - 1);
8381   freeAsmop (result, NULL, ic, TRUE);
8382   freeAsmop (left, NULL, ic, TRUE);
8383 }
8384
8385 /*-----------------------------------------------------------------*/
8386 /* genRLC - generate code for rotate left with carry               */
8387 /*-----------------------------------------------------------------*/
8388 static void
8389 genRLC (iCode * ic)
8390 {
8391   operand *left, *result;
8392   int size, offset;
8393   char *l;
8394
8395   D (emitcode (";", "genRLC"));
8396
8397   /* rotate right with carry */
8398   left = IC_LEFT (ic);
8399   result = IC_RESULT (ic);
8400   aopOp (left, ic, FALSE, FALSE);
8401   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8402
8403   /* move it to the result */
8404   size = AOP_SIZE (result);
8405   offset = 0;
8406   if (size--)
8407     {
8408       l = aopGet (left, offset, FALSE, FALSE, NULL);
8409       MOVA (l);
8410       emitcode ("add", "a,acc");
8411       if (AOP_SIZE (result) > 1)
8412         {
8413           aopPut (result, "a", offset++);
8414         }
8415
8416       _startLazyDPSEvaluation ();
8417       while (size--)
8418         {
8419           l = aopGet (left, offset, FALSE, FALSE, NULL);
8420           MOVA (l);
8421           emitcode ("rlc", "a");
8422           if (AOP_SIZE (result) > 1)
8423             aopPut (result, "a", offset++);
8424         }
8425       _endLazyDPSEvaluation ();
8426     }
8427   /* now we need to put the carry into the
8428      highest order byte of the result */
8429   if (AOP_SIZE (result) > 1)
8430     {
8431       l = aopGet (result, 0, FALSE, FALSE, NULL);
8432       MOVA (l);
8433     }
8434   emitcode ("mov", "acc.0,c");
8435   aopPut (result, "a", 0);
8436   freeAsmop (result, NULL, ic, TRUE);
8437   freeAsmop (left, NULL, ic, TRUE);
8438 }
8439
8440 /*-----------------------------------------------------------------*/
8441 /* genGetHbit - generates code get highest order bit               */
8442 /*-----------------------------------------------------------------*/
8443 static void
8444 genGetHbit (iCode * ic)
8445 {
8446   operand *left, *result;
8447
8448   D (emitcode (";", "genGetHbit"));
8449
8450   left = IC_LEFT (ic);
8451   result = IC_RESULT (ic);
8452   aopOp (left, ic, FALSE, FALSE);
8453   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8454
8455   /* get the highest order byte into a */
8456   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8457   if (AOP_TYPE (result) == AOP_CRY)
8458     {
8459       emitcode ("rlc", "a");
8460       outBitC (result);
8461     }
8462   else
8463     {
8464       emitcode ("rl", "a");
8465       emitcode ("anl", "a,#1");
8466       outAcc (result);
8467     }
8468
8469
8470   freeAsmop (result, NULL, ic, TRUE);
8471   freeAsmop (left, NULL, ic, TRUE);
8472 }
8473
8474 /*-----------------------------------------------------------------*/
8475 /* genSwap - generates code to swap nibbles or bytes               */
8476 /*-----------------------------------------------------------------*/
8477 static void
8478 genSwap (iCode * ic)
8479 {
8480   operand *left, *result;
8481
8482   D(emitcode (";     genSwap",""));
8483
8484   left = IC_LEFT (ic);
8485   result = IC_RESULT (ic);
8486   aopOp (left, ic, FALSE, FALSE);
8487   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8488
8489   _startLazyDPSEvaluation ();
8490   switch (AOP_SIZE (left))
8491     {
8492     case 1: /* swap nibbles in byte */
8493       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8494       emitcode ("swap", "a");
8495       aopPut (result, "a", 0);
8496       break;
8497     case 2: /* swap bytes in word */
8498       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8499         {
8500           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8501           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8502           aopPut (result, "a", 1);
8503         }
8504       else if (operandsEqu (left, result))
8505         {
8506           char * reg = "a";
8507           bool pushedB = FALSE, leftInB = FALSE;
8508
8509           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8510           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8511             {
8512               pushedB = pushB ();
8513               emitcode ("mov", "b,a");
8514               reg = "b";
8515               leftInB = TRUE;
8516             }
8517           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8518           aopPut (result, reg, 1);
8519
8520           if (leftInB)
8521             popB (pushedB);
8522         }
8523       else
8524         {
8525           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8526           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8527         }
8528       break;
8529     default:
8530       wassertl(FALSE, "unsupported SWAP operand size");
8531     }
8532   _endLazyDPSEvaluation ();
8533
8534   freeAsmop (result, NULL, ic, TRUE);
8535   freeAsmop (left, NULL, ic, TRUE);
8536 }
8537
8538 /*-----------------------------------------------------------------*/
8539 /* AccRol - rotate left accumulator by known count                 */
8540 /*-----------------------------------------------------------------*/
8541 static void
8542 AccRol (int shCount)
8543 {
8544   shCount &= 0x0007;            // shCount : 0..7
8545
8546   switch (shCount)
8547     {
8548     case 0:
8549       break;
8550     case 1:
8551       emitcode ("rl", "a");
8552       break;
8553     case 2:
8554       emitcode ("rl", "a");
8555       emitcode ("rl", "a");
8556       break;
8557     case 3:
8558       emitcode ("swap", "a");
8559       emitcode ("rr", "a");
8560       break;
8561     case 4:
8562       emitcode ("swap", "a");
8563       break;
8564     case 5:
8565       emitcode ("swap", "a");
8566       emitcode ("rl", "a");
8567       break;
8568     case 6:
8569       emitcode ("rr", "a");
8570       emitcode ("rr", "a");
8571       break;
8572     case 7:
8573       emitcode ("rr", "a");
8574       break;
8575     }
8576 }
8577
8578 /*-----------------------------------------------------------------*/
8579 /* AccLsh - left shift accumulator by known count                  */
8580 /*-----------------------------------------------------------------*/
8581 static void
8582 AccLsh (int shCount)
8583 {
8584   if (shCount != 0)
8585     {
8586       if (shCount == 1)
8587         emitcode ("add", "a,acc");
8588       else if (shCount == 2)
8589         {
8590           emitcode ("add", "a,acc");
8591           emitcode ("add", "a,acc");
8592         }
8593       else
8594         {
8595           /* rotate left accumulator */
8596           AccRol (shCount);
8597           /* and kill the lower order bits */
8598           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8599         }
8600     }
8601 }
8602
8603 /*-----------------------------------------------------------------*/
8604 /* AccRsh - right shift accumulator by known count                 */
8605 /*-----------------------------------------------------------------*/
8606 static void
8607 AccRsh (int shCount)
8608 {
8609   if (shCount != 0)
8610     {
8611       if (shCount == 1)
8612         {
8613           CLRC;
8614           emitcode ("rrc", "a");
8615         }
8616       else
8617         {
8618           /* rotate right accumulator */
8619           AccRol (8 - shCount);
8620           /* and kill the higher order bits */
8621           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8622         }
8623     }
8624 }
8625
8626 #ifdef BETTER_LITERAL_SHIFT
8627 /*-----------------------------------------------------------------*/
8628 /* AccSRsh - signed right shift accumulator by known count                 */
8629 /*-----------------------------------------------------------------*/
8630 static void
8631 AccSRsh (int shCount)
8632 {
8633   symbol *tlbl;
8634   if (shCount != 0)
8635     {
8636       if (shCount == 1)
8637         {
8638           emitcode ("mov", "c,acc.7");
8639           emitcode ("rrc", "a");
8640         }
8641       else if (shCount == 2)
8642         {
8643           emitcode ("mov", "c,acc.7");
8644           emitcode ("rrc", "a");
8645           emitcode ("mov", "c,acc.7");
8646           emitcode ("rrc", "a");
8647         }
8648       else
8649         {
8650           tlbl = newiTempLabel (NULL);
8651           /* rotate right accumulator */
8652           AccRol (8 - shCount);
8653           /* and kill the higher order bits */
8654           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8655           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8656           emitcode ("orl", "a,#!constbyte",
8657                     (unsigned char) ~SRMask[shCount]);
8658           emitLabel (tlbl);
8659         }
8660     }
8661 }
8662 #endif
8663
8664 #ifdef BETTER_LITERAL_SHIFT
8665 /*-----------------------------------------------------------------*/
8666 /* shiftR1Left2Result - shift right one byte from left to result   */
8667 /*-----------------------------------------------------------------*/
8668 static void
8669 shiftR1Left2Result (operand * left, int offl,
8670                     operand * result, int offr,
8671                     int shCount, int sign)
8672 {
8673   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8674   /* shift right accumulator */
8675   if (sign)
8676     AccSRsh (shCount);
8677   else
8678     AccRsh (shCount);
8679   aopPut (result, "a", offr);
8680 }
8681 #endif
8682
8683 #ifdef BETTER_LITERAL_SHIFT
8684 /*-----------------------------------------------------------------*/
8685 /* shiftL1Left2Result - shift left one byte from left to result    */
8686 /*-----------------------------------------------------------------*/
8687 static void
8688 shiftL1Left2Result (operand * left, int offl,
8689                     operand * result, int offr, int shCount)
8690 {
8691   char *l;
8692   l = aopGet (left, offl, FALSE, FALSE, NULL);
8693   MOVA (l);
8694   /* shift left accumulator */
8695   AccLsh (shCount);
8696   aopPut (result, "a", offr);
8697 }
8698 #endif
8699
8700 #ifdef BETTER_LITERAL_SHIFT
8701 /*-----------------------------------------------------------------*/
8702 /* movLeft2Result - move byte from left to result                  */
8703 /*-----------------------------------------------------------------*/
8704 static void
8705 movLeft2Result (operand * left, int offl,
8706                 operand * result, int offr, int sign)
8707 {
8708   char *l;
8709   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8710   {
8711       l = aopGet (left, offl, FALSE, FALSE, NULL);
8712
8713       if (*l == '@' && (IS_AOP_PREG (result)))
8714       {
8715           emitcode ("mov", "a,%s", l);
8716           aopPut (result, "a", offr);
8717       }
8718       else
8719       {
8720           if (!sign)
8721             {
8722               aopPut (result, l, offr);
8723             }
8724           else
8725             {
8726               /* MSB sign in acc.7 ! */
8727               if (getDataSize (left) == offl + 1)
8728                 {
8729                   MOVA (l);
8730                   aopPut (result, "a", offr);
8731                 }
8732             }
8733       }
8734   }
8735 }
8736 #endif
8737
8738 #ifdef BETTER_LITERAL_SHIFT
8739 /*-----------------------------------------------------------------*/
8740 /* AccAXRrl1 - right rotate a:x by 1                               */
8741 /*-----------------------------------------------------------------*/
8742 static void
8743 AccAXRrl1 (char *x)
8744 {
8745   emitcode ("mov", "c,acc.0");
8746   emitcode ("xch", "a,%s", x);
8747   emitcode ("rrc", "a");
8748   emitcode ("xch", "a,%s", x);
8749   emitcode ("rrc", "a");
8750 }
8751 #endif
8752
8753 #ifdef BETTER_LITERAL_SHIFT
8754 //REMOVE ME!!!
8755 /*-----------------------------------------------------------------*/
8756 /* AccAXLrl1 - left rotate a:x by 1                                */
8757 /*-----------------------------------------------------------------*/
8758 static void
8759 AccAXLrl1 (char *x)
8760 {
8761   emitcode ("mov", "c,acc.7");
8762   emitcode ("xch", "a,%s", x);
8763   emitcode ("rlc", "a");
8764   emitcode ("xch", "a,%s", x);
8765   emitcode ("rlc", "a");
8766 }
8767 #endif
8768
8769 #ifdef BETTER_LITERAL_SHIFT
8770 /*-----------------------------------------------------------------*/
8771 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8772 /*-----------------------------------------------------------------*/
8773 static void
8774 AccAXRsh1 (char *x)
8775 {
8776   emitcode ("rrc", "a");
8777   emitcode ("xch", "a,%s", x);
8778   emitcode ("rrc", "a");
8779   emitcode ("xch", "a,%s", x);
8780 }
8781 #endif
8782
8783 #ifdef BETTER_LITERAL_SHIFT
8784 /*-----------------------------------------------------------------*/
8785 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8786 /*-----------------------------------------------------------------*/
8787 static void
8788 AccAXLsh1 (char *x)
8789 {
8790   emitcode ("xch", "a,%s", x);
8791   emitcode ("add", "a,acc");
8792   emitcode ("xch", "a,%s", x);
8793   emitcode ("rlc", "a");
8794 }
8795 #endif
8796
8797 #ifdef BETTER_LITERAL_SHIFT
8798 /*-----------------------------------------------------------------*/
8799 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8800 /*-----------------------------------------------------------------*/
8801 static void
8802 AccAXLsh (char *x, int shCount)
8803 {
8804   switch (shCount)
8805     {
8806     case 0:
8807       break;
8808     case 1:
8809       AccAXLsh1 (x);
8810       break;
8811     case 2:
8812       AccAXLsh1 (x);
8813       AccAXLsh1 (x);
8814       break;
8815     case 3:
8816     case 4:
8817     case 5:                             // AAAAABBB:CCCCCDDD
8818
8819       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8820
8821       emitcode ("anl", "a,#!constbyte",
8822                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8823
8824       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8825
8826       AccRol (shCount);                 // DDDCCCCC:BBB00000
8827
8828       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8829
8830       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8831
8832       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8833
8834       emitcode ("anl", "a,#!constbyte",
8835                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8836
8837       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8838
8839       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8840
8841       break;
8842     case 6:                             // AAAAAABB:CCCCCCDD
8843       emitcode ("anl", "a,#!constbyte",
8844                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8845 #if 1
8846       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8847       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8848       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8849 #else
8850       emitcode ("mov", "c,acc.0");      // c = B
8851       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8852       emitcode("rrc","a");
8853       emitcode("xch","a,%s", x);
8854       emitcode("rrc","a");
8855       emitcode("mov","c,acc.0"); //<< get correct bit
8856       emitcode("xch","a,%s", x);
8857
8858       emitcode("rrc","a");
8859       emitcode("xch","a,%s", x);
8860       emitcode("rrc","a");
8861       emitcode("xch","a,%s", x);
8862 #endif
8863       break;
8864     case 7:                             // a:x <<= 7
8865
8866       emitcode ("anl", "a,#!constbyte",
8867                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8868
8869       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8870
8871       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8872
8873       break;
8874     default:
8875       break;
8876     }
8877 }
8878 #endif
8879
8880 #ifdef BETTER_LITERAL_SHIFT
8881 //REMOVE ME!!!
8882 /*-----------------------------------------------------------------*/
8883 /* AccAXRsh - right shift a:x known count (0..7)                   */
8884 /*-----------------------------------------------------------------*/
8885 static void
8886 AccAXRsh (char *x, int shCount)
8887 {
8888   switch (shCount)
8889     {
8890     case 0:
8891       break;
8892     case 1:
8893       CLRC;
8894       AccAXRsh1 (x);                    // 0->a:x
8895
8896       break;
8897     case 2:
8898       CLRC;
8899       AccAXRsh1 (x);                    // 0->a:x
8900
8901       CLRC;
8902       AccAXRsh1 (x);                    // 0->a:x
8903
8904       break;
8905     case 3:
8906     case 4:
8907     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8908
8909       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8910
8911       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8912
8913       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8914
8915       emitcode ("anl", "a,#!constbyte",
8916                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8917
8918       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8919
8920       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8921
8922       emitcode ("anl", "a,#!constbyte",
8923                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8924
8925       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8926
8927       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8928
8929       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8930
8931       break;
8932     case 6:                             // AABBBBBB:CCDDDDDD
8933
8934       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8935       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8936
8937       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8938
8939       emitcode ("anl", "a,#!constbyte",
8940                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8941
8942       break;
8943     case 7:                             // ABBBBBBB:CDDDDDDD
8944
8945       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8946
8947       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8948
8949       emitcode ("anl", "a,#!constbyte",
8950                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8951
8952       break;
8953     default:
8954       break;
8955     }
8956 }
8957 #endif
8958
8959 #ifdef BETTER_LITERAL_SHIFT
8960 /*-----------------------------------------------------------------*/
8961 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8962 /*-----------------------------------------------------------------*/
8963 static void
8964 AccAXRshS (char *x, int shCount)
8965 {
8966   symbol *tlbl;
8967   switch (shCount)
8968     {
8969     case 0:
8970       break;
8971     case 1:
8972       emitcode ("mov", "c,acc.7");
8973       AccAXRsh1 (x);                    // s->a:x
8974
8975       break;
8976     case 2:
8977       emitcode ("mov", "c,acc.7");
8978       AccAXRsh1 (x);                    // s->a:x
8979
8980       emitcode ("mov", "c,acc.7");
8981       AccAXRsh1 (x);                    // s->a:x
8982
8983       break;
8984     case 3:
8985     case 4:
8986     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8987
8988       tlbl = newiTempLabel (NULL);
8989       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8990
8991       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8992
8993       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8994
8995       emitcode ("anl", "a,#!constbyte",
8996                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8997
8998       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8999
9000       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9001
9002       emitcode ("anl", "a,#!constbyte",
9003                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9004
9005       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9006
9007       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9008
9009       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9010
9011       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9012       emitcode ("orl", "a,#!constbyte",
9013                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9014
9015       emitLabel (tlbl);
9016       break;                            // SSSSAAAA:BBBCCCCC
9017
9018     case 6:                             // AABBBBBB:CCDDDDDD
9019
9020       tlbl = newiTempLabel (NULL);
9021
9022       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9023       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9024
9025       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9026
9027       emitcode ("anl", "a,#!constbyte",
9028                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9029
9030       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9031       emitcode ("orl", "a,#!constbyte",
9032                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9033
9034       emitLabel (tlbl);
9035       break;
9036     case 7:                             // ABBBBBBB:CDDDDDDD
9037
9038       tlbl = newiTempLabel (NULL);
9039
9040       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9041
9042       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9043
9044       emitcode ("anl", "a,#!constbyte",
9045                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9046
9047       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9048       emitcode ("orl", "a,#!constbyte",
9049                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9050
9051       emitLabel (tlbl);
9052       break;
9053     default:
9054       break;
9055     }
9056 }
9057 #endif
9058
9059 #ifdef BETTER_LITERAL_SHIFT
9060 static void
9061 _loadLeftIntoAx(char    **lsb,
9062                 operand *left,
9063                 operand *result,
9064                 int     offl,
9065                 int     offr)
9066 {
9067   // Get the initial value from left into a pair of registers.
9068   // MSB must be in A, LSB can be any register.
9069   //
9070   // If the result is held in registers, it is an optimization
9071   // if the LSB can be held in the register which will hold the,
9072   // result LSB since this saves us from having to copy it into
9073   // the result following AccAXLsh.
9074   //
9075   // If the result is addressed indirectly, this is not a gain.
9076   if (AOP_NEEDSACC(result))
9077   {
9078        char *leftByte;
9079
9080        _startLazyDPSEvaluation();
9081       if (AOP_TYPE(left) == AOP_DPTR2)
9082        {
9083            // Get MSB in A.
9084            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9085            // get LSB in DP2_RESULT_REG.
9086            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9087            assert(!strcmp(leftByte, DP2_RESULT_REG));
9088        }
9089        else
9090        {
9091            // get LSB into DP2_RESULT_REG
9092            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9093            if (strcmp(leftByte, DP2_RESULT_REG))
9094            {
9095                TR_AP("#7");
9096                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9097            }
9098            // And MSB in A.
9099            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9100            assert(strcmp(leftByte, DP2_RESULT_REG));
9101            MOVA (leftByte);
9102        }
9103        _endLazyDPSEvaluation();
9104        *lsb = DP2_RESULT_REG;
9105   }
9106   else
9107   {
9108       if (sameRegs (AOP (result), AOP (left)) &&
9109         ((offl + MSB16) == offr))
9110       {
9111           /* don't crash result[offr] */
9112           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9113           emitcode ("xch", "a,%s",
9114                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9115       }
9116       else
9117       {
9118           movLeft2Result (left, offl, result, offr, 0);
9119           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9120       }
9121       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9122       assert(strcmp(*lsb,"a"));
9123   }
9124 }
9125
9126 static void
9127 _storeAxResults(char    *lsb,
9128                 operand *result,
9129                 int     offr)
9130 {
9131   _startLazyDPSEvaluation();
9132   if (AOP_NEEDSACC(result))
9133   {
9134       /* We have to explicitly update the result LSB.
9135        */
9136       emitcode ("xch","a,%s", lsb);
9137       aopPut (result, "a", offr);
9138       emitcode ("mov","a,%s", lsb);
9139   }
9140   if (getDataSize (result) > 1)
9141   {
9142       aopPut (result, "a", offr + MSB16);
9143   }
9144   _endLazyDPSEvaluation();
9145 }
9146
9147 /*-----------------------------------------------------------------*/
9148 /* shiftL2Left2Result - shift left two bytes from left to result   */
9149 /*-----------------------------------------------------------------*/
9150 static void
9151 shiftL2Left2Result (operand * left, int offl,
9152                     operand * result, int offr, int shCount)
9153 {
9154   char *lsb;
9155
9156   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9157
9158   AccAXLsh (lsb, shCount);
9159
9160   _storeAxResults(lsb, result, offr);
9161 }
9162 #endif
9163
9164 #ifdef BETTER_LITERAL_SHIFT
9165 /*-----------------------------------------------------------------*/
9166 /* shiftR2Left2Result - shift right two bytes from left to result  */
9167 /*-----------------------------------------------------------------*/
9168 static void
9169 shiftR2Left2Result (operand * left, int offl,
9170                     operand * result, int offr,
9171                     int shCount, int sign)
9172 {
9173   char *lsb;
9174
9175   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9176
9177   /* a:x >> shCount (x = lsb(result)) */
9178   if (sign)
9179   {
9180      AccAXRshS(lsb, shCount);
9181   }
9182   else
9183   {
9184     AccAXRsh(lsb, shCount);
9185   }
9186
9187   _storeAxResults(lsb, result, offr);
9188 }
9189 #endif
9190
9191 /*-----------------------------------------------------------------*/
9192 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9193 /*-----------------------------------------------------------------*/
9194 static void
9195 shiftLLeftOrResult (operand * left, int offl,
9196                     operand * result, int offr, int shCount)
9197 {
9198   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9199   /* shift left accumulator */
9200   AccLsh (shCount);
9201   /* or with result */
9202   emitcode ("orl", "a,%s",
9203             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9204   /* back to result */
9205   aopPut (result, "a", offr);
9206 }
9207
9208 #if 0
9209 //REMOVE ME!!!
9210 /*-----------------------------------------------------------------*/
9211 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9212 /*-----------------------------------------------------------------*/
9213 static void
9214 shiftRLeftOrResult (operand * left, int offl,
9215                     operand * result, int offr, int shCount)
9216 {
9217   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9218   /* shift right accumulator */
9219   AccRsh (shCount);
9220   /* or with result */
9221   emitcode ("orl", "a,%s",
9222             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9223   /* back to result */
9224   aopPut (result, "a", offr);
9225 }
9226 #endif
9227
9228 #ifdef BETTER_LITERAL_SHIFT
9229 /*-----------------------------------------------------------------*/
9230 /* genlshOne - left shift a one byte quantity by known count       */
9231 /*-----------------------------------------------------------------*/
9232 static void
9233 genlshOne (operand * result, operand * left, int shCount)
9234 {
9235   D (emitcode (";", "genlshOne"));
9236
9237   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9238 }
9239 #endif
9240
9241 #ifdef BETTER_LITERAL_SHIFT
9242 /*-----------------------------------------------------------------*/
9243 /* genlshTwo - left shift two bytes by known amount != 0           */
9244 /*-----------------------------------------------------------------*/
9245 static void
9246 genlshTwo (operand * result, operand * left, int shCount)
9247 {
9248   int size;
9249
9250   D (emitcode (";", "genlshTwo"));
9251
9252   size = getDataSize (result);
9253
9254   /* if shCount >= 8 */
9255   if (shCount >= 8)
9256   {
9257       shCount -= 8;
9258
9259       _startLazyDPSEvaluation();
9260
9261       if (size > 1)
9262         {
9263           if (shCount)
9264           {
9265             _endLazyDPSEvaluation();
9266             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9267             aopPut (result, zero, LSB);
9268           }
9269           else
9270           {
9271             movLeft2Result (left, LSB, result, MSB16, 0);
9272             aopPut (result, zero, LSB);
9273             _endLazyDPSEvaluation();
9274           }
9275         }
9276         else
9277         {
9278           aopPut (result, zero, LSB);
9279           _endLazyDPSEvaluation();
9280         }
9281   }
9282
9283   /*  1 <= shCount <= 7 */
9284   else
9285     {
9286       if (size == 1)
9287         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9288       else
9289         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9290     }
9291 }
9292 #endif
9293
9294 #if 0
9295 //REMOVE ME!!!
9296 /*-----------------------------------------------------------------*/
9297 /* shiftLLong - shift left one long from left to result            */
9298 /* offl = LSB or MSB16                                             */
9299 /*-----------------------------------------------------------------*/
9300 static void
9301 shiftLLong (operand * left, operand * result, int offr)
9302 {
9303   char *l;
9304   int size = AOP_SIZE (result);
9305
9306   if (size >= LSB + offr)
9307     {
9308       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9309       MOVA (l);
9310       emitcode ("add", "a,acc");
9311       if (sameRegs (AOP (left), AOP (result)) &&
9312           size >= MSB16 + offr && offr != LSB)
9313         emitcode ("xch", "a,%s",
9314                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9315       else
9316         aopPut (result, "a", LSB + offr);
9317     }
9318
9319   if (size >= MSB16 + offr)
9320     {
9321       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9322         {
9323           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9324           MOVA (l);
9325         }
9326       emitcode ("rlc", "a");
9327       if (sameRegs (AOP (left), AOP (result)) &&
9328           size >= MSB24 + offr && offr != LSB)
9329         emitcode ("xch", "a,%s",
9330                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9331       else
9332         aopPut (result, "a", MSB16 + offr);
9333     }
9334
9335   if (size >= MSB24 + offr)
9336     {
9337       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9338         {
9339           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9340           MOVA (l);
9341         }
9342       emitcode ("rlc", "a");
9343       if (sameRegs (AOP (left), AOP (result)) &&
9344           size >= MSB32 + offr && offr != LSB)
9345         emitcode ("xch", "a,%s",
9346                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9347       else
9348         aopPut (result, "a", MSB24 + offr);
9349     }
9350
9351   if (size > MSB32 + offr)
9352     {
9353       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9354         {
9355           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9356           MOVA (l);
9357         }
9358       emitcode ("rlc", "a");
9359       aopPut (result, "a", MSB32 + offr);
9360     }
9361   if (offr != LSB)
9362     aopPut (result, zero, LSB);
9363 }
9364 #endif
9365
9366 #if 0
9367 //REMOVE ME!!!
9368 /*-----------------------------------------------------------------*/
9369 /* genlshFour - shift four byte by a known amount != 0             */
9370 /*-----------------------------------------------------------------*/
9371 static void
9372 genlshFour (operand * result, operand * left, int shCount)
9373 {
9374   int size;
9375
9376   D (emitcode (";", "genlshFour"));
9377
9378   size = AOP_SIZE (result);
9379
9380   /* if shifting more that 3 bytes */
9381   if (shCount >= 24)
9382     {
9383       shCount -= 24;
9384       if (shCount)
9385         /* lowest order of left goes to the highest
9386            order of the destination */
9387         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9388       else
9389         movLeft2Result (left, LSB, result, MSB32, 0);
9390       aopPut (result, zero, LSB);
9391       aopPut (result, zero, MSB16);
9392       aopPut (result, zero, MSB24);
9393       return;
9394     }
9395
9396   /* more than two bytes */
9397   else if (shCount >= 16)
9398     {
9399       /* lower order two bytes goes to higher order two bytes */
9400       shCount -= 16;
9401       /* if some more remaining */
9402       if (shCount)
9403         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9404       else
9405         {
9406           movLeft2Result (left, MSB16, result, MSB32, 0);
9407           movLeft2Result (left, LSB, result, MSB24, 0);
9408         }
9409       aopPut (result, zero, MSB16);
9410       aopPut (result, zero, LSB);
9411       return;
9412     }
9413
9414   /* if more than 1 byte */
9415   else if (shCount >= 8)
9416     {
9417       /* lower order three bytes goes to higher order  three bytes */
9418       shCount -= 8;
9419       if (size == 2)
9420         {
9421           if (shCount)
9422             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9423           else
9424             movLeft2Result (left, LSB, result, MSB16, 0);
9425         }
9426       else
9427         {                       /* size = 4 */
9428           if (shCount == 0)
9429             {
9430               movLeft2Result (left, MSB24, result, MSB32, 0);
9431               movLeft2Result (left, MSB16, result, MSB24, 0);
9432               movLeft2Result (left, LSB, result, MSB16, 0);
9433               aopPut (result, zero, LSB);
9434             }
9435           else if (shCount == 1)
9436             shiftLLong (left, result, MSB16);
9437           else
9438             {
9439               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9440               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9441               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9442               aopPut (result, zero, LSB);
9443             }
9444         }
9445     }
9446
9447   /* 1 <= shCount <= 7 */
9448   else if (shCount <= 2)
9449     {
9450       shiftLLong (left, result, LSB);
9451       if (shCount == 2)
9452         shiftLLong (result, result, LSB);
9453     }
9454   /* 3 <= shCount <= 7, optimize */
9455   else
9456     {
9457       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9458       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9459       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9460     }
9461 }
9462 #endif
9463
9464 #ifdef BETTER_LITERAL_SHIFT
9465 /*-----------------------------------------------------------------*/
9466 /* genLeftShiftLiteral - left shifting by known count              */
9467 /*-----------------------------------------------------------------*/
9468 static bool
9469 genLeftShiftLiteral (operand * left,
9470                      operand * right,
9471                      operand * result,
9472                      iCode * ic)
9473 {
9474   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9475   int size;
9476
9477   size = getSize (operandType (result));
9478
9479   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9480
9481   /* We only handle certain easy cases so far. */
9482   if ((shCount != 0)
9483    && (shCount < (size * 8))
9484    && (size != 1)
9485    && (size != 2))
9486   {
9487       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9488       return FALSE;
9489   }
9490
9491   freeAsmop (right, NULL, ic, TRUE);
9492
9493   aopOp(left, ic, FALSE, FALSE);
9494   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9495
9496 #if 0 // debug spew
9497   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9498   {
9499         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9500         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9501         {
9502            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9503         }
9504   }
9505   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9506   {
9507         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9508         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9509         {
9510            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9511         }
9512   }
9513 #endif
9514
9515 #if VIEW_SIZE
9516   emitcode ("; shift left ", "result %d, left %d", size,
9517             AOP_SIZE (left));
9518 #endif
9519
9520   /* I suppose that the left size >= result size */
9521   if (shCount == 0)
9522   {
9523         _startLazyDPSEvaluation();
9524         while (size--)
9525         {
9526           movLeft2Result (left, size, result, size, 0);
9527         }
9528         _endLazyDPSEvaluation();
9529   }
9530   else if (shCount >= (size * 8))
9531   {
9532     _startLazyDPSEvaluation();
9533     while (size--)
9534     {
9535       aopPut (result, zero, size);
9536     }
9537     _endLazyDPSEvaluation();
9538   }
9539   else
9540   {
9541       switch (size)
9542         {
9543         case 1:
9544           genlshOne (result, left, shCount);
9545           break;
9546
9547         case 2:
9548           genlshTwo (result, left, shCount);
9549           break;
9550 #if 0
9551         case 4:
9552           genlshFour (result, left, shCount);
9553           break;
9554 #endif
9555         default:
9556           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9557                   "*** ack! mystery literal shift!\n");
9558           break;
9559         }
9560     }
9561   freeAsmop (result, NULL, ic, TRUE);
9562   freeAsmop (left, NULL, ic, TRUE);
9563   return TRUE;
9564 }
9565 #endif
9566
9567 /*-----------------------------------------------------------------*/
9568 /* genLeftShift - generates code for left shifting                 */
9569 /*-----------------------------------------------------------------*/
9570 static void
9571 genLeftShift (iCode * ic)
9572 {
9573   operand *left, *right, *result;
9574   int size, offset;
9575   char *l;
9576   symbol *tlbl, *tlbl1;
9577   bool pushedB;
9578
9579   D (emitcode (";", "genLeftShift"));
9580
9581   right = IC_RIGHT (ic);
9582   left = IC_LEFT (ic);
9583   result = IC_RESULT (ic);
9584
9585   aopOp (right, ic, FALSE, FALSE);
9586
9587
9588 #ifdef BETTER_LITERAL_SHIFT
9589   /* if the shift count is known then do it
9590      as efficiently as possible */
9591   if (AOP_TYPE (right) == AOP_LIT)
9592     {
9593       if (genLeftShiftLiteral (left, right, result, ic))
9594       {
9595         return;
9596       }
9597     }
9598 #endif
9599
9600   /* shift count is unknown then we have to form
9601      a loop get the loop count in B : Note: we take
9602      only the lower order byte since shifting
9603      more that 32 bits make no sense anyway, ( the
9604      largest size of an object can be only 32 bits ) */
9605
9606   pushedB = pushB ();
9607   if (AOP_TYPE (right) == AOP_LIT)
9608   {
9609       /* Really should be handled by genLeftShiftLiteral,
9610        * but since I'm too lazy to fix that today, at least we can make
9611        * some small improvement.
9612        */
9613        emitcode("mov", "b,#!constbyte",
9614                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9615   }
9616   else
9617   {
9618       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9619       emitcode ("inc", "b");
9620   }
9621   freeAsmop (right, NULL, ic, TRUE);
9622   aopOp (left, ic, FALSE, FALSE);
9623   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9624
9625   /* now move the left to the result if they are not the same */
9626   if (!sameRegs (AOP (left), AOP (result)) &&
9627       AOP_SIZE (result) > 1)
9628     {
9629
9630       size = AOP_SIZE (result);
9631       offset = 0;
9632       _startLazyDPSEvaluation ();
9633       while (size--)
9634         {
9635           l = aopGet (left, offset, FALSE, TRUE, NULL);
9636           if (*l == '@' && (IS_AOP_PREG (result)))
9637             {
9638
9639               emitcode ("mov", "a,%s", l);
9640               aopPut (result, "a", offset);
9641             }
9642           else
9643             aopPut (result, l, offset);
9644           offset++;
9645         }
9646       _endLazyDPSEvaluation ();
9647     }
9648
9649   tlbl = newiTempLabel (NULL);
9650   size = AOP_SIZE (result);
9651   offset = 0;
9652   tlbl1 = newiTempLabel (NULL);
9653
9654   /* if it is only one byte then */
9655   if (size == 1)
9656     {
9657       symbol *tlbl1 = newiTempLabel (NULL);
9658
9659       l = aopGet (left, 0, FALSE, FALSE, NULL);
9660       MOVA (l);
9661       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9662       emitLabel (tlbl);
9663       emitcode ("add", "a,acc");
9664       emitLabel (tlbl1);
9665       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9666       popB (pushedB);
9667       aopPut (result, "a", 0);
9668       goto release;
9669     }
9670
9671   reAdjustPreg (AOP (result));
9672
9673   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9674   emitLabel (tlbl);
9675   l = aopGet (result, offset, FALSE, FALSE, NULL);
9676   MOVA (l);
9677   emitcode ("add", "a,acc");
9678   aopPut (result, "a", offset++);
9679   _startLazyDPSEvaluation ();
9680   while (--size)
9681     {
9682       l = aopGet (result, offset, FALSE, FALSE, NULL);
9683       MOVA (l);
9684       emitcode ("rlc", "a");
9685       aopPut (result, "a", offset++);
9686     }
9687   _endLazyDPSEvaluation ();
9688   reAdjustPreg (AOP (result));
9689
9690   emitLabel (tlbl1);
9691   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9692   popB (pushedB);
9693 release:
9694   freeAsmop (result, NULL, ic, TRUE);
9695   freeAsmop (left, NULL, ic, TRUE);
9696 }
9697
9698 #ifdef BETTER_LITERAL_SHIFT
9699 /*-----------------------------------------------------------------*/
9700 /* genrshOne - right shift a one byte quantity by known count      */
9701 /*-----------------------------------------------------------------*/
9702 static void
9703 genrshOne (operand * result, operand * left,
9704            int shCount, int sign)
9705 {
9706   D (emitcode (";", "genrshOne"));
9707
9708   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9709 }
9710 #endif
9711
9712 #ifdef BETTER_LITERAL_SHIFT
9713 /*-----------------------------------------------------------------*/
9714 /* genrshTwo - right shift two bytes by known amount != 0          */
9715 /*-----------------------------------------------------------------*/
9716 static void
9717 genrshTwo (operand * result, operand * left,
9718            int shCount, int sign)
9719 {
9720   D (emitcode (";", "genrshTwo"));
9721
9722   /* if shCount >= 8 */
9723   if (shCount >= 8)
9724     {
9725       shCount -= 8;
9726       _startLazyDPSEvaluation();
9727       if (shCount)
9728         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9729       else
9730         movLeft2Result (left, MSB16, result, LSB, sign);
9731       addSign (result, MSB16, sign);
9732       _endLazyDPSEvaluation();
9733     }
9734
9735   /*  1 <= shCount <= 7 */
9736   else
9737     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9738 }
9739 #endif
9740
9741 /*-----------------------------------------------------------------*/
9742 /* shiftRLong - shift right one long from left to result           */
9743 /* offl = LSB or MSB16                                             */
9744 /*-----------------------------------------------------------------*/
9745 static void
9746 shiftRLong (operand * left, int offl,
9747             operand * result, int sign)
9748 {
9749   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9750
9751   if (overlapping && offl>1)
9752     {
9753       // we are in big trouble, but this shouldn't happen
9754       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9755     }
9756
9757   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9758
9759   if (offl==MSB16)
9760     {
9761       // shift is > 8
9762       if (sign)
9763         {
9764           emitcode ("rlc", "a");
9765           emitcode ("subb", "a,acc");
9766           emitcode ("xch", "a,%s",
9767                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9768         }
9769       else
9770         {
9771           aopPut (result, zero, MSB32);
9772         }
9773     }
9774
9775   if (!sign)
9776     {
9777       emitcode ("clr", "c");
9778     }
9779   else
9780     {
9781       emitcode ("mov", "c,acc.7");
9782     }
9783
9784   emitcode ("rrc", "a");
9785
9786   if (overlapping && offl==MSB16)
9787     {
9788       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9789     }
9790   else
9791     {
9792       aopPut (result, "a", MSB32 - offl);
9793       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9794     }
9795
9796   emitcode ("rrc", "a");
9797
9798   if (overlapping && offl==MSB16)
9799     {
9800       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9801     }
9802   else
9803     {
9804       aopPut (result, "a", MSB24 - offl);
9805       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9806     }
9807
9808   emitcode ("rrc", "a");
9809   if (offl != LSB)
9810     {
9811       aopPut (result, "a", MSB16 - offl);
9812     }
9813   else
9814     {
9815       if (overlapping && offl==MSB16)
9816         {
9817           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9818         }
9819       else
9820         {
9821           aopPut (result, "a", MSB16 - offl);
9822           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9823         }
9824       emitcode ("rrc", "a");
9825       aopPut (result, "a", LSB);
9826     }
9827 }
9828
9829 /*-----------------------------------------------------------------*/
9830 /* genrshFour - shift four byte by a known amount != 0             */
9831 /*-----------------------------------------------------------------*/
9832 static void
9833 genrshFour (operand * result, operand * left,
9834             int shCount, int sign)
9835 {
9836   D (emitcode (";", "genrshFour"));
9837
9838   /* if shifting more that 3 bytes */
9839   if (shCount >= 24)
9840     {
9841       shCount -= 24;
9842       _startLazyDPSEvaluation();
9843       if (shCount)
9844         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9845       else
9846         movLeft2Result (left, MSB32, result, LSB, sign);
9847       addSign (result, MSB16, sign);
9848       _endLazyDPSEvaluation();
9849     }
9850   else if (shCount >= 16)
9851     {
9852       shCount -= 16;
9853       _startLazyDPSEvaluation();
9854       if (shCount)
9855         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9856       else
9857         {
9858           movLeft2Result (left, MSB24, result, LSB, 0);
9859           movLeft2Result (left, MSB32, result, MSB16, sign);
9860         }
9861       addSign (result, MSB24, sign);
9862       _endLazyDPSEvaluation();
9863     }
9864   else if (shCount >= 8)
9865     {
9866       shCount -= 8;
9867       _startLazyDPSEvaluation();
9868       if (shCount == 1)
9869         {
9870             shiftRLong (left, MSB16, result, sign);
9871         }
9872       else if (shCount == 0)
9873         {
9874           movLeft2Result (left, MSB16, result, LSB, 0);
9875           movLeft2Result (left, MSB24, result, MSB16, 0);
9876           movLeft2Result (left, MSB32, result, MSB24, sign);
9877           addSign (result, MSB32, sign);
9878         }
9879       else
9880         {
9881           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9882           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9883           /* the last shift is signed */
9884           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9885           addSign (result, MSB32, sign);
9886         }
9887         _endLazyDPSEvaluation();
9888     }
9889   else
9890     {
9891       /* 1 <= shCount <= 7 */
9892       if (shCount <= 2)
9893         {
9894           shiftRLong (left, LSB, result, sign);
9895           if (shCount == 2)
9896             shiftRLong (result, LSB, result, sign);
9897         }
9898       else
9899         {
9900           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9901           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9902           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9903         }
9904     }
9905 }
9906
9907 #ifdef BETTER_LITERAL_SHIFT
9908 /*-----------------------------------------------------------------*/
9909 /* genRightShiftLiteral - right shifting by known count            */
9910 /*-----------------------------------------------------------------*/
9911 static bool
9912 genRightShiftLiteral (operand * left,
9913                       operand * right,
9914                       operand * result,
9915                       iCode * ic,
9916                       int sign)
9917 {
9918   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9919   int size;
9920
9921   size = getSize (operandType (result));
9922
9923   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9924
9925   /* We only handle certain easy cases so far. */
9926   if ((shCount != 0)
9927    && (shCount < (size * 8))
9928    && (size != 1)
9929    && (size != 2)
9930    && (size != 4))
9931   {
9932       D(emitcode (";", "genRightShiftLiteral wimping out"););
9933       return FALSE;
9934   }
9935
9936   freeAsmop (right, NULL, ic, TRUE);
9937
9938   aopOp (left, ic, FALSE, FALSE);
9939   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9940
9941 #if VIEW_SIZE
9942   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9943             AOP_SIZE (left));
9944 #endif
9945
9946   /* test the LEFT size !!! */
9947
9948   /* I suppose that the left size >= result size */
9949   if (shCount == 0)
9950   {
9951       size = getDataSize (result);
9952       _startLazyDPSEvaluation();
9953       while (size--)
9954         movLeft2Result (left, size, result, size, 0);
9955       _endLazyDPSEvaluation();
9956   }
9957   else if (shCount >= (size * 8))
9958     {
9959       if (sign)
9960         {
9961           /* get sign in acc.7 */
9962           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9963         }
9964       addSign (result, LSB, sign);
9965     }
9966   else
9967     {
9968       switch (size)
9969         {
9970         case 1:
9971           genrshOne (result, left, shCount, sign);
9972           break;
9973
9974         case 2:
9975           genrshTwo (result, left, shCount, sign);
9976           break;
9977 #if 1
9978         case 4:
9979           genrshFour (result, left, shCount, sign);
9980           break;
9981 #endif
9982         default:
9983           break;
9984         }
9985     }
9986   freeAsmop (result, NULL, ic, TRUE);
9987   freeAsmop (left, NULL, ic, TRUE);
9988
9989   return TRUE;
9990 }
9991 #endif
9992
9993 /*-----------------------------------------------------------------*/
9994 /* genSignedRightShift - right shift of signed number              */
9995 /*-----------------------------------------------------------------*/
9996 static void
9997 genSignedRightShift (iCode * ic)
9998 {
9999   operand *right, *left, *result;
10000   int size, offset;
10001   char *l;
10002   symbol *tlbl, *tlbl1;
10003   bool pushedB;
10004
10005   D (emitcode (";", "genSignedRightShift"));
10006
10007   /* we do it the hard way put the shift count in b
10008      and loop thru preserving the sign */
10009
10010   right = IC_RIGHT (ic);
10011   left = IC_LEFT (ic);
10012   result = IC_RESULT (ic);
10013
10014   aopOp (right, ic, FALSE, FALSE);
10015
10016 #ifdef BETTER_LITERAL_SHIFT
10017   if (AOP_TYPE (right) == AOP_LIT)
10018     {
10019       if (genRightShiftLiteral (left, right, result, ic, 1))
10020       {
10021         return;
10022       }
10023     }
10024 #endif
10025   /* shift count is unknown then we have to form
10026      a loop get the loop count in B : Note: we take
10027      only the lower order byte since shifting
10028      more that 32 bits make no sense anyway, ( the
10029      largest size of an object can be only 32 bits ) */
10030
10031   pushedB = pushB ();
10032   if (AOP_TYPE (right) == AOP_LIT)
10033   {
10034       /* Really should be handled by genRightShiftLiteral,
10035        * but since I'm too lazy to fix that today, at least we can make
10036        * some small improvement.
10037        */
10038        emitcode("mov", "b,#!constbyte",
10039                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10040   }
10041   else
10042   {
10043         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10044         emitcode ("inc", "b");
10045   }
10046   freeAsmop (right, NULL, ic, TRUE);
10047   aopOp (left, ic, FALSE, FALSE);
10048   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10049
10050   /* now move the left to the result if they are not the
10051      same */
10052   if (!sameRegs (AOP (left), AOP (result)) &&
10053       AOP_SIZE (result) > 1)
10054     {
10055
10056       size = AOP_SIZE (result);
10057       offset = 0;
10058       _startLazyDPSEvaluation ();
10059       while (size--)
10060         {
10061           l = aopGet (left, offset, FALSE, TRUE, NULL);
10062           if (*l == '@' && IS_AOP_PREG (result))
10063             {
10064
10065               emitcode ("mov", "a,%s", l);
10066               aopPut (result, "a", offset);
10067             }
10068           else
10069             aopPut (result, l, offset);
10070           offset++;
10071         }
10072       _endLazyDPSEvaluation ();
10073     }
10074
10075   /* mov the highest order bit to OVR */
10076   tlbl = newiTempLabel (NULL);
10077   tlbl1 = newiTempLabel (NULL);
10078
10079   size = AOP_SIZE (result);
10080   offset = size - 1;
10081   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10082   emitcode ("rlc", "a");
10083   emitcode ("mov", "ov,c");
10084   /* if it is only one byte then */
10085   if (size == 1)
10086     {
10087       l = aopGet (left, 0, FALSE, FALSE, NULL);
10088       MOVA (l);
10089       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10090       emitLabel (tlbl);
10091       emitcode ("mov", "c,ov");
10092       emitcode ("rrc", "a");
10093       emitLabel (tlbl1);
10094       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10095       popB (pushedB);
10096       aopPut (result, "a", 0);
10097       goto release;
10098     }
10099
10100   reAdjustPreg (AOP (result));
10101   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10102   emitLabel (tlbl);
10103   emitcode ("mov", "c,ov");
10104   _startLazyDPSEvaluation ();
10105   while (size--)
10106     {
10107       l = aopGet (result, offset, FALSE, FALSE, NULL);
10108       MOVA (l);
10109       emitcode ("rrc", "a");
10110       aopPut (result, "a", offset--);
10111     }
10112   _endLazyDPSEvaluation ();
10113   reAdjustPreg (AOP (result));
10114   emitLabel (tlbl1);
10115   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10116   popB (pushedB);
10117
10118 release:
10119   freeAsmop (result, NULL, ic, TRUE);
10120   freeAsmop (left, NULL, ic, TRUE);
10121 }
10122
10123 /*-----------------------------------------------------------------*/
10124 /* genRightShift - generate code for right shifting                */
10125 /*-----------------------------------------------------------------*/
10126 static void
10127 genRightShift (iCode * ic)
10128 {
10129   operand *right, *left, *result;
10130   sym_link *letype;
10131   int size, offset;
10132   char *l;
10133   symbol *tlbl, *tlbl1;
10134   bool pushedB;
10135
10136   D (emitcode (";", "genRightShift"));
10137
10138   /* if signed then we do it the hard way preserve the
10139      sign bit moving it inwards */
10140   letype = getSpec (operandType (IC_LEFT (ic)));
10141
10142   if (!SPEC_USIGN (letype))
10143     {
10144       genSignedRightShift (ic);
10145       return;
10146     }
10147
10148   /* signed & unsigned types are treated the same : i.e. the
10149      signed is NOT propagated inwards : quoting from the
10150      ANSI - standard : "for E1 >> E2, is equivalent to division
10151      by 2**E2 if unsigned or if it has a non-negative value,
10152      otherwise the result is implementation defined ", MY definition
10153      is that the sign does not get propagated */
10154
10155   right = IC_RIGHT (ic);
10156   left = IC_LEFT (ic);
10157   result = IC_RESULT (ic);
10158
10159   aopOp (right, ic, FALSE, FALSE);
10160
10161 #ifdef BETTER_LITERAL_SHIFT
10162   /* if the shift count is known then do it
10163      as efficiently as possible */
10164   if (AOP_TYPE (right) == AOP_LIT)
10165     {
10166       if (genRightShiftLiteral (left, right, result, ic, 0))
10167       {
10168         return;
10169       }
10170     }
10171 #endif
10172
10173   /* shift count is unknown then we have to form
10174      a loop get the loop count in B : Note: we take
10175      only the lower order byte since shifting
10176      more that 32 bits make no sense anyway, ( the
10177      largest size of an object can be only 32 bits ) */
10178
10179   pushedB = pushB ();
10180   if (AOP_TYPE (right) == AOP_LIT)
10181   {
10182       /* Really should be handled by genRightShiftLiteral,
10183        * but since I'm too lazy to fix that today, at least we can make
10184        * some small improvement.
10185        */
10186        emitcode("mov", "b,#!constbyte",
10187                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10188   }
10189   else
10190   {
10191       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10192       emitcode ("inc", "b");
10193   }
10194   freeAsmop (right, NULL, ic, TRUE);
10195   aopOp (left, ic, FALSE, FALSE);
10196   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10197
10198   /* now move the left to the result if they are not the
10199      same */
10200   if (!sameRegs (AOP (left), AOP (result)) &&
10201       AOP_SIZE (result) > 1)
10202     {
10203       size = AOP_SIZE (result);
10204       offset = 0;
10205       _startLazyDPSEvaluation ();
10206       while (size--)
10207         {
10208           l = aopGet (left, offset, FALSE, TRUE, NULL);
10209           if (*l == '@' && IS_AOP_PREG (result))
10210             {
10211
10212               emitcode ("mov", "a,%s", l);
10213               aopPut (result, "a", offset);
10214             }
10215           else
10216             aopPut (result, l, offset);
10217           offset++;
10218         }
10219       _endLazyDPSEvaluation ();
10220     }
10221
10222   tlbl = newiTempLabel (NULL);
10223   tlbl1 = newiTempLabel (NULL);
10224   size = AOP_SIZE (result);
10225   offset = size - 1;
10226
10227   /* if it is only one byte then */
10228   if (size == 1)
10229     {
10230       l = aopGet (left, 0, FALSE, FALSE, NULL);
10231       MOVA (l);
10232       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10233       emitLabel (tlbl);
10234       CLRC;
10235       emitcode ("rrc", "a");
10236       emitLabel (tlbl1);
10237       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10238       popB (pushedB);
10239       aopPut (result, "a", 0);
10240       goto release;
10241     }
10242
10243   reAdjustPreg (AOP (result));
10244   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10245   emitLabel (tlbl);
10246   CLRC;
10247   _startLazyDPSEvaluation ();
10248   while (size--)
10249     {
10250       l = aopGet (result, offset, FALSE, FALSE, NULL);
10251       MOVA (l);
10252       emitcode ("rrc", "a");
10253       aopPut (result, "a", offset--);
10254     }
10255   _endLazyDPSEvaluation ();
10256   reAdjustPreg (AOP (result));
10257
10258   emitLabel (tlbl1);
10259   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10260   popB (pushedB);
10261
10262 release:
10263   freeAsmop (result, NULL, ic, TRUE);
10264   freeAsmop (left, NULL, ic, TRUE);
10265 }
10266
10267 /*-----------------------------------------------------------------*/
10268 /* emitPtrByteGet - emits code to get a byte into A through a      */
10269 /*                  pointer register (R0, R1, or DPTR). The        */
10270 /*                  original value of A can be preserved in B.     */
10271 /*-----------------------------------------------------------------*/
10272 static void
10273 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10274 {
10275   switch (p_type)
10276     {
10277     case IPOINTER:
10278     case POINTER:
10279       if (preserveAinB)
10280         emitcode ("mov", "b,a");
10281       emitcode ("mov", "a,@%s", rname);
10282       break;
10283
10284     case PPOINTER:
10285       if (preserveAinB)
10286         emitcode ("mov", "b,a");
10287       emitcode ("movx", "a,@%s", rname);
10288       break;
10289
10290     case FPOINTER:
10291       if (preserveAinB)
10292         emitcode ("mov", "b,a");
10293       emitcode ("movx", "a,@dptr");
10294       break;
10295
10296     case CPOINTER:
10297       if (preserveAinB)
10298         emitcode ("mov", "b,a");
10299       emitcode ("clr", "a");
10300       emitcode ("movc", "a,@a+dptr");
10301       break;
10302
10303     case GPOINTER:
10304       if (preserveAinB)
10305         {
10306           emitcode ("push", "b");
10307           emitcode ("push", "acc");
10308         }
10309       emitcode ("lcall", "__gptrget");
10310       if (preserveAinB)
10311         emitcode ("pop", "b");
10312       break;
10313     }
10314 }
10315
10316 /*-----------------------------------------------------------------*/
10317 /* emitPtrByteSet - emits code to set a byte from src through a    */
10318 /*                  pointer register (R0, R1, or DPTR).            */
10319 /*-----------------------------------------------------------------*/
10320 static void
10321 emitPtrByteSet (char *rname, int p_type, char *src)
10322 {
10323   switch (p_type)
10324     {
10325     case IPOINTER:
10326     case POINTER:
10327       if (*src=='@')
10328         {
10329           MOVA (src);
10330           emitcode ("mov", "@%s,a", rname);
10331         }
10332       else
10333         emitcode ("mov", "@%s,%s", rname, src);
10334       break;
10335
10336     case PPOINTER:
10337       MOVA (src);
10338       emitcode ("movx", "@%s,a", rname);
10339       break;
10340
10341     case FPOINTER:
10342       MOVA (src);
10343       emitcode ("movx", "@dptr,a");
10344       break;
10345
10346     case GPOINTER:
10347       MOVA (src);
10348       emitcode ("lcall", "__gptrput");
10349       break;
10350     }
10351 }
10352
10353 /*-----------------------------------------------------------------*/
10354 /* genUnpackBits - generates code for unpacking bits               */
10355 /*-----------------------------------------------------------------*/
10356 static void
10357 genUnpackBits (operand * result, char *rname, int ptype)
10358 {
10359   int offset = 0;       /* result byte offset */
10360   int rsize;            /* result size */
10361   int rlen = 0;         /* remaining bitfield length */
10362   sym_link *etype;      /* bitfield type information */
10363   int blen;             /* bitfield length */
10364   int bstr;             /* bitfield starting bit within byte */
10365
10366   D(emitcode (";     genUnpackBits",""));
10367
10368   etype = getSpec (operandType (result));
10369   rsize = getSize (operandType (result));
10370   blen = SPEC_BLEN (etype);
10371   bstr = SPEC_BSTR (etype);
10372
10373   /* If the bitfield length is less than a byte */
10374   if (blen < 8)
10375     {
10376       emitPtrByteGet (rname, ptype, FALSE);
10377       AccRol (8 - bstr);
10378       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10379       if (!SPEC_USIGN (etype))
10380         {
10381           /* signed bitfield */
10382           symbol *tlbl = newiTempLabel (NULL);
10383
10384           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10385           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10386           emitLabel (tlbl);
10387         }
10388       aopPut (result, "a", offset++);
10389       goto finish;
10390     }
10391
10392   /* Bit field did not fit in a byte. Copy all
10393      but the partial byte at the end.  */
10394   for (rlen=blen;rlen>=8;rlen-=8)
10395     {
10396       emitPtrByteGet (rname, ptype, FALSE);
10397       aopPut (result, "a", offset++);
10398       if (rlen>8)
10399         emitcode ("inc", "%s", rname);
10400     }
10401
10402   /* Handle the partial byte at the end */
10403   if (rlen)
10404     {
10405       emitPtrByteGet (rname, ptype, FALSE);
10406       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10407       if (!SPEC_USIGN (etype))
10408         {
10409           /* signed bitfield */
10410           symbol *tlbl = newiTempLabel (NULL);
10411
10412           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10413           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10414           emitLabel (tlbl);
10415         }
10416       aopPut (result, "a", offset++);
10417     }
10418
10419 finish:
10420   if (offset < rsize)
10421     {
10422       char *source;
10423
10424       if (SPEC_USIGN (etype))
10425         source = zero;
10426       else
10427         {
10428           /* signed bitfield: sign extension with 0x00 or 0xff */
10429           emitcode ("rlc", "a");
10430           emitcode ("subb", "a,acc");
10431
10432           source = "a";
10433         }
10434       rsize -= offset;
10435       while (rsize--)
10436         aopPut (result, source, offset++);
10437     }
10438 }
10439
10440
10441 /*-----------------------------------------------------------------*/
10442 /* genDataPointerGet - generates code when ptr offset is known     */
10443 /*-----------------------------------------------------------------*/
10444 static void
10445 genDataPointerGet (operand * left,
10446                    operand * result,
10447                    iCode * ic)
10448 {
10449   char *l;
10450   char buffer[256];
10451   int size, offset = 0;
10452   aopOp (result, ic, TRUE, FALSE);
10453
10454   /* get the string representation of the name */
10455   l = aopGet (left, 0, FALSE, TRUE, NULL);
10456   size = AOP_SIZE (result);
10457   _startLazyDPSEvaluation ();
10458   while (size--)
10459     {
10460         if (offset)
10461         {
10462             SNPRINTF (buffer, sizeof(buffer),
10463                       "(%s + %d)", l + 1, offset);
10464         }
10465         else
10466         {
10467             SNPRINTF (buffer, sizeof(buffer),
10468                       "%s", l + 1);
10469         }
10470       aopPut (result, buffer, offset++);
10471     }
10472   _endLazyDPSEvaluation ();
10473
10474   freeAsmop (result, NULL, ic, TRUE);
10475   freeAsmop (left, NULL, ic, TRUE);
10476 }
10477
10478 /*-----------------------------------------------------------------*/
10479 /* genNearPointerGet - emitcode for near pointer fetch             */
10480 /*-----------------------------------------------------------------*/
10481 static void
10482 genNearPointerGet (operand * left,
10483                    operand * result,
10484                    iCode * ic,
10485                    iCode *pi)
10486 {
10487   asmop *aop = NULL;
10488   regs *preg;
10489   char *rname;
10490   sym_link *rtype, *retype, *letype;
10491   sym_link *ltype = operandType (left);
10492   char buffer[80];
10493
10494   rtype = operandType (result);
10495   retype = getSpec (rtype);
10496   letype = getSpec (ltype);
10497
10498   aopOp (left, ic, FALSE, FALSE);
10499
10500   /* if left is rematerialisable and
10501      result is not bitfield variable type and
10502      the left is pointer to data space i.e
10503      lower 128 bytes of space */
10504   if (AOP_TYPE (left) == AOP_IMMD &&
10505       !IS_BITFIELD (retype) &&
10506       !IS_BITFIELD (letype) &&
10507       DCL_TYPE (ltype) == POINTER)
10508     {
10509       genDataPointerGet (left, result, ic);
10510       return;
10511     }
10512
10513   /* if the value is already in a pointer register
10514      then don't need anything more */
10515   if (!AOP_INPREG (AOP (left)))
10516     {
10517       /* otherwise get a free pointer register */
10518       aop = newAsmop (0);
10519       preg = getFreePtr (ic, &aop, FALSE);
10520       emitcode ("mov", "%s,%s",
10521                 preg->name,
10522                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10523       rname = preg->name;
10524     }
10525   else
10526     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10527
10528   freeAsmop (left, NULL, ic, TRUE);
10529   aopOp (result, ic, FALSE, FALSE);
10530
10531   /* if bitfield then unpack the bits */
10532   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10533     genUnpackBits (result, rname, POINTER);
10534   else
10535     {
10536       /* we have can just get the values */
10537       int size = AOP_SIZE (result);
10538       int offset = 0;
10539
10540       while (size--)
10541         {
10542           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10543             {
10544
10545               emitcode ("mov", "a,@%s", rname);
10546               aopPut (result, "a", offset);
10547             }
10548           else
10549             {
10550               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10551               aopPut (result, buffer, offset);
10552             }
10553           offset++;
10554           if (size || pi)
10555             emitcode ("inc", "%s", rname);
10556         }
10557     }
10558
10559   /* now some housekeeping stuff */
10560   if (aop)      /* we had to allocate for this iCode */
10561     {
10562       if (pi) { /* post increment present */
10563         aopPut (left, rname, 0);
10564       }
10565       freeAsmop (NULL, aop, ic, TRUE);
10566     }
10567   else
10568     {
10569       /* we did not allocate which means left
10570          already in a pointer register, then
10571          if size > 0 && this could be used again
10572          we have to point it back to where it
10573          belongs */
10574       if (AOP_SIZE (result) > 1 &&
10575           !OP_SYMBOL (left)->remat &&
10576           (OP_SYMBOL (left)->liveTo > ic->seq ||
10577            ic->depth) &&
10578           !pi)
10579         {
10580           int size = AOP_SIZE (result) - 1;
10581           while (size--)
10582             emitcode ("dec", "%s", rname);
10583         }
10584     }
10585
10586   /* done */
10587   freeAsmop (result, NULL, ic, TRUE);
10588   if (pi) pi->generated = 1;
10589 }
10590
10591 /*-----------------------------------------------------------------*/
10592 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10593 /*-----------------------------------------------------------------*/
10594 static void
10595 genPagedPointerGet (operand * left,
10596                     operand * result,
10597                     iCode * ic,
10598                     iCode * pi)
10599 {
10600   asmop *aop = NULL;
10601   regs *preg;
10602   char *rname;
10603   sym_link *rtype, *retype, *letype;
10604
10605   rtype = operandType (result);
10606   retype = getSpec (rtype);
10607   letype = getSpec (operandType (left));
10608   aopOp (left, ic, FALSE, FALSE);
10609
10610   /* if the value is already in a pointer register
10611      then don't need anything more */
10612   if (!AOP_INPREG (AOP (left)))
10613     {
10614       /* otherwise get a free pointer register */
10615       aop = newAsmop (0);
10616       preg = getFreePtr (ic, &aop, FALSE);
10617       emitcode ("mov", "%s,%s",
10618                 preg->name,
10619                 aopGet (left, 0, FALSE, TRUE, NULL));
10620       rname = preg->name;
10621     }
10622   else
10623     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10624
10625   freeAsmop (left, NULL, ic, TRUE);
10626   aopOp (result, ic, FALSE, FALSE);
10627
10628   /* if bitfield then unpack the bits */
10629   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10630     genUnpackBits (result, rname, PPOINTER);
10631   else
10632     {
10633       /* we have can just get the values */
10634       int size = AOP_SIZE (result);
10635       int offset = 0;
10636
10637       while (size--)
10638         {
10639
10640           emitcode ("movx", "a,@%s", rname);
10641           aopPut (result, "a", offset);
10642
10643           offset++;
10644
10645           if (size || pi)
10646             emitcode ("inc", "%s", rname);
10647         }
10648     }
10649
10650   /* now some housekeeping stuff */
10651   if (aop)      /* we had to allocate for this iCode */
10652     {
10653       if (pi)
10654         aopPut (left, rname, 0);
10655       freeAsmop (NULL, aop, ic, TRUE);
10656     }
10657   else
10658     {
10659       /* we did not allocate which means left
10660          already in a pointer register, then
10661          if size > 0 && this could be used again
10662          we have to point it back to where it
10663          belongs */
10664       if (AOP_SIZE (result) > 1 &&
10665           !OP_SYMBOL (left)->remat &&
10666           (OP_SYMBOL (left)->liveTo > ic->seq ||
10667            ic->depth) &&
10668           !pi)
10669         {
10670           int size = AOP_SIZE (result) - 1;
10671           while (size--)
10672             emitcode ("dec", "%s", rname);
10673         }
10674     }
10675
10676   /* done */
10677   freeAsmop (result, NULL, ic, TRUE);
10678   if (pi) pi->generated = 1;
10679 }
10680
10681 /*-----------------------------------------------------------------*/
10682 /* genFarPointerGet - get value from far space                     */
10683 /*-----------------------------------------------------------------*/
10684 static void
10685 genFarPointerGet (operand * left,
10686                   operand * result, iCode * ic, iCode *pi)
10687 {
10688   int size, offset, dopi=1;
10689   sym_link *retype = getSpec (operandType (result));
10690   sym_link *letype = getSpec (operandType (left));
10691   D (emitcode (";", "genFarPointerGet"););
10692
10693   aopOp (left, ic, FALSE, FALSE);
10694
10695   /* if the operand is already in dptr
10696      then we do nothing else we move the value to dptr */
10697   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10698     {
10699       /* if this is rematerializable */
10700       if (AOP_TYPE (left) == AOP_IMMD)
10701         {
10702           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10703         }
10704       else
10705         {
10706           /* we need to get it byte by byte */
10707           _startLazyDPSEvaluation ();
10708           if (AOP_TYPE (left) != AOP_DPTR)
10709             {
10710               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10711               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10712               if (options.model == MODEL_FLAT24)
10713                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10714             }
10715           else
10716             {
10717               /* We need to generate a load to DPTR indirect through DPTR. */
10718               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10719               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10720               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10721               if (options.model == MODEL_FLAT24)
10722                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10723               emitcode ("pop", "dph");
10724               emitcode ("pop", "dpl");
10725               dopi =0;
10726             }
10727           _endLazyDPSEvaluation ();
10728         }
10729     }
10730   /* so dptr now contains the address */
10731   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10732
10733   /* if bit then unpack */
10734   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10735       if (AOP_INDPTRn(left)) {
10736           genSetDPTR(AOP(left)->aopu.dptr);
10737       }
10738       genUnpackBits (result, "dptr", FPOINTER);
10739       if (AOP_INDPTRn(left)) {
10740           genSetDPTR(0);
10741       }
10742   } else
10743     {
10744       size = AOP_SIZE (result);
10745       offset = 0;
10746
10747       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10748           while (size--) {
10749               genSetDPTR(AOP(left)->aopu.dptr);
10750               emitcode ("movx", "a,@dptr");
10751               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10752                   emitcode ("inc", "dptr");
10753               genSetDPTR (0);
10754               aopPut (result, "a", offset++);
10755           }
10756       } else {
10757           _startLazyDPSEvaluation ();
10758           while (size--) {
10759               if (AOP_INDPTRn(left)) {
10760                   genSetDPTR(AOP(left)->aopu.dptr);
10761               } else {
10762                   genSetDPTR (0);
10763               }
10764               _flushLazyDPS ();
10765
10766               emitcode ("movx", "a,@dptr");
10767               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10768                   emitcode ("inc", "dptr");
10769
10770               aopPut (result, "a", offset++);
10771           }
10772           _endLazyDPSEvaluation ();
10773       }
10774     }
10775   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10776       if (!AOP_INDPTRn(left)) {
10777           _startLazyDPSEvaluation ();
10778           aopPut (left, "dpl", 0);
10779           aopPut (left, "dph", 1);
10780           if (options.model == MODEL_FLAT24)
10781               aopPut (left, "dpx", 2);
10782           _endLazyDPSEvaluation ();
10783       }
10784     pi->generated = 1;
10785   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10786              AOP_SIZE(result) > 1 &&
10787              IS_SYMOP(left) &&
10788              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10789
10790       size = AOP_SIZE (result) - 1;
10791       if (AOP_INDPTRn(left)) {
10792           genSetDPTR(AOP(left)->aopu.dptr);
10793       }
10794       while (size--) emitcode ("lcall","__decdptr");
10795       if (AOP_INDPTRn(left)) {
10796           genSetDPTR(0);
10797       }
10798   }
10799
10800   freeAsmop (result, NULL, ic, TRUE);
10801   freeAsmop (left, NULL, ic, TRUE);
10802 }
10803
10804 /*-----------------------------------------------------------------*/
10805 /* genCodePointerGet - get value from code space                   */
10806 /*-----------------------------------------------------------------*/
10807 static void
10808 genCodePointerGet (operand * left,
10809                     operand * result, iCode * ic, iCode *pi)
10810 {
10811   int size, offset, dopi=1;
10812   sym_link *retype = getSpec (operandType (result));
10813
10814   aopOp (left, ic, FALSE, FALSE);
10815
10816   /* if the operand is already in dptr
10817      then we do nothing else we move the value to dptr */
10818   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10819     {
10820       /* if this is rematerializable */
10821       if (AOP_TYPE (left) == AOP_IMMD)
10822         {
10823           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10824         }
10825       else
10826         {                       /* we need to get it byte by byte */
10827           _startLazyDPSEvaluation ();
10828           if (AOP_TYPE (left) != AOP_DPTR)
10829             {
10830               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10831               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10832               if (options.model == MODEL_FLAT24)
10833                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10834             }
10835           else
10836             {
10837               /* We need to generate a load to DPTR indirect through DPTR. */
10838               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10839               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10840               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10841               if (options.model == MODEL_FLAT24)
10842                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10843               emitcode ("pop", "dph");
10844               emitcode ("pop", "dpl");
10845               dopi=0;
10846             }
10847           _endLazyDPSEvaluation ();
10848         }
10849     }
10850   /* so dptr now contains the address */
10851   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10852
10853   /* if bit then unpack */
10854   if (IS_BITFIELD (retype)) {
10855       if (AOP_INDPTRn(left)) {
10856           genSetDPTR(AOP(left)->aopu.dptr);
10857       }
10858       genUnpackBits (result, "dptr", CPOINTER);
10859       if (AOP_INDPTRn(left)) {
10860           genSetDPTR(0);
10861       }
10862   } else
10863     {
10864       size = AOP_SIZE (result);
10865       offset = 0;
10866       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10867           while (size--) {
10868               genSetDPTR(AOP(left)->aopu.dptr);
10869               emitcode ("clr", "a");
10870               emitcode ("movc", "a,@a+dptr");
10871               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10872                   emitcode ("inc", "dptr");
10873               genSetDPTR (0);
10874               aopPut (result, "a", offset++);
10875           }
10876       } else {
10877           _startLazyDPSEvaluation ();
10878           while (size--)
10879               {
10880                   if (AOP_INDPTRn(left)) {
10881                       genSetDPTR(AOP(left)->aopu.dptr);
10882                   } else {
10883                       genSetDPTR (0);
10884                   }
10885                   _flushLazyDPS ();
10886
10887                   emitcode ("clr", "a");
10888                   emitcode ("movc", "a,@a+dptr");
10889                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10890                       emitcode ("inc", "dptr");
10891                   aopPut (result, "a", offset++);
10892               }
10893           _endLazyDPSEvaluation ();
10894       }
10895     }
10896   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10897       if (!AOP_INDPTRn(left)) {
10898           _startLazyDPSEvaluation ();
10899
10900           aopPut (left, "dpl", 0);
10901           aopPut (left, "dph", 1);
10902           if (options.model == MODEL_FLAT24)
10903               aopPut (left, "dpx", 2);
10904
10905           _endLazyDPSEvaluation ();
10906       }
10907       pi->generated = 1;
10908   } else if (IS_SYMOP(left) &&
10909              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10910              AOP_SIZE(result) > 1 &&
10911              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10912
10913       size = AOP_SIZE (result) - 1;
10914       if (AOP_INDPTRn(left)) {
10915           genSetDPTR(AOP(left)->aopu.dptr);
10916       }
10917       while (size--) emitcode ("lcall","__decdptr");
10918       if (AOP_INDPTRn(left)) {
10919           genSetDPTR(0);
10920       }
10921   }
10922
10923   freeAsmop (result, NULL, ic, TRUE);
10924   freeAsmop (left, NULL, ic, TRUE);
10925 }
10926
10927 /*-----------------------------------------------------------------*/
10928 /* genGenPointerGet - get value from generic pointer space         */
10929 /*-----------------------------------------------------------------*/
10930 static void
10931 genGenPointerGet (operand * left,
10932                   operand * result, iCode * ic, iCode * pi)
10933 {
10934   int size, offset;
10935   bool pushedB;
10936   sym_link *retype = getSpec (operandType (result));
10937   sym_link *letype = getSpec (operandType (left));
10938
10939   D (emitcode (";", "genGenPointerGet"));
10940
10941   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10942
10943   pushedB = pushB ();
10944   /* if the operand is already in dptr
10945      then we do nothing else we move the value to dptr */
10946   if (AOP_TYPE (left) != AOP_STR)
10947     {
10948       /* if this is rematerializable */
10949       if (AOP_TYPE (left) == AOP_IMMD)
10950         {
10951           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10952           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10953             {
10954               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10955             }
10956           else
10957             {
10958               emitcode ("mov", "b,#%d", pointerCode (retype));
10959             }
10960         }
10961       else
10962         {                       /* we need to get it byte by byte */
10963           _startLazyDPSEvaluation ();
10964           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10965           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10966           if (options.model == MODEL_FLAT24) {
10967               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10968               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10969           } else {
10970               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10971           }
10972           _endLazyDPSEvaluation ();
10973         }
10974     }
10975
10976   /* so dptr-b now contains the address */
10977   aopOp (result, ic, FALSE, TRUE);
10978
10979   /* if bit then unpack */
10980   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10981   {
10982     genUnpackBits (result, "dptr", GPOINTER);
10983   }
10984   else
10985     {
10986         size = AOP_SIZE (result);
10987         offset = 0;
10988
10989         while (size--)
10990         {
10991             if (size)
10992             {
10993                 // Get two bytes at a time, results in _AP & A.
10994                 // dptr will be incremented ONCE by __gptrgetWord.
10995                 //
10996                 // Note: any change here must be coordinated
10997                 // with the implementation of __gptrgetWord
10998                 // in device/lib/_gptrget.c
10999                 emitcode ("lcall", "__gptrgetWord");
11000                 aopPut (result, DP2_RESULT_REG, offset++);
11001                 aopPut (result, "a", offset++);
11002                 size--;
11003             }
11004             else
11005             {
11006                 // Only one byte to get.
11007                 emitcode ("lcall", "__gptrget");
11008                 aopPut (result, "a", offset++);
11009             }
11010
11011             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11012             {
11013                 emitcode ("inc", "dptr");
11014             }
11015         }
11016     }
11017
11018   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11019     _startLazyDPSEvaluation ();
11020
11021     aopPut (left, "dpl", 0);
11022     aopPut (left, "dph", 1);
11023     if (options.model == MODEL_FLAT24) {
11024         aopPut (left, "dpx", 2);
11025         aopPut (left, "b", 3);
11026     } else  aopPut (left, "b", 2);
11027
11028     _endLazyDPSEvaluation ();
11029
11030     pi->generated = 1;
11031   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11032              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11033
11034       size = AOP_SIZE (result) - 1;
11035       while (size--) emitcode ("lcall","__decdptr");
11036   }
11037   popB (pushedB);
11038
11039   freeAsmop (result, NULL, ic, TRUE);
11040   freeAsmop (left, NULL, ic, TRUE);
11041 }
11042
11043 /*-----------------------------------------------------------------*/
11044 /* genPointerGet - generate code for pointer get                   */
11045 /*-----------------------------------------------------------------*/
11046 static void
11047 genPointerGet (iCode * ic, iCode *pi)
11048 {
11049   operand *left, *result;
11050   sym_link *type, *etype;
11051   int p_type;
11052
11053   D (emitcode (";", "genPointerGet"));
11054
11055   left = IC_LEFT (ic);
11056   result = IC_RESULT (ic);
11057
11058   /* depending on the type of pointer we need to
11059      move it to the correct pointer register */
11060   type = operandType (left);
11061   etype = getSpec (type);
11062   /* if left is of type of pointer then it is simple */
11063   if (IS_PTR (type) && !IS_FUNC (type->next))
11064     p_type = DCL_TYPE (type);
11065   else
11066     {
11067       /* we have to go by the storage class */
11068       p_type = PTR_TYPE (SPEC_OCLS (etype));
11069     }
11070
11071   /* special case when cast remat */
11072   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11073       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11074     {
11075       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11076       type = operandType (left);
11077       p_type = DCL_TYPE (type);
11078     }
11079   /* now that we have the pointer type we assign
11080      the pointer values */
11081   switch (p_type)
11082     {
11083
11084     case POINTER:
11085     case IPOINTER:
11086       genNearPointerGet (left, result, ic, pi);
11087       break;
11088
11089     case PPOINTER:
11090       genPagedPointerGet (left, result, ic, pi);
11091       break;
11092
11093     case FPOINTER:
11094       genFarPointerGet (left, result, ic, pi);
11095       break;
11096
11097     case CPOINTER:
11098       genCodePointerGet (left, result, ic, pi);
11099       break;
11100
11101     case GPOINTER:
11102       genGenPointerGet (left, result, ic, pi);
11103       break;
11104     }
11105 }
11106
11107
11108 /*-----------------------------------------------------------------*/
11109 /* genPackBits - generates code for packed bit storage             */
11110 /*-----------------------------------------------------------------*/
11111 static void
11112 genPackBits (sym_link * etype,
11113              operand * right,
11114              char *rname, int p_type)
11115 {
11116   int offset = 0;       /* source byte offset */
11117   int rlen = 0;         /* remaining bitfield length */
11118   int blen;             /* bitfield length */
11119   int bstr;             /* bitfield starting bit within byte */
11120   int litval;           /* source literal value (if AOP_LIT) */
11121   unsigned char mask;   /* bitmask within current byte */
11122
11123   D(emitcode (";     genPackBits",""));
11124
11125   blen = SPEC_BLEN (etype);
11126   bstr = SPEC_BSTR (etype);
11127
11128   /* If the bitfield length is less than a byte */
11129   if (blen < 8)
11130     {
11131       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11132               (unsigned char) (0xFF >> (8 - bstr)));
11133
11134       if (AOP_TYPE (right) == AOP_LIT)
11135         {
11136           /* Case with a bitfield length <8 and literal source
11137           */
11138           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11139           litval <<= bstr;
11140           litval &= (~mask) & 0xff;
11141           emitPtrByteGet (rname, p_type, FALSE);
11142           if ((mask|litval)!=0xff)
11143             emitcode ("anl","a,#!constbyte", mask);
11144           if (litval)
11145             emitcode ("orl","a,#!constbyte", litval);
11146         }
11147       else
11148         {
11149           if ((blen==1) && (p_type!=GPOINTER))
11150             {
11151               /* Case with a bitfield length == 1 and no generic pointer
11152               */
11153               if (AOP_TYPE (right) == AOP_CRY)
11154                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11155               else
11156                 {
11157                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11158                   emitcode ("rrc","a");
11159                 }
11160               emitPtrByteGet (rname, p_type, FALSE);
11161               emitcode ("mov","acc.%d,c",bstr);
11162             }
11163           else
11164             {
11165               bool pushedB;
11166               /* Case with a bitfield length < 8 and arbitrary source
11167               */
11168               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11169               /* shift and mask source value */
11170               AccLsh (bstr);
11171               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11172
11173               pushedB = pushB ();
11174               /* transfer A to B and get next byte */
11175               emitPtrByteGet (rname, p_type, TRUE);
11176
11177               emitcode ("anl", "a,#!constbyte", mask);
11178               emitcode ("orl", "a,b");
11179               if (p_type == GPOINTER)
11180                 emitcode ("pop", "b");
11181
11182               popB (pushedB);
11183            }
11184         }
11185
11186       emitPtrByteSet (rname, p_type, "a");
11187       return;
11188     }
11189
11190   /* Bit length is greater than 7 bits. In this case, copy  */
11191   /* all except the partial byte at the end                 */
11192   for (rlen=blen;rlen>=8;rlen-=8)
11193     {
11194       emitPtrByteSet (rname, p_type,
11195                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11196       if (rlen>8)
11197         emitcode ("inc", "%s", rname);
11198     }
11199
11200   /* If there was a partial byte at the end */
11201   if (rlen)
11202     {
11203       mask = (((unsigned char) -1 << rlen) & 0xff);
11204
11205       if (AOP_TYPE (right) == AOP_LIT)
11206         {
11207           /* Case with partial byte and literal source
11208           */
11209           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11210           litval >>= (blen-rlen);
11211           litval &= (~mask) & 0xff;
11212           emitPtrByteGet (rname, p_type, FALSE);
11213           if ((mask|litval)!=0xff)
11214             emitcode ("anl","a,#!constbyte", mask);
11215           if (litval)
11216             emitcode ("orl","a,#!constbyte", litval);
11217         }
11218       else
11219         {
11220           bool pushedB;
11221           /* Case with partial byte and arbitrary source
11222           */
11223           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11224           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11225
11226           pushedB = pushB ();
11227           /* transfer A to B and get next byte */
11228           emitPtrByteGet (rname, p_type, TRUE);
11229
11230           emitcode ("anl", "a,#!constbyte", mask);
11231           emitcode ("orl", "a,b");
11232           if (p_type == GPOINTER)
11233             emitcode ("pop", "b");
11234
11235           popB (pushedB);
11236         }
11237       emitPtrByteSet (rname, p_type, "a");
11238     }
11239 }
11240
11241
11242 /*-----------------------------------------------------------------*/
11243 /* genDataPointerSet - remat pointer to data space                 */
11244 /*-----------------------------------------------------------------*/
11245 static void
11246 genDataPointerSet (operand * right,
11247                    operand * result,
11248                    iCode * ic)
11249 {
11250   int size, offset = 0;
11251   char *l, buffer[256];
11252
11253   D (emitcode (";", "genDataPointerSet"));
11254
11255   aopOp (right, ic, FALSE, FALSE);
11256
11257   l = aopGet (result, 0, FALSE, TRUE, NULL);
11258   size = AOP_SIZE (right);
11259   while (size--)
11260     {
11261       if (offset)
11262           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11263       else
11264           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11265       emitcode ("mov", "%s,%s", buffer,
11266                 aopGet (right, offset++, FALSE, FALSE, NULL));
11267     }
11268
11269   freeAsmop (result, NULL, ic, TRUE);
11270   freeAsmop (right, NULL, ic, TRUE);
11271 }
11272
11273 /*-----------------------------------------------------------------*/
11274 /* genNearPointerSet - emitcode for near pointer put                */
11275 /*-----------------------------------------------------------------*/
11276 static void
11277 genNearPointerSet (operand * right,
11278                    operand * result,
11279                    iCode * ic,
11280                    iCode * pi)
11281 {
11282   asmop *aop = NULL;
11283   char *rname, *l;
11284   sym_link *retype, *letype;
11285   sym_link *ptype = operandType (result);
11286
11287   D (emitcode (";", "genNearPointerSet"));
11288
11289   retype = getSpec (operandType (right));
11290   letype = getSpec (ptype);
11291
11292   aopOp (result, ic, FALSE, FALSE);
11293
11294   /* if the result is rematerializable &
11295      in data space & not a bit variable */
11296   if (AOP_TYPE (result) == AOP_IMMD &&
11297       DCL_TYPE (ptype) == POINTER &&
11298       !IS_BITVAR (retype) &&
11299       !IS_BITVAR (letype))
11300     {
11301       genDataPointerSet (right, result, ic);
11302       return;
11303     }
11304
11305   /* if the value is already in a pointer register
11306      then don't need anything more */
11307   if (!AOP_INPREG (AOP (result)))
11308     {
11309       /* otherwise get a free pointer register */
11310       regs *preg;
11311
11312       aop = newAsmop (0);
11313       preg = getFreePtr (ic, &aop, FALSE);
11314       emitcode ("mov", "%s,%s",
11315                 preg->name,
11316                 aopGet (result, 0, FALSE, TRUE, NULL));
11317       rname = preg->name;
11318     }
11319   else
11320     {
11321       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11322     }
11323
11324   aopOp (right, ic, FALSE, FALSE);
11325
11326   /* if bitfield then unpack the bits */
11327   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11328     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11329   else
11330     {
11331       /* we can just get the values */
11332       int size = AOP_SIZE (right);
11333       int offset = 0;
11334
11335       while (size--)
11336         {
11337           l = aopGet (right, offset, FALSE, TRUE, NULL);
11338           if ((*l == '@') || (strcmp (l, "acc") == 0))
11339             {
11340               MOVA (l);
11341               emitcode ("mov", "@%s,a", rname);
11342             }
11343           else
11344             emitcode ("mov", "@%s,%s", rname, l);
11345           if (size || pi)
11346             emitcode ("inc", "%s", rname);
11347           offset++;
11348         }
11349     }
11350
11351   /* now some housekeeping stuff */
11352   if (aop)      /* we had to allocate for this iCode */
11353     {
11354       if (pi)
11355         aopPut (result, rname, 0);
11356       freeAsmop (NULL, aop, ic, TRUE);
11357     }
11358   else
11359     {
11360       /* we did not allocate which means left
11361          already in a pointer register, then
11362          if size > 0 && this could be used again
11363          we have to point it back to where it
11364          belongs */
11365       if (AOP_SIZE (right) > 1 &&
11366           !OP_SYMBOL (result)->remat &&
11367           (OP_SYMBOL (result)->liveTo > ic->seq ||
11368            ic->depth) &&
11369           !pi)
11370         {
11371           int size = AOP_SIZE (right) - 1;
11372           while (size--)
11373             emitcode ("dec", "%s", rname);
11374         }
11375     }
11376
11377   /* done */
11378   if (pi) pi->generated = 1;
11379   freeAsmop (result, NULL, ic, TRUE);
11380   freeAsmop (right, NULL, ic, TRUE);
11381 }
11382
11383 /*-----------------------------------------------------------------*/
11384 /* genPagedPointerSet - emitcode for Paged pointer put             */
11385 /*-----------------------------------------------------------------*/
11386 static void
11387 genPagedPointerSet (operand * right,
11388                     operand * result,
11389                     iCode * ic,
11390                     iCode *pi)
11391 {
11392   asmop *aop = NULL;
11393   char *rname, *l;
11394   sym_link *retype, *letype;
11395
11396   D (emitcode (";", "genPagedPointerSet"));
11397
11398   retype = getSpec (operandType (right));
11399   letype = getSpec (operandType (result));
11400
11401   aopOp (result, ic, FALSE, FALSE);
11402
11403   /* if the value is already in a pointer register
11404      then don't need anything more */
11405   if (!AOP_INPREG (AOP (result)))
11406     {
11407       /* otherwise get a free pointer register */
11408       regs *preg;
11409
11410       aop = newAsmop (0);
11411       preg = getFreePtr (ic, &aop, FALSE);
11412       emitcode ("mov", "%s,%s",
11413                 preg->name,
11414                 aopGet (result, 0, FALSE, TRUE, NULL));
11415       rname = preg->name;
11416     }
11417   else
11418     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11419
11420   aopOp (right, ic, FALSE, FALSE);
11421
11422   /* if bitfield then unpack the bits */
11423   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11424     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11425   else
11426     {
11427       /* we have can just get the values */
11428       int size = AOP_SIZE (right);
11429       int offset = 0;
11430
11431       while (size--)
11432         {
11433           l = aopGet (right, offset, FALSE, TRUE, NULL);
11434           MOVA (l);
11435           emitcode ("movx", "@%s,a", rname);
11436
11437           if (size || pi)
11438             emitcode ("inc", "%s", rname);
11439
11440           offset++;
11441         }
11442     }
11443
11444   /* now some housekeeping stuff */
11445   if (aop)
11446     {
11447       if (pi)
11448         aopPut (result, rname, 0);
11449       /* we had to allocate for this iCode */
11450       freeAsmop (NULL, aop, ic, TRUE);
11451     }
11452   else
11453     {
11454       /* we did not allocate which means left
11455          already in a pointer register, then
11456          if size > 0 && this could be used again
11457          we have to point it back to where it
11458          belongs */
11459       if (AOP_SIZE (right) > 1 &&
11460           !OP_SYMBOL (result)->remat &&
11461           (OP_SYMBOL (result)->liveTo > ic->seq ||
11462            ic->depth) &&
11463           !pi)
11464         {
11465           int size = AOP_SIZE (right) - 1;
11466           while (size--)
11467             emitcode ("dec", "%s", rname);
11468         }
11469     }
11470
11471   /* done */
11472   if (pi) pi->generated = 1;
11473   freeAsmop (result, NULL, ic, TRUE);
11474   freeAsmop (right, NULL, ic, TRUE);
11475 }
11476
11477 /*-----------------------------------------------------------------*/
11478 /* genFarPointerSet - set value from far space                     */
11479 /*-----------------------------------------------------------------*/
11480 static void
11481 genFarPointerSet (operand * right,
11482                   operand * result, iCode * ic, iCode *pi)
11483 {
11484   int size, offset, dopi=1;
11485   sym_link *retype = getSpec (operandType (right));
11486   sym_link *letype = getSpec (operandType (result));
11487
11488   aopOp (result, ic, FALSE, FALSE);
11489
11490   /* if the operand is already in dptr
11491      then we do nothing else we move the value to dptr */
11492   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11493     {
11494       /* if this is remateriazable */
11495       if (AOP_TYPE (result) == AOP_IMMD)
11496         emitcode ("mov", "dptr,%s",
11497                   aopGet (result, 0, TRUE, FALSE, NULL));
11498       else
11499         {
11500           /* we need to get it byte by byte */
11501           _startLazyDPSEvaluation ();
11502           if (AOP_TYPE (result) != AOP_DPTR)
11503             {
11504               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11505               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11506               if (options.model == MODEL_FLAT24)
11507                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11508             }
11509           else
11510             {
11511               /* We need to generate a load to DPTR indirect through DPTR. */
11512               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11513
11514               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11515               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11516               if (options.model == MODEL_FLAT24)
11517                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11518               emitcode ("pop", "dph");
11519               emitcode ("pop", "dpl");
11520               dopi=0;
11521             }
11522           _endLazyDPSEvaluation ();
11523         }
11524     }
11525   /* so dptr now contains the address */
11526   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11527
11528   /* if bit then unpack */
11529   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11530   {
11531       if (AOP_INDPTRn(result)) {
11532           genSetDPTR(AOP(result)->aopu.dptr);
11533       }
11534       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11535       if (AOP_INDPTRn(result)) {
11536           genSetDPTR(0);
11537       }
11538   } else {
11539       size = AOP_SIZE (right);
11540       offset = 0;
11541       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11542           while (size--) {
11543               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11544
11545               genSetDPTR(AOP(result)->aopu.dptr);
11546               emitcode ("movx", "@dptr,a");
11547               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11548                   emitcode ("inc", "dptr");
11549               genSetDPTR (0);
11550           }
11551       } else {
11552           _startLazyDPSEvaluation ();
11553           while (size--) {
11554               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11555
11556               if (AOP_INDPTRn(result)) {
11557                   genSetDPTR(AOP(result)->aopu.dptr);
11558               } else {
11559                   genSetDPTR (0);
11560               }
11561               _flushLazyDPS ();
11562
11563               emitcode ("movx", "@dptr,a");
11564               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11565                   emitcode ("inc", "dptr");
11566           }
11567           _endLazyDPSEvaluation ();
11568       }
11569   }
11570
11571   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11572       if (!AOP_INDPTRn(result)) {
11573           _startLazyDPSEvaluation ();
11574
11575           aopPut (result,"dpl",0);
11576           aopPut (result,"dph",1);
11577           if (options.model == MODEL_FLAT24)
11578               aopPut (result,"dpx",2);
11579
11580           _endLazyDPSEvaluation ();
11581       }
11582       pi->generated=1;
11583   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11584              AOP_SIZE(right) > 1 &&
11585              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11586
11587       size = AOP_SIZE (right) - 1;
11588       if (AOP_INDPTRn(result)) {
11589           genSetDPTR(AOP(result)->aopu.dptr);
11590       }
11591       while (size--) emitcode ("lcall","__decdptr");
11592       if (AOP_INDPTRn(result)) {
11593           genSetDPTR(0);
11594       }
11595   }
11596   freeAsmop (result, NULL, ic, TRUE);
11597   freeAsmop (right, NULL, ic, TRUE);
11598 }
11599
11600 /*-----------------------------------------------------------------*/
11601 /* genGenPointerSet - set value from generic pointer space         */
11602 /*-----------------------------------------------------------------*/
11603 static void
11604 genGenPointerSet (operand * right,
11605                   operand * result, iCode * ic, iCode *pi)
11606 {
11607   int size, offset;
11608   bool pushedB;
11609   sym_link *retype = getSpec (operandType (right));
11610   sym_link *letype = getSpec (operandType (result));
11611
11612   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11613
11614   pushedB = pushB ();
11615   /* if the operand is already in dptr
11616      then we do nothing else we move the value to dptr */
11617   if (AOP_TYPE (result) != AOP_STR)
11618     {
11619       _startLazyDPSEvaluation ();
11620       /* if this is remateriazable */
11621       if (AOP_TYPE (result) == AOP_IMMD)
11622         {
11623           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11624           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11625           {
11626               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11627           }
11628           else
11629           {
11630               emitcode ("mov",
11631                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11632           }
11633         }
11634       else
11635         {                       /* we need to get it byte by byte */
11636           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11637           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11638           if (options.model == MODEL_FLAT24) {
11639             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11640             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11641           } else {
11642             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11643           }
11644         }
11645       _endLazyDPSEvaluation ();
11646     }
11647   /* so dptr + b now contains the address */
11648   aopOp (right, ic, FALSE, TRUE);
11649
11650   /* if bit then unpack */
11651   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11652     {
11653         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11654     }
11655   else
11656     {
11657         size = AOP_SIZE (right);
11658         offset = 0;
11659
11660         _startLazyDPSEvaluation ();
11661         while (size--)
11662         {
11663             if (size)
11664             {
11665                 // Set two bytes at a time, passed in _AP & A.
11666                 // dptr will be incremented ONCE by __gptrputWord.
11667                 //
11668                 // Note: any change here must be coordinated
11669                 // with the implementation of __gptrputWord
11670                 // in device/lib/_gptrput.c
11671                 emitcode("mov", "_ap, %s",
11672                          aopGet (right, offset++, FALSE, FALSE, NULL));
11673                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11674
11675                 genSetDPTR (0);
11676                 _flushLazyDPS ();
11677                 emitcode ("lcall", "__gptrputWord");
11678                 size--;
11679             }
11680             else
11681             {
11682                 // Only one byte to put.
11683                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11684
11685                 genSetDPTR (0);
11686                 _flushLazyDPS ();
11687                 emitcode ("lcall", "__gptrput");
11688             }
11689
11690             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11691             {
11692                 emitcode ("inc", "dptr");
11693             }
11694         }
11695         _endLazyDPSEvaluation ();
11696     }
11697
11698   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11699       _startLazyDPSEvaluation ();
11700
11701       aopPut (result, "dpl",0);
11702       aopPut (result, "dph",1);
11703       if (options.model == MODEL_FLAT24) {
11704           aopPut (result, "dpx",2);
11705           aopPut (result, "b",3);
11706       } else {
11707           aopPut (result, "b",2);
11708       }
11709       _endLazyDPSEvaluation ();
11710
11711       pi->generated=1;
11712   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11713              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11714
11715       size = AOP_SIZE (right) - 1;
11716       while (size--) emitcode ("lcall","__decdptr");
11717   }
11718   popB (pushedB);
11719
11720   freeAsmop (result, NULL, ic, TRUE);
11721   freeAsmop (right, NULL, ic, TRUE);
11722 }
11723
11724 /*-----------------------------------------------------------------*/
11725 /* genPointerSet - stores the value into a pointer location        */
11726 /*-----------------------------------------------------------------*/
11727 static void
11728 genPointerSet (iCode * ic, iCode *pi)
11729 {
11730   operand *right, *result;
11731   sym_link *type, *etype;
11732   int p_type;
11733
11734   D (emitcode (";", "genPointerSet"));
11735
11736   right = IC_RIGHT (ic);
11737   result = IC_RESULT (ic);
11738
11739   /* depending on the type of pointer we need to
11740      move it to the correct pointer register */
11741   type = operandType (result);
11742   etype = getSpec (type);
11743   /* if left is of type of pointer then it is simple */
11744   if (IS_PTR (type) && !IS_FUNC (type->next))
11745     {
11746       p_type = DCL_TYPE (type);
11747     }
11748   else
11749     {
11750       /* we have to go by the storage class */
11751       p_type = PTR_TYPE (SPEC_OCLS (etype));
11752     }
11753
11754   /* special case when cast remat */
11755   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11756       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11757           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11758           type = operandType (result);
11759           p_type = DCL_TYPE (type);
11760   }
11761
11762   /* now that we have the pointer type we assign
11763      the pointer values */
11764   switch (p_type)
11765     {
11766
11767     case POINTER:
11768     case IPOINTER:
11769       genNearPointerSet (right, result, ic, pi);
11770       break;
11771
11772     case PPOINTER:
11773       genPagedPointerSet (right, result, ic, pi);
11774       break;
11775
11776     case FPOINTER:
11777       genFarPointerSet (right, result, ic, pi);
11778       break;
11779
11780     case GPOINTER:
11781       genGenPointerSet (right, result, ic, pi);
11782       break;
11783
11784     default:
11785       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11786               "genPointerSet: illegal pointer type");
11787     }
11788 }
11789
11790 /*-----------------------------------------------------------------*/
11791 /* genIfx - generate code for Ifx statement                        */
11792 /*-----------------------------------------------------------------*/
11793 static void
11794 genIfx (iCode * ic, iCode * popIc)
11795 {
11796   operand *cond = IC_COND (ic);
11797   int isbit = 0;
11798   char *dup = NULL;
11799
11800   D (emitcode (";", "genIfx"));
11801
11802   aopOp (cond, ic, FALSE, FALSE);
11803
11804   /* get the value into acc */
11805   if (AOP_TYPE (cond) != AOP_CRY)
11806     {
11807       toBoolean (cond);
11808     }
11809   else
11810     {
11811       isbit = 1;
11812       if (AOP(cond)->aopu.aop_dir)
11813         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11814     }
11815
11816   /* the result is now in the accumulator or a directly addressable bit */
11817   freeAsmop (cond, NULL, ic, TRUE);
11818
11819   /* if there was something to be popped then do it */
11820   if (popIc)
11821     genIpop (popIc);
11822
11823   /* if the condition is a bit variable */
11824   if (isbit && dup)
11825     genIfxJump (ic, dup);
11826   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11827     genIfxJump (ic, SPIL_LOC (cond)->rname);
11828   else if (isbit && !IS_ITEMP (cond))
11829     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11830   else
11831     genIfxJump (ic, "a");
11832
11833   ic->generated = 1;
11834 }
11835
11836 /*-----------------------------------------------------------------*/
11837 /* genAddrOf - generates code for address of                       */
11838 /*-----------------------------------------------------------------*/
11839 static void
11840 genAddrOf (iCode * ic)
11841 {
11842   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11843   int size, offset;
11844
11845   D (emitcode (";", "genAddrOf"));
11846
11847   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11848
11849   /* if the operand is on the stack then we
11850      need to get the stack offset of this
11851      variable */
11852   if (sym->onStack)
11853   {
11854
11855       /* if 10 bit stack */
11856       if (options.stack10bit) {
11857           char buff[10];
11858           int  offset;
11859
11860           tsprintf(buff, sizeof(buff),
11861                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11862           /* if it has an offset then we need to compute it */
11863 /*        emitcode ("subb", "a,#!constbyte", */
11864 /*                  -((sym->stack < 0) ? */
11865 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11866 /*                    ((short) sym->stack)) & 0xff); */
11867 /*        emitcode ("mov","b,a"); */
11868 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11869 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11870 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11871           if (sym->stack) {
11872               emitcode ("mov", "a,_bpx");
11873               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11874                                              ((char) (sym->stack - _G.nRegsSaved)) :
11875                                              ((char) sym->stack )) & 0xff);
11876               emitcode ("mov", "b,a");
11877               emitcode ("mov", "a,_bpx+1");
11878
11879               offset = (((sym->stack < 0) ?
11880                          ((short) (sym->stack - _G.nRegsSaved)) :
11881                          ((short) sym->stack )) >> 8) & 0xff;
11882
11883               emitcode ("addc","a,#!constbyte", offset);
11884
11885               aopPut (IC_RESULT (ic), "b", 0);
11886               aopPut (IC_RESULT (ic), "a", 1);
11887               aopPut (IC_RESULT (ic), buff, 2);
11888           } else {
11889               /* we can just move _bp */
11890               aopPut (IC_RESULT (ic), "_bpx", 0);
11891               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11892               aopPut (IC_RESULT (ic), buff, 2);
11893           }
11894       } else {
11895           /* if it has an offset then we need to compute it */
11896           if (sym->stack)
11897             {
11898               emitcode ("mov", "a,_bp");
11899               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11900               aopPut (IC_RESULT (ic), "a", 0);
11901             }
11902           else
11903             {
11904               /* we can just move _bp */
11905               aopPut (IC_RESULT (ic), "_bp", 0);
11906             }
11907           /* fill the result with zero */
11908           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11909
11910
11911           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11912               fprintf (stderr,
11913                        "*** warning: pointer to stack var truncated.\n");
11914           }
11915
11916           offset = 1;
11917           while (size--)
11918             {
11919               aopPut (IC_RESULT (ic), zero, offset++);
11920             }
11921       }
11922       goto release;
11923   }
11924
11925   /* object not on stack then we need the name */
11926   size = AOP_SIZE (IC_RESULT (ic));
11927   offset = 0;
11928
11929   while (size--)
11930     {
11931       char s[SDCC_NAME_MAX];
11932       if (offset) {
11933           switch (offset) {
11934           case 1:
11935               tsprintf(s, sizeof(s), "#!his",sym->rname);
11936               break;
11937           case 2:
11938               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11939               break;
11940           case 3:
11941               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11942               break;
11943           default: /* should not need this (just in case) */
11944               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11945                        sym->rname,
11946                        offset * 8);
11947           }
11948       }
11949       else
11950       {
11951           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11952       }
11953
11954       aopPut (IC_RESULT (ic), s, offset++);
11955     }
11956
11957 release:
11958   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11959
11960 }
11961
11962 #if 0 // obsolete, and buggy for != xdata
11963 /*-----------------------------------------------------------------*/
11964 /* genArrayInit - generates code for address of                       */
11965 /*-----------------------------------------------------------------*/
11966 static void
11967 genArrayInit (iCode * ic)
11968 {
11969     literalList *iLoop;
11970     int         ix, count;
11971     int         elementSize = 0, eIndex;
11972     unsigned    val, lastVal;
11973     sym_link    *type;
11974     operand     *left=IC_LEFT(ic);
11975
11976     D (emitcode (";", "genArrayInit"));
11977
11978     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11979
11980     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11981     {
11982         // Load immediate value into DPTR.
11983         emitcode("mov", "dptr, %s",
11984              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11985     }
11986     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11987     {
11988 #if 0
11989       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11990               "Unexpected operand to genArrayInit.\n");
11991       exit(1);
11992 #else
11993       // a regression because of SDCCcse.c:1.52
11994       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11995       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11996       if (options.model == MODEL_FLAT24)
11997         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11998 #endif
11999     }
12000
12001     type = operandType(IC_LEFT(ic));
12002
12003     if (type && type->next)
12004     {
12005         elementSize = getSize(type->next);
12006     }
12007     else
12008     {
12009         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12010                                 "can't determine element size in genArrayInit.\n");
12011         exit(1);
12012     }
12013
12014     iLoop = IC_ARRAYILIST(ic);
12015     lastVal = 0xffff;
12016
12017     while (iLoop)
12018     {
12019         bool firstpass = TRUE;
12020
12021         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12022                  iLoop->count, (int)iLoop->literalValue, elementSize);
12023
12024         ix = iLoop->count;
12025
12026         while (ix)
12027         {
12028             symbol *tlbl = NULL;
12029
12030             count = ix > 256 ? 256 : ix;
12031
12032             if (count > 1)
12033             {
12034                 tlbl = newiTempLabel (NULL);
12035                 if (firstpass || (count & 0xff))
12036                 {
12037                     emitcode("mov", "b, #!constbyte", count & 0xff);
12038                 }
12039
12040                 emitLabel (tlbl);
12041             }
12042
12043             firstpass = FALSE;
12044
12045             for (eIndex = 0; eIndex < elementSize; eIndex++)
12046             {
12047                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12048                 if (val != lastVal)
12049                 {
12050                     emitcode("mov", "a, #!constbyte", val);
12051                     lastVal = val;
12052                 }
12053
12054                 emitcode("movx", "@dptr, a");
12055                 emitcode("inc", "dptr");
12056             }
12057
12058             if (count > 1)
12059             {
12060                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12061             }
12062
12063             ix -= count;
12064         }
12065
12066         iLoop = iLoop->next;
12067     }
12068
12069     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12070 }
12071 #endif
12072
12073 /*-----------------------------------------------------------------*/
12074 /* genFarFarAssign - assignment when both are in far space         */
12075 /*-----------------------------------------------------------------*/
12076 static void
12077 genFarFarAssign (operand * result, operand * right, iCode * ic)
12078 {
12079   int size = AOP_SIZE (right);
12080   int offset = 0;
12081   symbol *rSym = NULL;
12082
12083   if (size == 1)
12084   {
12085       /* quick & easy case. */
12086       D (emitcode(";","genFarFarAssign (1 byte case)"));
12087       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12088       freeAsmop (right, NULL, ic, FALSE);
12089       /* now assign DPTR to result */
12090       _G.accInUse++;
12091       aopOp(result, ic, FALSE, FALSE);
12092       _G.accInUse--;
12093       aopPut (result, "a", 0);
12094       freeAsmop(result, NULL, ic, FALSE);
12095       return;
12096   }
12097
12098   /* See if we've got an underlying symbol to abuse. */
12099   if (IS_SYMOP(result) && OP_SYMBOL(result))
12100   {
12101       if (IS_TRUE_SYMOP(result))
12102       {
12103           rSym = OP_SYMBOL(result);
12104       }
12105       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12106       {
12107           rSym = OP_SYMBOL(result)->usl.spillLoc;
12108       }
12109   }
12110
12111   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12112   {
12113       /* We can use the '390 auto-toggle feature to good effect here. */
12114
12115       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12116       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12117       emitcode ("mov", "dptr,#%s", rSym->rname);
12118       /* DP2 = result, DP1 = right, DP1 is current. */
12119       while (size)
12120       {
12121           emitcode("movx", "a,@dptr");
12122           emitcode("movx", "@dptr,a");
12123           if (--size)
12124           {
12125                emitcode("inc", "dptr");
12126                emitcode("inc", "dptr");
12127           }
12128       }
12129       emitcode("mov", "dps,#0");
12130       freeAsmop (right, NULL, ic, FALSE);
12131 #if 0
12132 some alternative code for processors without auto-toggle
12133 no time to test now, so later well put in...kpb
12134         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12135         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12136         emitcode ("mov", "dptr,#%s", rSym->rname);
12137         /* DP2 = result, DP1 = right, DP1 is current. */
12138         while (size)
12139         {
12140           --size;
12141           emitcode("movx", "a,@dptr");
12142           if (size)
12143             emitcode("inc", "dptr");
12144           emitcode("inc", "dps");
12145           emitcode("movx", "@dptr,a");
12146           if (size)
12147             emitcode("inc", "dptr");
12148           emitcode("inc", "dps");
12149         }
12150         emitcode("mov", "dps,#0");
12151         freeAsmop (right, NULL, ic, FALSE);
12152 #endif
12153   }
12154   else
12155   {
12156       D (emitcode (";", "genFarFarAssign"));
12157       aopOp (result, ic, TRUE, TRUE);
12158
12159       _startLazyDPSEvaluation ();
12160
12161       while (size--)
12162         {
12163           aopPut (result,
12164                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12165           offset++;
12166         }
12167       _endLazyDPSEvaluation ();
12168       freeAsmop (result, NULL, ic, FALSE);
12169       freeAsmop (right, NULL, ic, FALSE);
12170   }
12171 }
12172
12173 /*-----------------------------------------------------------------*/
12174 /* genAssign - generate code for assignment                        */
12175 /*-----------------------------------------------------------------*/
12176 static void
12177 genAssign (iCode * ic)
12178 {
12179   operand *result, *right;
12180   int size, offset;
12181   unsigned long lit = 0L;
12182
12183   D (emitcode (";", "genAssign"));
12184
12185   result = IC_RESULT (ic);
12186   right = IC_RIGHT (ic);
12187
12188   /* if they are the same */
12189   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12190     return;
12191
12192   aopOp (right, ic, FALSE, FALSE);
12193
12194   emitcode (";", "genAssign: resultIsFar = %s",
12195             isOperandInFarSpace (result) ?
12196             "TRUE" : "FALSE");
12197
12198   /* special case both in far space */
12199   if ((AOP_TYPE (right) == AOP_DPTR ||
12200        AOP_TYPE (right) == AOP_DPTR2) &&
12201   /* IS_TRUE_SYMOP(result)       && */
12202       isOperandInFarSpace (result))
12203     {
12204       genFarFarAssign (result, right, ic);
12205       return;
12206     }
12207
12208   aopOp (result, ic, TRUE, FALSE);
12209
12210   /* if they are the same registers */
12211   if (sameRegs (AOP (right), AOP (result)))
12212     goto release;
12213
12214   /* if the result is a bit */
12215   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12216     {
12217       /* if the right size is a literal then
12218          we know what the value is */
12219       if (AOP_TYPE (right) == AOP_LIT)
12220         {
12221           if (((int) operandLitValue (right)))
12222             aopPut (result, one, 0);
12223           else
12224             aopPut (result, zero, 0);
12225           goto release;
12226         }
12227
12228       /* the right is also a bit variable */
12229       if (AOP_TYPE (right) == AOP_CRY)
12230         {
12231           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12232           aopPut (result, "c", 0);
12233           goto release;
12234         }
12235
12236       /* we need to or */
12237       toBoolean (right);
12238       aopPut (result, "a", 0);
12239       goto release;
12240     }
12241
12242   /* bit variables done */
12243   /* general case */
12244   size = AOP_SIZE (result);
12245   offset = 0;
12246   if (AOP_TYPE (right) == AOP_LIT)
12247     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12248
12249   if ((size > 1) &&
12250       (AOP_TYPE (result) != AOP_REG) &&
12251       (AOP_TYPE (right) == AOP_LIT) &&
12252       !IS_FLOAT (operandType (right)))
12253     {
12254       _startLazyDPSEvaluation ();
12255       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12256         {
12257           aopPut (result,
12258                   aopGet (right, offset, FALSE, FALSE, NULL),
12259                   offset);
12260           offset++;
12261           size--;
12262         }
12263       /* And now fill the rest with zeros. */
12264       if (size)
12265         {
12266           emitcode ("clr", "a");
12267         }
12268       while (size--)
12269         {
12270           aopPut (result, "a", offset++);
12271         }
12272       _endLazyDPSEvaluation ();
12273     }
12274   else
12275     {
12276       _startLazyDPSEvaluation ();
12277       while (size--)
12278         {
12279           aopPut (result,
12280                   aopGet (right, offset, FALSE, FALSE, NULL),
12281                   offset);
12282           offset++;
12283         }
12284       _endLazyDPSEvaluation ();
12285     }
12286
12287 release:
12288   freeAsmop (result, NULL, ic, TRUE);
12289   freeAsmop (right, NULL, ic, TRUE);
12290 }
12291
12292 /*-----------------------------------------------------------------*/
12293 /* genJumpTab - generates code for jump table                      */
12294 /*-----------------------------------------------------------------*/
12295 static void
12296 genJumpTab (iCode * ic)
12297 {
12298   symbol *jtab;
12299   char *l;
12300
12301   D (emitcode (";", "genJumpTab"));
12302
12303   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12304   /* get the condition into accumulator */
12305   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12306   MOVA (l);
12307   /* multiply by four! */
12308   emitcode ("add", "a,acc");
12309   emitcode ("add", "a,acc");
12310   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12311
12312   jtab = newiTempLabel (NULL);
12313   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12314   emitcode ("jmp", "@a+dptr");
12315   emitLabel (jtab);
12316   /* now generate the jump labels */
12317   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12318        jtab = setNextItem (IC_JTLABELS (ic)))
12319     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12320
12321 }
12322
12323 /*-----------------------------------------------------------------*/
12324 /* genCast - gen code for casting                                  */
12325 /*-----------------------------------------------------------------*/
12326 static void
12327 genCast (iCode * ic)
12328 {
12329   operand *result = IC_RESULT (ic);
12330   sym_link *ctype = operandType (IC_LEFT (ic));
12331   sym_link *rtype = operandType (IC_RIGHT (ic));
12332   operand *right = IC_RIGHT (ic);
12333   int size, offset;
12334
12335   D (emitcode (";", "genCast"));
12336
12337   /* if they are equivalent then do nothing */
12338   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12339     return;
12340
12341   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12342   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12343
12344   /* if the result is a bit (and not a bitfield) */
12345   if (IS_BIT (OP_SYMBOL (result)->type))
12346     {
12347       /* if the right size is a literal then
12348          we know what the value is */
12349       if (AOP_TYPE (right) == AOP_LIT)
12350         {
12351           if (((int) operandLitValue (right)))
12352             aopPut (result, one, 0);
12353           else
12354             aopPut (result, zero, 0);
12355
12356           goto release;
12357         }
12358
12359       /* the right is also a bit variable */
12360       if (AOP_TYPE (right) == AOP_CRY)
12361         {
12362           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12363           aopPut (result, "c", 0);
12364           goto release;
12365         }
12366
12367       /* we need to or */
12368       toBoolean (right);
12369       aopPut (result, "a", 0);
12370       goto release;
12371     }
12372
12373   /* if they are the same size : or less */
12374   if (AOP_SIZE (result) <= AOP_SIZE (right))
12375     {
12376
12377       /* if they are in the same place */
12378       if (sameRegs (AOP (right), AOP (result)))
12379         goto release;
12380
12381       /* if they in different places then copy */
12382       size = AOP_SIZE (result);
12383       offset = 0;
12384       _startLazyDPSEvaluation ();
12385       while (size--)
12386         {
12387           aopPut (result,
12388                   aopGet (right, offset, FALSE, FALSE, NULL),
12389                   offset);
12390           offset++;
12391         }
12392       _endLazyDPSEvaluation ();
12393       goto release;
12394     }
12395
12396   /* if the result is of type pointer */
12397   if (IS_PTR (ctype))
12398     {
12399
12400       int p_type;
12401       sym_link *type = operandType (right);
12402
12403       /* pointer to generic pointer */
12404       if (IS_GENPTR (ctype))
12405         {
12406           if (IS_PTR (type))
12407             {
12408               p_type = DCL_TYPE (type);
12409             }
12410           else
12411             {
12412 #if OLD_CAST_BEHAVIOR
12413               /* KV: we are converting a non-pointer type to
12414                * a generic pointer. This (ifdef'd out) code
12415                * says that the resulting generic pointer
12416                * should have the same class as the storage
12417                * location of the non-pointer variable.
12418                *
12419                * For example, converting an int (which happens
12420                * to be stored in DATA space) to a pointer results
12421                * in a DATA generic pointer; if the original int
12422                * in XDATA space, so will be the resulting pointer.
12423                *
12424                * I don't like that behavior, and thus this change:
12425                * all such conversions will be forced to XDATA and
12426                * throw a warning. If you want some non-XDATA
12427                * type, or you want to suppress the warning, you
12428                * must go through an intermediate cast, like so:
12429                *
12430                * char _generic *gp = (char _xdata *)(intVar);
12431                */
12432               sym_link *etype = getSpec (type);
12433
12434               /* we have to go by the storage class */
12435               if (SPEC_OCLS (etype) != generic)
12436                 {
12437                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12438                 }
12439               else
12440 #endif
12441                 {
12442                   /* Converting unknown class (i.e. register variable)
12443                    * to generic pointer. This is not good, but
12444                    * we'll make a guess (and throw a warning).
12445                    */
12446                   p_type = FPOINTER;
12447                   werror (W_INT_TO_GEN_PTR_CAST);
12448                 }
12449             }
12450
12451           /* the first two bytes are known */
12452           size = GPTRSIZE - 1;
12453           offset = 0;
12454           _startLazyDPSEvaluation ();
12455           while (size--)
12456             {
12457               aopPut (result,
12458                       aopGet (right, offset, FALSE, FALSE, NULL),
12459                       offset);
12460               offset++;
12461             }
12462           _endLazyDPSEvaluation ();
12463
12464           /* the last byte depending on type */
12465             {
12466                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12467                 char gpValStr[10];
12468
12469                 if (gpVal == -1)
12470                 {
12471                     // pointerTypeToGPByte will have bitched.
12472                     exit(1);
12473                 }
12474
12475                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12476                 aopPut (result, gpValStr, GPTRSIZE - 1);
12477             }
12478           goto release;
12479         }
12480
12481       /* just copy the pointers */
12482       size = AOP_SIZE (result);
12483       offset = 0;
12484       _startLazyDPSEvaluation ();
12485       while (size--)
12486         {
12487           aopPut (result,
12488                   aopGet (right, offset, FALSE, FALSE, NULL),
12489                   offset);
12490           offset++;
12491         }
12492       _endLazyDPSEvaluation ();
12493       goto release;
12494     }
12495
12496   /* so we now know that the size of destination is greater
12497      than the size of the source */
12498   /* we move to result for the size of source */
12499   size = AOP_SIZE (right);
12500   offset = 0;
12501   _startLazyDPSEvaluation ();
12502   while (size--)
12503     {
12504       aopPut (result,
12505               aopGet (right, offset, FALSE, FALSE, NULL),
12506               offset);
12507       offset++;
12508     }
12509   _endLazyDPSEvaluation ();
12510
12511   /* now depending on the sign of the source && destination */
12512   size = AOP_SIZE (result) - AOP_SIZE (right);
12513   /* if unsigned or not an integral type */
12514   /* also, if the source is a bit, we don't need to sign extend, because
12515    * it can't possibly have set the sign bit.
12516    */
12517   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12518     {
12519       while (size--)
12520         {
12521           aopPut (result, zero, offset++);
12522         }
12523     }
12524   else
12525     {
12526       /* we need to extend the sign :{ */
12527       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12528                         FALSE, FALSE, NULL));
12529       emitcode ("rlc", "a");
12530       emitcode ("subb", "a,acc");
12531       while (size--)
12532         aopPut (result, "a", offset++);
12533     }
12534
12535   /* we are done hurray !!!! */
12536
12537 release:
12538   freeAsmop (right, NULL, ic, TRUE);
12539   freeAsmop (result, NULL, ic, TRUE);
12540
12541 }
12542
12543 /*-----------------------------------------------------------------*/
12544 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12545 /*-----------------------------------------------------------------*/
12546 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12547 {
12548     operand *from , *to , *count;
12549     symbol *lbl;
12550     bitVect *rsave;
12551     int i;
12552
12553     /* we know it has to be 3 parameters */
12554     assert (nparms == 3);
12555
12556     rsave = newBitVect(16);
12557     /* save DPTR if it needs to be saved */
12558     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12559             if (bitVectBitValue(ic->rMask,i))
12560                     rsave = bitVectSetBit(rsave,i);
12561     }
12562     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12563                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12564     savermask(rsave);
12565
12566     to = parms[0];
12567     from = parms[1];
12568     count = parms[2];
12569
12570     aopOp (from, ic->next, FALSE, FALSE);
12571
12572     /* get from into DPTR1 */
12573     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12574     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12575     if (options.model == MODEL_FLAT24) {
12576         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12577     }
12578
12579     freeAsmop (from, NULL, ic, FALSE);
12580     aopOp (to, ic, FALSE, FALSE);
12581     /* get "to" into DPTR */
12582     /* if the operand is already in dptr
12583        then we do nothing else we move the value to dptr */
12584     if (AOP_TYPE (to) != AOP_STR) {
12585         /* if already in DPTR then we need to push */
12586         if (AOP_TYPE(to) == AOP_DPTR) {
12587             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12588             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12589             if (options.model == MODEL_FLAT24)
12590                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12591             emitcode ("pop", "dph");
12592             emitcode ("pop", "dpl");
12593         } else {
12594             _startLazyDPSEvaluation ();
12595             /* if this is remateriazable */
12596             if (AOP_TYPE (to) == AOP_IMMD) {
12597                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12598             } else {                    /* we need to get it byte by byte */
12599                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12600                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12601                 if (options.model == MODEL_FLAT24) {
12602                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12603                 }
12604             }
12605             _endLazyDPSEvaluation ();
12606         }
12607     }
12608     freeAsmop (to, NULL, ic, FALSE);
12609     _G.dptrInUse = _G.dptr1InUse = 1;
12610     aopOp (count, ic->next->next, FALSE,FALSE);
12611     lbl =newiTempLabel(NULL);
12612
12613     /* now for the actual copy */
12614     if (AOP_TYPE(count) == AOP_LIT &&
12615         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12616         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12617         if (fromc) {
12618             emitcode ("lcall","__bi_memcpyc2x_s");
12619         } else {
12620             emitcode ("lcall","__bi_memcpyx2x_s");
12621         }
12622         freeAsmop (count, NULL, ic, FALSE);
12623     } else {
12624         symbol *lbl1 = newiTempLabel(NULL);
12625
12626         emitcode (";"," Auto increment but no djnz");
12627         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12628         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12629         freeAsmop (count, NULL, ic, FALSE);
12630         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12631         emitLabel (lbl);
12632         if (fromc) {
12633             emitcode ("clr","a");
12634             emitcode ("movc", "a,@a+dptr");
12635         } else
12636             emitcode ("movx", "a,@dptr");
12637         emitcode ("movx", "@dptr,a");
12638         emitcode ("inc", "dptr");
12639         emitcode ("inc", "dptr");
12640         emitcode ("mov","a,b");
12641         emitcode ("orl","a,_ap");
12642         emitcode ("jz","!tlabel",lbl1->key+100);
12643         emitcode ("mov","a,_ap");
12644         emitcode ("add","a,#!constbyte",0xFF);
12645         emitcode ("mov","_ap,a");
12646         emitcode ("mov","a,b");
12647         emitcode ("addc","a,#!constbyte",0xFF);
12648         emitcode ("mov","b,a");
12649         emitcode ("sjmp","!tlabel",lbl->key+100);
12650         emitLabel (lbl1);
12651     }
12652     emitcode ("mov", "dps,#0");
12653     _G.dptrInUse = _G.dptr1InUse = 0;
12654     unsavermask(rsave);
12655
12656 }
12657
12658 /*-----------------------------------------------------------------*/
12659 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12660 /*-----------------------------------------------------------------*/
12661 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12662 {
12663     operand *from , *to , *count;
12664     symbol *lbl,*lbl2;
12665     bitVect *rsave;
12666     int i;
12667
12668     /* we know it has to be 3 parameters */
12669     assert (nparms == 3);
12670
12671     rsave = newBitVect(16);
12672     /* save DPTR if it needs to be saved */
12673     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12674             if (bitVectBitValue(ic->rMask,i))
12675                     rsave = bitVectSetBit(rsave,i);
12676     }
12677     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12678                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12679     savermask(rsave);
12680
12681     to = parms[0];
12682     from = parms[1];
12683     count = parms[2];
12684
12685     aopOp (from, ic->next, FALSE, FALSE);
12686
12687     /* get from into DPTR1 */
12688     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12689     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12690     if (options.model == MODEL_FLAT24) {
12691         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12692     }
12693
12694     freeAsmop (from, NULL, ic, FALSE);
12695     aopOp (to, ic, FALSE, FALSE);
12696     /* get "to" into DPTR */
12697     /* if the operand is already in dptr
12698        then we do nothing else we move the value to dptr */
12699     if (AOP_TYPE (to) != AOP_STR) {
12700         /* if already in DPTR then we need to push */
12701         if (AOP_TYPE(to) == AOP_DPTR) {
12702             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12703             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12704             if (options.model == MODEL_FLAT24)
12705                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12706             emitcode ("pop", "dph");
12707             emitcode ("pop", "dpl");
12708         } else {
12709             _startLazyDPSEvaluation ();
12710             /* if this is remateriazable */
12711             if (AOP_TYPE (to) == AOP_IMMD) {
12712                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12713             } else {                    /* we need to get it byte by byte */
12714                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12715                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12716                 if (options.model == MODEL_FLAT24) {
12717                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12718                 }
12719             }
12720             _endLazyDPSEvaluation ();
12721         }
12722     }
12723     freeAsmop (to, NULL, ic, FALSE);
12724     _G.dptrInUse = _G.dptr1InUse = 1;
12725     aopOp (count, ic->next->next, FALSE,FALSE);
12726     lbl =newiTempLabel(NULL);
12727     lbl2 =newiTempLabel(NULL);
12728
12729     /* now for the actual compare */
12730     if (AOP_TYPE(count) == AOP_LIT &&
12731         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12732         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12733         if (fromc)
12734             emitcode("lcall","__bi_memcmpc2x_s");
12735         else
12736             emitcode("lcall","__bi_memcmpx2x_s");
12737         freeAsmop (count, NULL, ic, FALSE);
12738         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12739         aopPut(IC_RESULT(ic),"a",0);
12740         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12741     } else {
12742         symbol *lbl1 = newiTempLabel(NULL);
12743
12744         emitcode("push","ar0");
12745         emitcode (";"," Auto increment but no djnz");
12746         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12747         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12748         freeAsmop (count, NULL, ic, FALSE);
12749         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12750         emitLabel (lbl);
12751         if (fromc) {
12752             emitcode ("clr","a");
12753             emitcode ("movc", "a,@a+dptr");
12754         } else
12755             emitcode ("movx", "a,@dptr");
12756         emitcode ("mov","r0,a");
12757         emitcode ("movx", "a,@dptr");
12758         emitcode ("clr","c");
12759         emitcode ("subb","a,r0");
12760         emitcode ("jnz","!tlabel",lbl2->key+100);
12761         emitcode ("inc", "dptr");
12762         emitcode ("inc", "dptr");
12763         emitcode ("mov","a,b");
12764         emitcode ("orl","a,_ap");
12765         emitcode ("jz","!tlabel",lbl1->key+100);
12766         emitcode ("mov","a,_ap");
12767         emitcode ("add","a,#!constbyte",0xFF);
12768         emitcode ("mov","_ap,a");
12769         emitcode ("mov","a,b");
12770         emitcode ("addc","a,#!constbyte",0xFF);
12771         emitcode ("mov","b,a");
12772         emitcode ("sjmp","!tlabel",lbl->key+100);
12773         emitLabel (lbl1);
12774         emitcode ("clr","a");
12775         emitLabel (lbl2);
12776         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12777         aopPut(IC_RESULT(ic),"a",0);
12778         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12779         emitcode("pop","ar0");
12780         emitcode ("mov", "dps,#0");
12781     }
12782     _G.dptrInUse = _G.dptr1InUse = 0;
12783     unsavermask(rsave);
12784
12785 }
12786
12787 /*-----------------------------------------------------------------*/
12788 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12789 /* port, first parameter output area second parameter pointer to   */
12790 /* port third parameter count                                      */
12791 /*-----------------------------------------------------------------*/
12792 static void genInp( iCode *ic, int nparms, operand **parms)
12793 {
12794     operand *from , *to , *count;
12795     symbol *lbl;
12796     bitVect *rsave;
12797     int i;
12798
12799     /* we know it has to be 3 parameters */
12800     assert (nparms == 3);
12801
12802     rsave = newBitVect(16);
12803     /* save DPTR if it needs to be saved */
12804     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12805             if (bitVectBitValue(ic->rMask,i))
12806                     rsave = bitVectSetBit(rsave,i);
12807     }
12808     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12809                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12810     savermask(rsave);
12811
12812     to = parms[0];
12813     from = parms[1];
12814     count = parms[2];
12815
12816     aopOp (from, ic->next, FALSE, FALSE);
12817
12818     /* get from into DPTR1 */
12819     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12820     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12821     if (options.model == MODEL_FLAT24) {
12822         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12823     }
12824
12825     freeAsmop (from, NULL, ic, FALSE);
12826     aopOp (to, ic, FALSE, FALSE);
12827     /* get "to" into DPTR */
12828     /* if the operand is already in dptr
12829        then we do nothing else we move the value to dptr */
12830     if (AOP_TYPE (to) != AOP_STR) {
12831         /* if already in DPTR then we need to push */
12832         if (AOP_TYPE(to) == AOP_DPTR) {
12833             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12834             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12835             if (options.model == MODEL_FLAT24)
12836                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12837             emitcode ("pop", "dph");
12838             emitcode ("pop", "dpl");
12839         } else {
12840             _startLazyDPSEvaluation ();
12841             /* if this is remateriazable */
12842             if (AOP_TYPE (to) == AOP_IMMD) {
12843                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12844             } else {                    /* we need to get it byte by byte */
12845                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12846                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12847                 if (options.model == MODEL_FLAT24) {
12848                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12849                 }
12850             }
12851             _endLazyDPSEvaluation ();
12852         }
12853     }
12854     freeAsmop (to, NULL, ic, FALSE);
12855
12856     _G.dptrInUse = _G.dptr1InUse = 1;
12857     aopOp (count, ic->next->next, FALSE,FALSE);
12858     lbl =newiTempLabel(NULL);
12859
12860     /* now for the actual copy */
12861     if (AOP_TYPE(count) == AOP_LIT &&
12862         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12863         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12864         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12865         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12866         freeAsmop (count, NULL, ic, FALSE);
12867         emitLabel (lbl);
12868         emitcode ("movx", "a,@dptr");   /* read data from port */
12869         emitcode ("dec","dps");         /* switch to DPTR */
12870         emitcode ("movx", "@dptr,a");   /* save into location */
12871         emitcode ("inc", "dptr");       /* point to next area */
12872         emitcode ("inc","dps");         /* switch to DPTR2 */
12873         emitcode ("djnz","b,!tlabel",lbl->key+100);
12874     } else {
12875         symbol *lbl1 = newiTempLabel(NULL);
12876
12877         emitcode (";"," Auto increment but no djnz");
12878         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12879         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12880         freeAsmop (count, NULL, ic, FALSE);
12881         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12882         emitLabel (lbl);
12883         emitcode ("movx", "a,@dptr");
12884         emitcode ("dec","dps");         /* switch to DPTR */
12885         emitcode ("movx", "@dptr,a");
12886         emitcode ("inc", "dptr");
12887         emitcode ("inc","dps");         /* switch to DPTR2 */
12888 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12889 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12890         emitcode ("mov","a,b");
12891         emitcode ("orl","a,_ap");
12892         emitcode ("jz","!tlabel",lbl1->key+100);
12893         emitcode ("mov","a,_ap");
12894         emitcode ("add","a,#!constbyte",0xFF);
12895         emitcode ("mov","_ap,a");
12896         emitcode ("mov","a,b");
12897         emitcode ("addc","a,#!constbyte",0xFF);
12898         emitcode ("mov","b,a");
12899         emitcode ("sjmp","!tlabel",lbl->key+100);
12900         emitLabel (lbl1);
12901     }
12902     emitcode ("mov", "dps,#0");
12903     _G.dptrInUse = _G.dptr1InUse = 0;
12904     unsavermask(rsave);
12905
12906 }
12907
12908 /*-----------------------------------------------------------------*/
12909 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12910 /* port, first parameter output area second parameter pointer to   */
12911 /* port third parameter count                                      */
12912 /*-----------------------------------------------------------------*/
12913 static void genOutp( iCode *ic, int nparms, operand **parms)
12914 {
12915     operand *from , *to , *count;
12916     symbol *lbl;
12917     bitVect *rsave;
12918     int i;
12919
12920     /* we know it has to be 3 parameters */
12921     assert (nparms == 3);
12922
12923     rsave = newBitVect(16);
12924     /* save DPTR if it needs to be saved */
12925     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12926             if (bitVectBitValue(ic->rMask,i))
12927                     rsave = bitVectSetBit(rsave,i);
12928     }
12929     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12930                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12931     savermask(rsave);
12932
12933     to = parms[0];
12934     from = parms[1];
12935     count = parms[2];
12936
12937     aopOp (from, ic->next, FALSE, FALSE);
12938
12939     /* get from into DPTR1 */
12940     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12941     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12942     if (options.model == MODEL_FLAT24) {
12943         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12944     }
12945
12946     freeAsmop (from, NULL, ic, FALSE);
12947     aopOp (to, ic, FALSE, FALSE);
12948     /* get "to" into DPTR */
12949     /* if the operand is already in dptr
12950        then we do nothing else we move the value to dptr */
12951     if (AOP_TYPE (to) != AOP_STR) {
12952         /* if already in DPTR then we need to push */
12953         if (AOP_TYPE(to) == AOP_DPTR) {
12954             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12955             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12956             if (options.model == MODEL_FLAT24)
12957                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12958             emitcode ("pop", "dph");
12959             emitcode ("pop", "dpl");
12960         } else {
12961             _startLazyDPSEvaluation ();
12962             /* if this is remateriazable */
12963             if (AOP_TYPE (to) == AOP_IMMD) {
12964                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12965             } else {                    /* we need to get it byte by byte */
12966                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12967                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12968                 if (options.model == MODEL_FLAT24) {
12969                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12970                 }
12971             }
12972             _endLazyDPSEvaluation ();
12973         }
12974     }
12975     freeAsmop (to, NULL, ic, FALSE);
12976
12977     _G.dptrInUse = _G.dptr1InUse = 1;
12978     aopOp (count, ic->next->next, FALSE,FALSE);
12979     lbl =newiTempLabel(NULL);
12980
12981     /* now for the actual copy */
12982     if (AOP_TYPE(count) == AOP_LIT &&
12983         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12984         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12985         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12986         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12987         emitLabel (lbl);
12988         emitcode ("movx", "a,@dptr");   /* read data from port */
12989         emitcode ("inc","dps");         /* switch to DPTR2 */
12990         emitcode ("movx", "@dptr,a");   /* save into location */
12991         emitcode ("inc", "dptr");       /* point to next area */
12992         emitcode ("dec","dps");         /* switch to DPTR */
12993         emitcode ("djnz","b,!tlabel",lbl->key+100);
12994         freeAsmop (count, NULL, ic, FALSE);
12995     } else {
12996         symbol *lbl1 = newiTempLabel(NULL);
12997
12998         emitcode (";"," Auto increment but no djnz");
12999         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13000         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13001         freeAsmop (count, NULL, ic, FALSE);
13002         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13003         emitLabel (lbl);
13004         emitcode ("movx", "a,@dptr");
13005         emitcode ("inc", "dptr");
13006         emitcode ("inc","dps");         /* switch to DPTR2 */
13007         emitcode ("movx", "@dptr,a");
13008         emitcode ("dec","dps");         /* switch to DPTR */
13009         emitcode ("mov","a,b");
13010         emitcode ("orl","a,_ap");
13011         emitcode ("jz","!tlabel",lbl1->key+100);
13012         emitcode ("mov","a,_ap");
13013         emitcode ("add","a,#!constbyte",0xFF);
13014         emitcode ("mov","_ap,a");
13015         emitcode ("mov","a,b");
13016         emitcode ("addc","a,#!constbyte",0xFF);
13017         emitcode ("mov","b,a");
13018         emitcode ("sjmp","!tlabel",lbl->key+100);
13019         emitLabel (lbl1);
13020     }
13021     emitcode ("mov", "dps,#0");
13022     _G.dptrInUse = _G.dptr1InUse = 0;
13023     unsavermask(rsave);
13024
13025 }
13026
13027 /*-----------------------------------------------------------------*/
13028 /* genSwapW - swap lower & high order bytes                        */
13029 /*-----------------------------------------------------------------*/
13030 static void genSwapW(iCode *ic, int nparms, operand **parms)
13031 {
13032     operand *dest;
13033     operand *src;
13034     assert (nparms==1);
13035
13036     src = parms[0];
13037     dest=IC_RESULT(ic);
13038
13039     assert(getSize(operandType(src))==2);
13040
13041     aopOp (src, ic, FALSE, FALSE);
13042     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13043     _G.accInUse++;
13044     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13045     _G.accInUse--;
13046     freeAsmop (src, NULL, ic, FALSE);
13047
13048     aopOp (dest,ic, FALSE, FALSE);
13049     aopPut(dest,"b",0);
13050     aopPut(dest,"a",1);
13051     freeAsmop (dest, NULL, ic, FALSE);
13052 }
13053
13054 /*-----------------------------------------------------------------*/
13055 /* genMemsetX - gencode for memSetX data                           */
13056 /*-----------------------------------------------------------------*/
13057 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13058 {
13059     operand *to , *val , *count;
13060     symbol *lbl;
13061     char *l;
13062     int i;
13063     bitVect *rsave;
13064
13065     /* we know it has to be 3 parameters */
13066     assert (nparms == 3);
13067
13068     to = parms[0];
13069     val = parms[1];
13070     count = parms[2];
13071
13072     /* save DPTR if it needs to be saved */
13073     rsave = newBitVect(16);
13074     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13075             if (bitVectBitValue(ic->rMask,i))
13076                     rsave = bitVectSetBit(rsave,i);
13077     }
13078     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13079                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13080     savermask(rsave);
13081
13082     aopOp (to, ic, FALSE, FALSE);
13083     /* get "to" into DPTR */
13084     /* if the operand is already in dptr
13085        then we do nothing else we move the value to dptr */
13086     if (AOP_TYPE (to) != AOP_STR) {
13087         /* if already in DPTR then we need to push */
13088         if (AOP_TYPE(to) == AOP_DPTR) {
13089             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13090             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13091             if (options.model == MODEL_FLAT24)
13092                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13093             emitcode ("pop", "dph");
13094             emitcode ("pop", "dpl");
13095         } else {
13096             _startLazyDPSEvaluation ();
13097             /* if this is remateriazable */
13098             if (AOP_TYPE (to) == AOP_IMMD) {
13099                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13100             } else {                    /* we need to get it byte by byte */
13101                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13102                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13103                 if (options.model == MODEL_FLAT24) {
13104                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13105                 }
13106             }
13107             _endLazyDPSEvaluation ();
13108         }
13109     }
13110     freeAsmop (to, NULL, ic, FALSE);
13111
13112     aopOp (val, ic->next->next, FALSE,FALSE);
13113     aopOp (count, ic->next->next, FALSE,FALSE);
13114     lbl =newiTempLabel(NULL);
13115     /* now for the actual copy */
13116     if (AOP_TYPE(count) == AOP_LIT &&
13117         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13118         l = aopGet(val, 0, FALSE, FALSE, NULL);
13119         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13120         MOVA(l);
13121         emitLabel (lbl);
13122         emitcode ("movx", "@dptr,a");
13123         emitcode ("inc", "dptr");
13124         emitcode ("djnz","b,!tlabel",lbl->key+100);
13125     } else {
13126         symbol *lbl1 = newiTempLabel(NULL);
13127
13128         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13129         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13130         emitLabel (lbl);
13131         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13132         emitcode ("movx", "@dptr,a");
13133         emitcode ("inc", "dptr");
13134         emitcode ("mov","a,b");
13135         emitcode ("orl","a,_ap");
13136         emitcode ("jz","!tlabel",lbl1->key+100);
13137         emitcode ("mov","a,_ap");
13138         emitcode ("add","a,#!constbyte",0xFF);
13139         emitcode ("mov","_ap,a");
13140         emitcode ("mov","a,b");
13141         emitcode ("addc","a,#!constbyte",0xFF);
13142         emitcode ("mov","b,a");
13143         emitcode ("sjmp","!tlabel",lbl->key+100);
13144         emitLabel (lbl1);
13145     }
13146     freeAsmop (count, NULL, ic, FALSE);
13147     unsavermask(rsave);
13148 }
13149
13150 /*-----------------------------------------------------------------*/
13151 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13152 /*-----------------------------------------------------------------*/
13153 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13154 {
13155         bitVect *rsave ;
13156         operand *pnum, *result;
13157         int i;
13158
13159         assert (nparms==1);
13160         /* save registers that need to be saved */
13161         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13162                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13163
13164         pnum = parms[0];
13165         aopOp (pnum, ic, FALSE, FALSE);
13166         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13167         freeAsmop (pnum, NULL, ic, FALSE);
13168         emitcode ("lcall","NatLib_LoadPrimitive");
13169         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13170         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13171             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13172                 for (i = (size-1) ; i >= 0 ; i-- ) {
13173                         emitcode ("push","a%s",javaRet[i]);
13174                 }
13175                 for (i=0; i < size ; i++ ) {
13176                         emitcode ("pop","a%s",
13177                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13178                 }
13179         } else {
13180                 for (i = 0 ; i < size ; i++ ) {
13181                         aopPut(result,javaRet[i],i);
13182                 }
13183         }
13184         freeAsmop (result, NULL, ic, FALSE);
13185         unsavermask(rsave);
13186 }
13187
13188 /*-----------------------------------------------------------------*/
13189 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13190 /*-----------------------------------------------------------------*/
13191 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13192 {
13193         bitVect *rsave ;
13194         operand *pnum, *result;
13195         int size = 3;
13196         int i;
13197
13198         assert (nparms==1);
13199         /* save registers that need to be saved */
13200         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13201                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13202
13203         pnum = parms[0];
13204         aopOp (pnum, ic, FALSE, FALSE);
13205         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13206         freeAsmop (pnum, NULL, ic, FALSE);
13207         emitcode ("lcall","NatLib_LoadPointer");
13208         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13209         if (AOP_TYPE(result)!=AOP_STR) {
13210                 for (i = 0 ; i < size ; i++ ) {
13211                         aopPut(result,fReturn[i],i);
13212                 }
13213         }
13214         freeAsmop (result, NULL, ic, FALSE);
13215         unsavermask(rsave);
13216 }
13217
13218 /*-----------------------------------------------------------------*/
13219 /* genNatLibInstallStateBlock -                                    */
13220 /*-----------------------------------------------------------------*/
13221 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13222                                        operand **parms, const char *name)
13223 {
13224         bitVect *rsave ;
13225         operand *psb, *handle;
13226         assert (nparms==2);
13227
13228         /* save registers that need to be saved */
13229         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13230                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13231         psb = parms[0];
13232         handle = parms[1];
13233
13234         /* put pointer to state block into DPTR1 */
13235         aopOp (psb, ic, FALSE, FALSE);
13236         if (AOP_TYPE (psb) == AOP_IMMD) {
13237                 emitcode ("mov","dps,#1");
13238                 emitcode ("mov", "dptr,%s",
13239                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13240                 emitcode ("mov","dps,#0");
13241         } else {
13242                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13243                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13244                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13245         }
13246         freeAsmop (psb, NULL, ic, FALSE);
13247
13248         /* put libraryID into DPTR */
13249         emitcode ("mov","dptr,#LibraryID");
13250
13251         /* put handle into r3:r2 */
13252         aopOp (handle, ic, FALSE, FALSE);
13253         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13254                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13255                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13256                 emitcode ("pop","ar3");
13257                 emitcode ("pop","ar2");
13258         } else {
13259                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13260                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13261         }
13262         freeAsmop (psb, NULL, ic, FALSE);
13263
13264         /* make the call */
13265         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13266
13267         /* put return value into place*/
13268         _G.accInUse++;
13269         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13270         _G.accInUse--;
13271         aopPut(IC_RESULT(ic),"a",0);
13272         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13273         unsavermask(rsave);
13274 }
13275
13276 /*-----------------------------------------------------------------*/
13277 /* genNatLibRemoveStateBlock -                                     */
13278 /*-----------------------------------------------------------------*/
13279 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13280 {
13281         bitVect *rsave ;
13282
13283         assert(nparms==0);
13284
13285         /* save registers that need to be saved */
13286         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13287                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13288
13289         /* put libraryID into DPTR */
13290         emitcode ("mov","dptr,#LibraryID");
13291         /* make the call */
13292         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13293         unsavermask(rsave);
13294 }
13295
13296 /*-----------------------------------------------------------------*/
13297 /* genNatLibGetStateBlock -                                        */
13298 /*-----------------------------------------------------------------*/
13299 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13300                                    operand **parms,const char *name)
13301 {
13302         bitVect *rsave ;
13303         symbol *lbl = newiTempLabel(NULL);
13304
13305         assert(nparms==0);
13306         /* save registers that need to be saved */
13307         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13308                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13309
13310         /* put libraryID into DPTR */
13311         emitcode ("mov","dptr,#LibraryID");
13312         /* make the call */
13313         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13314         emitcode ("jnz","!tlabel",lbl->key+100);
13315
13316         /* put return value into place */
13317         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13318         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13319                 emitcode ("push","ar3");
13320                 emitcode ("push","ar2");
13321                 emitcode ("pop","%s",
13322                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13323                 emitcode ("pop","%s",
13324                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13325         } else {
13326                 aopPut(IC_RESULT(ic),"r2",0);
13327                 aopPut(IC_RESULT(ic),"r3",1);
13328         }
13329         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13330         emitLabel (lbl);
13331         unsavermask(rsave);
13332 }
13333
13334 /*-----------------------------------------------------------------*/
13335 /* genMMMalloc -                                                   */
13336 /*-----------------------------------------------------------------*/
13337 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13338                          int size, const char *name)
13339 {
13340         bitVect *rsave ;
13341         operand *bsize;
13342         symbol *rsym;
13343         symbol *lbl = newiTempLabel(NULL);
13344
13345         assert (nparms == 1);
13346         /* save registers that need to be saved */
13347         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13348                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13349
13350         bsize=parms[0];
13351         aopOp (bsize,ic,FALSE,FALSE);
13352
13353         /* put the size in R4-R2 */
13354         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13355                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13356                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13357                 if (size==3) {
13358                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13359                         emitcode("pop","ar4");
13360                 }
13361                 emitcode("pop","ar3");
13362                 emitcode("pop","ar2");
13363         } else {
13364                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13365                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13366                 if (size==3) {
13367                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13368                 }
13369         }
13370         freeAsmop (bsize, NULL, ic, FALSE);
13371
13372         /* make the call */
13373         emitcode ("lcall","MM_%s",name);
13374         emitcode ("jz","!tlabel",lbl->key+100);
13375         emitcode ("mov","r2,#!constbyte",0xff);
13376         emitcode ("mov","r3,#!constbyte",0xff);
13377         emitLabel (lbl);
13378         /* we don't care about the pointer : we just save the handle */
13379         rsym = OP_SYMBOL(IC_RESULT(ic));
13380         if (rsym->liveFrom != rsym->liveTo) {
13381                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13382                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13383                         emitcode ("push","ar3");
13384                         emitcode ("push","ar2");
13385                         emitcode ("pop","%s",
13386                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13387                         emitcode ("pop","%s",
13388                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13389                 } else {
13390                         aopPut(IC_RESULT(ic),"r2",0);
13391                         aopPut(IC_RESULT(ic),"r3",1);
13392                 }
13393                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13394         }
13395         unsavermask(rsave);
13396 }
13397
13398 /*-----------------------------------------------------------------*/
13399 /* genMMDeref -                                                    */
13400 /*-----------------------------------------------------------------*/
13401 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13402 {
13403         bitVect *rsave ;
13404         operand *handle;
13405
13406         assert (nparms == 1);
13407         /* save registers that need to be saved */
13408         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13409                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13410
13411         handle=parms[0];
13412         aopOp (handle,ic,FALSE,FALSE);
13413
13414         /* put the size in R4-R2 */
13415         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13416                 emitcode("push","%s",
13417                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13418                 emitcode("push","%s",
13419                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13420                 emitcode("pop","ar3");
13421                 emitcode("pop","ar2");
13422         } else {
13423                 emitcode ("mov","r2,%s",
13424                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13425                 emitcode ("mov","r3,%s",
13426                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13427         }
13428         freeAsmop (handle, NULL, ic, FALSE);
13429
13430         /* make the call */
13431         emitcode ("lcall","MM_Deref");
13432
13433         {
13434                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13435                 if (rsym->liveFrom != rsym->liveTo) {
13436                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13437                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13438                             _startLazyDPSEvaluation ();
13439
13440                             aopPut(IC_RESULT(ic),"dpl",0);
13441                             aopPut(IC_RESULT(ic),"dph",1);
13442                             aopPut(IC_RESULT(ic),"dpx",2);
13443
13444                             _endLazyDPSEvaluation ();
13445
13446                         }
13447                 }
13448         }
13449         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13450         unsavermask(rsave);
13451 }
13452
13453 /*-----------------------------------------------------------------*/
13454 /* genMMUnrestrictedPersist -                                      */
13455 /*-----------------------------------------------------------------*/
13456 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13457 {
13458         bitVect *rsave ;
13459         operand *handle;
13460
13461         assert (nparms == 1);
13462         /* save registers that need to be saved */
13463         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13464                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13465
13466         handle=parms[0];
13467         aopOp (handle,ic,FALSE,FALSE);
13468
13469         /* put the size in R3-R2 */
13470         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13471                 emitcode("push","%s",
13472                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13473                 emitcode("push","%s",
13474                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13475                 emitcode("pop","ar3");
13476                 emitcode("pop","ar2");
13477         } else {
13478                 emitcode ("mov","r2,%s",
13479                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13480                 emitcode ("mov","r3,%s",
13481                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13482         }
13483         freeAsmop (handle, NULL, ic, FALSE);
13484
13485         /* make the call */
13486         emitcode ("lcall","MM_UnrestrictedPersist");
13487
13488         {
13489                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13490                 if (rsym->liveFrom != rsym->liveTo) {
13491                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13492                         aopPut(IC_RESULT(ic),"a",0);
13493                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13494                 }
13495         }
13496         unsavermask(rsave);
13497 }
13498
13499 /*-----------------------------------------------------------------*/
13500 /* genSystemExecJavaProcess -                                      */
13501 /*-----------------------------------------------------------------*/
13502 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13503 {
13504         bitVect *rsave ;
13505         operand *handle, *pp;
13506
13507         assert (nparms==2);
13508         /* save registers that need to be saved */
13509         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13510                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13511
13512         pp = parms[0];
13513         handle = parms[1];
13514
13515         /* put the handle in R3-R2 */
13516         aopOp (handle,ic,FALSE,FALSE);
13517         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13518                 emitcode("push","%s",
13519                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13520                 emitcode("push","%s",
13521                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13522                 emitcode("pop","ar3");
13523                 emitcode("pop","ar2");
13524         } else {
13525                 emitcode ("mov","r2,%s",
13526                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13527                 emitcode ("mov","r3,%s",
13528                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13529         }
13530         freeAsmop (handle, NULL, ic, FALSE);
13531
13532         /* put pointer in DPTR */
13533         aopOp (pp,ic,FALSE,FALSE);
13534         if (AOP_TYPE(pp) == AOP_IMMD) {
13535                 emitcode ("mov", "dptr,%s",
13536                           aopGet (pp, 0, TRUE, FALSE, NULL));
13537         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13538                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13539                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13540                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13541         }
13542         freeAsmop (handle, NULL, ic, FALSE);
13543
13544         /* make the call */
13545         emitcode ("lcall","System_ExecJavaProcess");
13546
13547         /* put result in place */
13548         {
13549                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13550                 if (rsym->liveFrom != rsym->liveTo) {
13551                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13552                         aopPut(IC_RESULT(ic),"a",0);
13553                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13554                 }
13555         }
13556
13557         unsavermask(rsave);
13558 }
13559
13560 /*-----------------------------------------------------------------*/
13561 /* genSystemRTCRegisters -                                         */
13562 /*-----------------------------------------------------------------*/
13563 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13564                                   char *name)
13565 {
13566         bitVect *rsave ;
13567         operand *pp;
13568
13569         assert (nparms==1);
13570         /* save registers that need to be saved */
13571         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13572                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13573
13574         pp=parms[0];
13575         /* put pointer in DPTR */
13576         aopOp (pp,ic,FALSE,FALSE);
13577         if (AOP_TYPE (pp) == AOP_IMMD) {
13578                 emitcode ("mov","dps,#1");
13579                 emitcode ("mov", "dptr,%s",
13580                           aopGet (pp, 0, TRUE, FALSE, NULL));
13581                 emitcode ("mov","dps,#0");
13582         } else {
13583                 emitcode ("mov","dpl1,%s",
13584                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13585                 emitcode ("mov","dph1,%s",
13586                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13587                 emitcode ("mov","dpx1,%s",
13588                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13589         }
13590         freeAsmop (pp, NULL, ic, FALSE);
13591
13592         /* make the call */
13593         emitcode ("lcall","System_%sRTCRegisters",name);
13594
13595         unsavermask(rsave);
13596 }
13597
13598 /*-----------------------------------------------------------------*/
13599 /* genSystemThreadSleep -                                          */
13600 /*-----------------------------------------------------------------*/
13601 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13602 {
13603         bitVect *rsave ;
13604         operand *to, *s;
13605
13606         assert (nparms==1);
13607         /* save registers that need to be saved */
13608         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13609                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13610
13611         to = parms[0];
13612         aopOp(to,ic,FALSE,FALSE);
13613         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13614             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13615                 emitcode ("push","%s",
13616                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13617                 emitcode ("push","%s",
13618                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13619                 emitcode ("push","%s",
13620                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13621                 emitcode ("push","%s",
13622                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13623                 emitcode ("pop","ar3");
13624                 emitcode ("pop","ar2");
13625                 emitcode ("pop","ar1");
13626                 emitcode ("pop","ar0");
13627         } else {
13628                 emitcode ("mov","r0,%s",
13629                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13630                 emitcode ("mov","r1,%s",
13631                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13632                 emitcode ("mov","r2,%s",
13633                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13634                 emitcode ("mov","r3,%s",
13635                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13636         }
13637         freeAsmop (to, NULL, ic, FALSE);
13638
13639         /* suspend in acc */
13640         s = parms[1];
13641         aopOp(s,ic,FALSE,FALSE);
13642         emitcode ("mov","a,%s",
13643                   aopGet(s,0,FALSE,TRUE,NULL));
13644         freeAsmop (s, NULL, ic, FALSE);
13645
13646         /* make the call */
13647         emitcode ("lcall","System_%s",name);
13648
13649         unsavermask(rsave);
13650 }
13651
13652 /*-----------------------------------------------------------------*/
13653 /* genSystemThreadResume -                                         */
13654 /*-----------------------------------------------------------------*/
13655 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13656 {
13657         bitVect *rsave ;
13658         operand *tid,*pid;
13659
13660         assert (nparms==2);
13661         /* save registers that need to be saved */
13662         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13663                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13664
13665         tid = parms[0];
13666         pid = parms[1];
13667
13668         /* PID in R0 */
13669         aopOp(pid,ic,FALSE,FALSE);
13670         emitcode ("mov","r0,%s",
13671                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13672         freeAsmop (pid, NULL, ic, FALSE);
13673
13674         /* tid into ACC */
13675         aopOp(tid,ic,FALSE,FALSE);
13676         emitcode ("mov","a,%s",
13677                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13678         freeAsmop (tid, NULL, ic, FALSE);
13679
13680         emitcode ("lcall","System_ThreadResume");
13681
13682         /* put result into place */
13683         {
13684                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13685                 if (rsym->liveFrom != rsym->liveTo) {
13686                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13687                         aopPut(IC_RESULT(ic),"a",0);
13688                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13689                 }
13690         }
13691         unsavermask(rsave);
13692 }
13693
13694 /*-----------------------------------------------------------------*/
13695 /* genSystemProcessResume -                                        */
13696 /*-----------------------------------------------------------------*/
13697 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13698 {
13699         bitVect *rsave ;
13700         operand *pid;
13701
13702         assert (nparms==1);
13703         /* save registers that need to be saved */
13704         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13705                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13706
13707         pid = parms[0];
13708
13709         /* pid into ACC */
13710         aopOp(pid,ic,FALSE,FALSE);
13711         emitcode ("mov","a,%s",
13712                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13713         freeAsmop (pid, NULL, ic, FALSE);
13714
13715         emitcode ("lcall","System_ProcessResume");
13716
13717         unsavermask(rsave);
13718 }
13719
13720 /*-----------------------------------------------------------------*/
13721 /* genSystem -                                                     */
13722 /*-----------------------------------------------------------------*/
13723 static void genSystem (iCode *ic,int nparms,char *name)
13724 {
13725         assert(nparms == 0);
13726
13727         emitcode ("lcall","System_%s",name);
13728 }
13729
13730 /*-----------------------------------------------------------------*/
13731 /* genSystemPoll -                                                  */
13732 /*-----------------------------------------------------------------*/
13733 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13734 {
13735         bitVect *rsave ;
13736         operand *fp;
13737
13738         assert (nparms==1);
13739         /* save registers that need to be saved */
13740         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13741                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13742
13743         fp = parms[0];
13744         aopOp (fp,ic,FALSE,FALSE);
13745         if (AOP_TYPE (fp) == AOP_IMMD) {
13746                 emitcode ("mov", "dptr,%s",
13747                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13748         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13749                 emitcode ("mov","dpl,%s",
13750                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13751                 emitcode ("mov","dph,%s",
13752                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13753                 emitcode ("mov","dpx,%s",
13754                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13755         }
13756         freeAsmop (fp, NULL, ic, FALSE);
13757
13758         emitcode ("lcall","System_%sPoll",name);
13759
13760         /* put result into place */
13761         {
13762                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13763                 if (rsym->liveFrom != rsym->liveTo) {
13764                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13765                         aopPut(IC_RESULT(ic),"a",0);
13766                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13767                 }
13768         }
13769         unsavermask(rsave);
13770 }
13771
13772 /*-----------------------------------------------------------------*/
13773 /* genSystemGetCurrentID -                                         */
13774 /*-----------------------------------------------------------------*/
13775 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13776 {
13777         assert (nparms==0);
13778
13779         emitcode ("lcall","System_GetCurrent%sId",name);
13780         /* put result into place */
13781         {
13782                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13783                 if (rsym->liveFrom != rsym->liveTo) {
13784                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13785                         aopPut(IC_RESULT(ic),"a",0);
13786                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13787                 }
13788         }
13789 }
13790
13791 /*-----------------------------------------------------------------*/
13792 /* genDjnz - generate decrement & jump if not zero instrucion      */
13793 /*-----------------------------------------------------------------*/
13794 static int
13795 genDjnz (iCode * ic, iCode * ifx)
13796 {
13797   symbol *lbl, *lbl1;
13798   if (!ifx)
13799     return 0;
13800
13801   /* if the if condition has a false label
13802      then we cannot save */
13803   if (IC_FALSE (ifx))
13804     return 0;
13805
13806   /* if the minus is not of the form a = a - 1 */
13807   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13808       !IS_OP_LITERAL (IC_RIGHT (ic)))
13809     return 0;
13810
13811   if (operandLitValue (IC_RIGHT (ic)) != 1)
13812     return 0;
13813
13814   /* if the size of this greater than one then no
13815      saving */
13816   if (getSize (operandType (IC_RESULT (ic))) > 1)
13817     return 0;
13818
13819   /* otherwise we can save BIG */
13820
13821   D (emitcode (";", "genDjnz"));
13822
13823   lbl = newiTempLabel (NULL);
13824   lbl1 = newiTempLabel (NULL);
13825
13826   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13827
13828   if (AOP_NEEDSACC(IC_RESULT(ic)))
13829   {
13830       /* If the result is accessed indirectly via
13831        * the accumulator, we must explicitly write
13832        * it back after the decrement.
13833        */
13834       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13835
13836       if (strcmp(rByte, "a"))
13837       {
13838            /* Something is hopelessly wrong */
13839            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13840                    __FILE__, __LINE__);
13841            /* We can just give up; the generated code will be inefficient,
13842             * but what the hey.
13843             */
13844            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13845            return 0;
13846       }
13847       emitcode ("dec", "%s", rByte);
13848       aopPut (IC_RESULT (ic), rByte, 0);
13849       emitcode ("jnz", "!tlabel", lbl->key + 100);
13850   }
13851   else if (IS_AOP_PREG (IC_RESULT (ic)))
13852     {
13853       emitcode ("dec", "%s",
13854                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13855       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13856       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13857       ifx->generated = 1;
13858       emitcode ("jnz", "!tlabel", lbl->key + 100);
13859     }
13860   else
13861     {
13862       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13863                 lbl->key + 100);
13864     }
13865   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13866   emitLabel (lbl);
13867   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13868   emitLabel (lbl1);
13869
13870   if (!ifx->generated)
13871       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13872   ifx->generated = 1;
13873   return 1;
13874 }
13875
13876 /*-----------------------------------------------------------------*/
13877 /* genReceive - generate code for a receive iCode                  */
13878 /*-----------------------------------------------------------------*/
13879 static void
13880 genReceive (iCode * ic)
13881 {
13882     int size = getSize (operandType (IC_RESULT (ic)));
13883     int offset = 0;
13884     int rb1off ;
13885
13886     D (emitcode (";", "genReceive"));
13887
13888     if (ic->argreg == 1)
13889     {
13890         /* first parameter */
13891         if (AOP_IS_STR(IC_RESULT(ic)))
13892         {
13893             /* Nothing to do: it's already in the proper place. */
13894             return;
13895         }
13896         else
13897         {
13898             bool useDp2;
13899
13900             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13901                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13902                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13903
13904             _G.accInUse++;
13905             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13906             _G.accInUse--;
13907
13908             /* Sanity checking... */
13909             if (AOP_USESDPTR(IC_RESULT(ic)))
13910             {
13911                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13912                         "genReceive got unexpected DPTR.");
13913             }
13914             assignResultValue (IC_RESULT (ic), NULL);
13915         }
13916     }
13917     else if (ic->argreg > 12)
13918     { /* bit parameters */
13919       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13920         {
13921           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13922           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13923           outBitC(IC_RESULT (ic));
13924         }
13925     }
13926     else
13927     {
13928         /* second receive onwards */
13929         /* this gets a little tricky since unused receives will be
13930          eliminated, we have saved the reg in the type field . and
13931          we use that to figure out which register to use */
13932         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13933         rb1off = ic->argreg;
13934         while (size--)
13935         {
13936             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13937         }
13938     }
13939     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13940 }
13941
13942 /*-----------------------------------------------------------------*/
13943 /* genDummyRead - generate code for dummy read of volatiles        */
13944 /*-----------------------------------------------------------------*/
13945 static void
13946 genDummyRead (iCode * ic)
13947 {
13948   operand *op;
13949   int size, offset;
13950
13951   D (emitcode(";", "genDummyRead"));
13952
13953   op = IC_RIGHT (ic);
13954   if (op && IS_SYMOP (op))
13955     {
13956       aopOp (op, ic, FALSE, FALSE);
13957
13958       /* if the result is a bit */
13959       if (AOP_TYPE (op) == AOP_CRY)
13960         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13961       else
13962         {
13963           /* bit variables done */
13964           /* general case */
13965           size = AOP_SIZE (op);
13966           offset = 0;
13967           while (size--)
13968           {
13969             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13970             offset++;
13971           }
13972         }
13973
13974       freeAsmop (op, NULL, ic, TRUE);
13975     }
13976
13977   op = IC_LEFT (ic);
13978   if (op && IS_SYMOP (op))
13979     {
13980       aopOp (op, ic, FALSE, FALSE);
13981
13982       /* if the result is a bit */
13983       if (AOP_TYPE (op) == AOP_CRY)
13984         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13985       else
13986         {
13987           /* bit variables done */
13988           /* general case */
13989           size = AOP_SIZE (op);
13990           offset = 0;
13991           while (size--)
13992           {
13993             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13994             offset++;
13995           }
13996         }
13997
13998       freeAsmop (op, NULL, ic, TRUE);
13999     }
14000 }
14001
14002 /*-----------------------------------------------------------------*/
14003 /* genCritical - generate code for start of a critical sequence    */
14004 /*-----------------------------------------------------------------*/
14005 static void
14006 genCritical (iCode *ic)
14007 {
14008   symbol *tlbl = newiTempLabel (NULL);
14009
14010   D (emitcode(";", "genCritical"));
14011
14012   if (IC_RESULT (ic))
14013     {
14014       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14015       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14016       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14017       aopPut (IC_RESULT (ic), zero, 0);
14018       emitLabel (tlbl);
14019       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14020     }
14021   else
14022     {
14023       emitcode ("setb", "c");
14024       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14025       emitcode ("clr", "c");
14026       emitLabel (tlbl);
14027       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14028     }
14029 }
14030
14031 /*-----------------------------------------------------------------*/
14032 /* genEndCritical - generate code for end of a critical sequence   */
14033 /*-----------------------------------------------------------------*/
14034 static void
14035 genEndCritical (iCode *ic)
14036 {
14037   D(emitcode(";     genEndCritical",""));
14038
14039   if (IC_RIGHT (ic))
14040     {
14041       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14042       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14043         {
14044           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14045           emitcode ("mov", "ea,c");
14046         }
14047       else
14048         {
14049           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14050           emitcode ("rrc", "a");
14051           emitcode ("mov", "ea,c");
14052         }
14053       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14054     }
14055   else
14056     {
14057       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14058       emitcode ("mov", "ea,c");
14059     }
14060 }
14061
14062
14063
14064 /*-----------------------------------------------------------------*/
14065 /* genBuiltIn - calls the appropriate function to  generating code */
14066 /* for a built in function                                         */
14067 /*-----------------------------------------------------------------*/
14068 static void genBuiltIn (iCode *ic)
14069 {
14070         operand *bi_parms[MAX_BUILTIN_ARGS];
14071         int nbi_parms;
14072         iCode *bi_iCode;
14073         symbol *bif;
14074
14075         /* get all the arguments for a built in function */
14076         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14077
14078         /* which function is it */
14079         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14080         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14081                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14082         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14083                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14084         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14085                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14086         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14087                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14088         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14089                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14090         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14091                 genInp(bi_iCode,nbi_parms,bi_parms);
14092         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14093                 genOutp(bi_iCode,nbi_parms,bi_parms);
14094         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14095                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14096                 /* JavaNative builtIns */
14097         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14098                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14099         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14100                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14101         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14102                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14103         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14104                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14105         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14106                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14107         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14108                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14109         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14110                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14111         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14112                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14113         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14114                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14115         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14116                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14117         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14118                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14119         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14120                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14121         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14122                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14123         } else if (strcmp(bif->name,"MM_Free")==0) {
14124                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14125         } else if (strcmp(bif->name,"MM_Deref")==0) {
14126                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14127         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14128                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14129         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14130                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14131         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14132                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14133         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14134                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14135         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14136                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14137         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14138                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14139         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14140                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14141         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14142                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14143         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14144                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14145         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14146                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14147         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14148                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14149         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14150                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14151         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14152                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14153         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14154                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14155         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14156                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14157         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14158                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14159         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14160                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14161         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14162                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14163         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14164                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14165         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14166                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14167         } else {
14168                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14169                 return ;
14170         }
14171         return ;
14172 }
14173
14174 /*-----------------------------------------------------------------*/
14175 /* gen390Code - generate code for Dallas 390 based controllers     */
14176 /*-----------------------------------------------------------------*/
14177 void
14178 gen390Code (iCode * lic)
14179 {
14180   iCode *ic;
14181   int cln = 0;
14182
14183   _G.currentFunc = NULL;
14184   lineHead = lineCurr = NULL;
14185   dptrn[1][0] = "dpl1";
14186   dptrn[1][1] = "dph1";
14187   dptrn[1][2] = "dpx1";
14188
14189   if (options.model == MODEL_FLAT24) {
14190     fReturnSizeDS390 = 5;
14191     fReturn = fReturn24;
14192   } else {
14193     fReturnSizeDS390 = 4;
14194     fReturn = fReturn16;
14195     options.stack10bit=0;
14196   }
14197 #if 1
14198   /* print the allocation information */
14199   if (allocInfo && currFunc)
14200     printAllocInfo (currFunc, codeOutBuf);
14201 #endif
14202   /* if debug information required */
14203   if (options.debug && currFunc)
14204     {
14205       debugFile->writeFunction (currFunc, lic);
14206     }
14207   /* stack pointer name */
14208   if (options.useXstack)
14209     spname = "_spx";
14210   else
14211     spname = "sp";
14212
14213
14214   for (ic = lic; ic; ic = ic->next)
14215     {
14216       _G.current_iCode = ic;
14217
14218       if (ic->lineno && cln != ic->lineno)
14219         {
14220           if (options.debug)
14221             {
14222               debugFile->writeCLine (ic);
14223             }
14224           if (!options.noCcodeInAsm) {
14225             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14226                       printCLine(ic->filename, ic->lineno));
14227           }
14228           cln = ic->lineno;
14229         }
14230       if (options.iCodeInAsm) {
14231         char *iLine = printILine(ic);
14232         emitcode("", ";ic:%d: %s", ic->key, iLine);
14233         dbuf_free(iLine);
14234       }
14235       /* if the result is marked as
14236          spilt and rematerializable or code for
14237          this has already been generated then
14238          do nothing */
14239       if (resultRemat (ic) || ic->generated)
14240         continue;
14241
14242       /* depending on the operation */
14243       switch (ic->op)
14244         {
14245         case '!':
14246           genNot (ic);
14247           break;
14248
14249         case '~':
14250           genCpl (ic);
14251           break;
14252
14253         case UNARYMINUS:
14254           genUminus (ic);
14255           break;
14256
14257         case IPUSH:
14258           genIpush (ic);
14259           break;
14260
14261         case IPOP:
14262           /* IPOP happens only when trying to restore a
14263              spilt live range, if there is an ifx statement
14264              following this pop then the if statement might
14265              be using some of the registers being popped which
14266              would destory the contents of the register so
14267              we need to check for this condition and handle it */
14268           if (ic->next &&
14269               ic->next->op == IFX &&
14270               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14271             genIfx (ic->next, ic);
14272           else
14273             genIpop (ic);
14274           break;
14275
14276         case CALL:
14277           genCall (ic);
14278           break;
14279
14280         case PCALL:
14281           genPcall (ic);
14282           break;
14283
14284         case FUNCTION:
14285           genFunction (ic);
14286           break;
14287
14288         case ENDFUNCTION:
14289           genEndFunction (ic);
14290           break;
14291
14292         case RETURN:
14293           genRet (ic);
14294           break;
14295
14296         case LABEL:
14297           genLabel (ic);
14298           break;
14299
14300         case GOTO:
14301           genGoto (ic);
14302           break;
14303
14304         case '+':
14305           genPlus (ic);
14306           break;
14307
14308         case '-':
14309           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14310             genMinus (ic);
14311           break;
14312
14313         case '*':
14314           genMult (ic);
14315           break;
14316
14317         case '/':
14318           genDiv (ic);
14319           break;
14320
14321         case '%':
14322           genMod (ic);
14323           break;
14324
14325         case '>':
14326           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14327           break;
14328
14329         case '<':
14330           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14331           break;
14332
14333         case LE_OP:
14334         case GE_OP:
14335         case NE_OP:
14336
14337           /* note these two are xlated by algebraic equivalence
14338              during parsing SDCC.y */
14339           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14340                   "got '>=' or '<=' shouldn't have come here");
14341           break;
14342
14343         case EQ_OP:
14344           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14345           break;
14346
14347         case AND_OP:
14348           genAndOp (ic);
14349           break;
14350
14351         case OR_OP:
14352           genOrOp (ic);
14353           break;
14354
14355         case '^':
14356           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14357           break;
14358
14359         case '|':
14360           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14361           break;
14362
14363         case BITWISEAND:
14364           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14365           break;
14366
14367         case INLINEASM:
14368           genInline (ic);
14369           break;
14370
14371         case RRC:
14372           genRRC (ic);
14373           break;
14374
14375         case RLC:
14376           genRLC (ic);
14377           break;
14378
14379         case GETHBIT:
14380           genGetHbit (ic);
14381           break;
14382
14383         case LEFT_OP:
14384           genLeftShift (ic);
14385           break;
14386
14387         case RIGHT_OP:
14388           genRightShift (ic);
14389           break;
14390
14391         case GET_VALUE_AT_ADDRESS:
14392           genPointerGet (ic,
14393                          hasInc (IC_LEFT (ic), ic,
14394                                  getSize (operandType (IC_RESULT (ic)))));
14395           break;
14396
14397         case '=':
14398           if (POINTER_SET (ic))
14399             genPointerSet (ic,
14400                            hasInc (IC_RESULT (ic), ic,
14401                                    getSize (operandType (IC_RIGHT (ic)))));
14402           else
14403             genAssign (ic);
14404           break;
14405
14406         case IFX:
14407           genIfx (ic, NULL);
14408           break;
14409
14410         case ADDRESS_OF:
14411           genAddrOf (ic);
14412           break;
14413
14414         case JUMPTABLE:
14415           genJumpTab (ic);
14416           break;
14417
14418         case CAST:
14419           genCast (ic);
14420           break;
14421
14422         case RECEIVE:
14423           genReceive (ic);
14424           break;
14425
14426         case SEND:
14427           if (ic->builtinSEND)
14428             genBuiltIn(ic);
14429           else
14430             addSet (&_G.sendSet, ic);
14431           break;
14432
14433         case DUMMY_READ_VOLATILE:
14434           genDummyRead (ic);
14435           break;
14436
14437         case CRITICAL:
14438           genCritical (ic);
14439           break;
14440
14441         case ENDCRITICAL:
14442           genEndCritical (ic);
14443           break;
14444
14445         case SWAP:
14446           genSwap (ic);
14447           break;
14448
14449 #if 0 // obsolete, and buggy for != xdata
14450         case ARRAYINIT:
14451             genArrayInit(ic);
14452             break;
14453 #endif
14454
14455         default:
14456           ic = ic;
14457         }
14458     }
14459
14460
14461   /* now we are ready to call the
14462      peep hole optimizer */
14463   if (!options.nopeep)
14464     peepHole (&lineHead);
14465
14466   /* now do the actual printing */
14467   printLine (lineHead, codeOutBuf);
14468   return;
14469 }