728bf80d088021b4ed129492f6d648e491c4b15e
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) do if (options.verboseAsm) {x;} while(0)
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                         AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC     emitcode("clr","c")
170 #define SETC     emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227         }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_OP_ACCUSE (op))
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_OP_ACCUSE (op))
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_OP_ACCUSE (op))
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_OP_ACCUSE (op))
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerializes an object                          */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic))
908         {
909           sym_link *from_type = operandType(IC_RIGHT(ic));
910           aop->aopu.aop_immd.from_cast_remat = 1;
911           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
912           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
913           continue;
914         }
915       else break;
916
917       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
918     }
919
920   if (val)
921     {
922       SNPRINTF (buffer, sizeof(buffer),
923                 "(%s %c 0x%06x)",
924                 OP_SYMBOL (IC_LEFT (ic))->rname,
925                 val >= 0 ? '+' : '-',
926                 abs (val) & 0xffffff);
927     }
928   else
929     {
930       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
931         {
932           SNPRINTF(buffer, sizeof(buffer),
933                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
934         }
935       else
936         {
937           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
938         }
939     }
940
941   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
942   /* set immd2 field if required */
943   if (aop->aopu.aop_immd.from_cast_remat)
944     {
945       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
946       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
947     }
948
949   return aop;
950 }
951
952 /*-----------------------------------------------------------------*/
953 /* aopHasRegs - returns true if aop has regs between from-to       */
954 /*-----------------------------------------------------------------*/
955 static int aopHasRegs(asmop *aop, int from, int to)
956 {
957     int size =0;
958
959     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
960
961     for (; size < aop->size ; size++) {
962         int reg;
963         for (reg = from ; reg <= to ; reg++)
964             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
965     }
966     return 0;
967 }
968
969 /*-----------------------------------------------------------------*/
970 /* regsInCommon - two operands have some registers in common       */
971 /*-----------------------------------------------------------------*/
972 static bool
973 regsInCommon (operand * op1, operand * op2)
974 {
975   symbol *sym1, *sym2;
976   int i;
977
978   /* if they have registers in common */
979   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
980     return FALSE;
981
982   sym1 = OP_SYMBOL (op1);
983   sym2 = OP_SYMBOL (op2);
984
985   if (sym1->nRegs == 0 || sym2->nRegs == 0)
986     return FALSE;
987
988   for (i = 0; i < sym1->nRegs; i++)
989     {
990       int j;
991       if (!sym1->regs[i])
992         continue;
993
994       for (j = 0; j < sym2->nRegs; j++)
995         {
996           if (!sym2->regs[j])
997             continue;
998
999           if (sym2->regs[j] == sym1->regs[i])
1000             return TRUE;
1001         }
1002     }
1003
1004   return FALSE;
1005 }
1006
1007 /*-----------------------------------------------------------------*/
1008 /* operandsEqu - equivalent                                        */
1009 /*-----------------------------------------------------------------*/
1010 static bool
1011 operandsEqu (operand * op1, operand * op2)
1012 {
1013   symbol *sym1, *sym2;
1014
1015   /* if they're not symbols */
1016   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1017     return FALSE;
1018
1019   sym1 = OP_SYMBOL (op1);
1020   sym2 = OP_SYMBOL (op2);
1021
1022   /* if both are itemps & one is spilt
1023      and the other is not then false */
1024   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1025       sym1->isspilt != sym2->isspilt)
1026     return FALSE;
1027
1028   /* if they are the same */
1029   if (sym1 == sym2)
1030     return TRUE;
1031
1032   /* if they have the same rname */
1033   if (sym1->rname[0] && sym2->rname[0] &&
1034       strcmp (sym1->rname, sym2->rname) == 0 &&
1035       !(IS_PARM (op2) && IS_ITEMP (op1)))
1036     return TRUE;
1037
1038   /* if left is a tmp & right is not */
1039   if (IS_ITEMP (op1) &&
1040       !IS_ITEMP (op2) &&
1041       sym1->isspilt &&
1042       (sym1->usl.spillLoc == sym2))
1043     return TRUE;
1044
1045   if (IS_ITEMP (op2) &&
1046       !IS_ITEMP (op1) &&
1047       sym2->isspilt &&
1048       sym1->level > 0 &&
1049       (sym2->usl.spillLoc == sym1))
1050     return TRUE;
1051
1052   /* are they spilt to the same location */
1053   if (IS_ITEMP (op2) &&
1054       IS_ITEMP (op1) &&
1055       sym2->isspilt &&
1056       sym1->isspilt &&
1057       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1058     return TRUE;
1059
1060   return FALSE;
1061 }
1062
1063 /*-----------------------------------------------------------------*/
1064 /* sameRegs - two asmops have the same registers                   */
1065 /*-----------------------------------------------------------------*/
1066 static bool
1067 sameRegs (asmop * aop1, asmop * aop2)
1068 {
1069   int i;
1070
1071   if (aop1 == aop2)
1072     {
1073       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1074         {
1075           return FALSE;
1076         }
1077       return TRUE;
1078     }
1079
1080   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1081     return FALSE;
1082
1083   if (aop1->type != aop2->type)
1084     return FALSE;
1085
1086   if (aop1->size != aop2->size)
1087     return FALSE;
1088
1089   for (i = 0; i < aop1->size; i++)
1090     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1091       return FALSE;
1092
1093   return TRUE;
1094 }
1095
1096 /*-----------------------------------------------------------------*/
1097 /* aopOp - allocates an asmop for an operand  :                    */
1098 /*-----------------------------------------------------------------*/
1099 static void
1100 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1101 {
1102   asmop *aop;
1103   symbol *sym;
1104   int i;
1105
1106   if (!op)
1107     return;
1108
1109   /* if this a literal */
1110   if (IS_OP_LITERAL (op))
1111     {
1112       op->aop = aop = newAsmop (AOP_LIT);
1113       aop->aopu.aop_lit = op->operand.valOperand;
1114       aop->size = getSize (operandType (op));
1115       return;
1116     }
1117
1118   /* if already has a asmop then continue */
1119   if (op->aop)
1120     {
1121       if ((op->aop->type == AOP_DPTR && useDP2)
1122           || (op->aop->type == AOP_DPTR2 && !useDP2))
1123         op->aop = NULL;
1124       else
1125         {
1126           op->aop->allocated++;
1127           return;
1128         }
1129     }
1130
1131   /* if the underlying symbol has a aop */
1132   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1133     {
1134       op->aop = OP_SYMBOL (op)->aop;
1135       if ((op->aop->type == AOP_DPTR && useDP2)
1136           || (op->aop->type == AOP_DPTR2 && !useDP2))
1137         op->aop = NULL;
1138       else
1139         {
1140           op->aop->allocated++;
1141           return;
1142         }
1143     }
1144
1145   /* if this is a true symbol */
1146   if (IS_TRUE_SYMOP (op))
1147     {
1148       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1149       return;
1150     }
1151
1152   /* this is a temporary : this has
1153      only five choices :
1154      a) register
1155      b) spillocation
1156      c) rematerialize
1157      d) conditional
1158      e) can be a return use only */
1159
1160   sym = OP_SYMBOL (op);
1161
1162   /* if the type is a conditional */
1163   if (sym->regType == REG_CND)
1164     {
1165       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1166       aop->size = 0;
1167       return;
1168     }
1169
1170   /* if it is spilt then two situations
1171      a) is rematerialize
1172      b) has a spill location */
1173   if (sym->isspilt || sym->nRegs == 0)
1174     {
1175
1176       /* rematerialize it NOW */
1177       if (sym->remat)
1178         {
1179           sym->aop = op->aop = aop = aopForRemat (sym);
1180           aop->size = getSize (sym->type);
1181           return;
1182         }
1183
1184       if (sym->accuse)
1185         {
1186           int i;
1187           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1188           aop->size = getSize (sym->type);
1189           for (i = 0; i < 2; i++)
1190             aop->aopu.aop_str[i] = accUse[i];
1191           return;
1192         }
1193
1194       if (sym->ruonly)
1195         {
1196           unsigned i;
1197
1198           if (useDP2)
1199             {
1200               /* a AOP_STR uses DPTR, but DPTR is already in use;
1201                * we're just hosed.
1202                */
1203                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1204             }
1205
1206           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1207           aop->size = getSize (sym->type);
1208           for (i = 0; i < fReturnSizeDS390; i++)
1209             aop->aopu.aop_str[i] = fReturn[i];
1210           return;
1211         }
1212
1213       if (sym->dptr) { /* has been allocated to a DPTRn */
1214           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1215           aop->size = getSize (sym->type);
1216           aop->aopu.dptr = sym->dptr;
1217           return ;
1218       }
1219
1220       if (sym->usl.spillLoc)
1221         {
1222           asmop *oldAsmOp = NULL;
1223
1224           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1225             {
1226               /* force a new aop if sizes differ */
1227               oldAsmOp = sym->usl.spillLoc->aop;
1228               sym->usl.spillLoc->aop = NULL;
1229             }
1230           sym->aop = op->aop = aop =
1231                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1232           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1233             {
1234               /* Don't reuse the new aop, go with the last one */
1235               sym->usl.spillLoc->aop = oldAsmOp;
1236             }
1237           aop->size = getSize (sym->type);
1238           return;
1239         }
1240
1241       /* else must be a dummy iTemp */
1242       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1243       aop->size = getSize (sym->type);
1244       return;
1245     }
1246
1247   /* if the type is a bit register */
1248   if (sym->regType == REG_BIT)
1249     {
1250       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1251       aop->size = sym->nRegs;//1???
1252       aop->aopu.aop_reg[0] = sym->regs[0];
1253       aop->aopu.aop_dir = sym->regs[0]->name;
1254       return;
1255     }
1256
1257   /* must be in a register */
1258   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1259   aop->size = sym->nRegs;
1260   for (i = 0; i < sym->nRegs; i++)
1261     aop->aopu.aop_reg[i] = sym->regs[i];
1262 }
1263
1264 /*-----------------------------------------------------------------*/
1265 /* freeAsmop - free up the asmop given to an operand               */
1266 /*-----------------------------------------------------------------*/
1267 static void
1268 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1269 {
1270   asmop *aop;
1271
1272   if (!op)
1273     aop = aaop;
1274   else
1275     aop = op->aop;
1276
1277   if (!aop)
1278     return;
1279
1280   aop->allocated--;
1281
1282   if (aop->allocated)
1283     goto dealloc;
1284
1285   /* depending on the asmop type only three cases need work
1286      AOP_R0, AOP_R1 & AOP_STK */
1287   switch (aop->type)
1288     {
1289     case AOP_R0:
1290       if (_G.r0Pushed)
1291         {
1292           if (pop)
1293             {
1294               emitcode ("pop", "ar0");
1295               _G.r0Pushed--;
1296             }
1297         }
1298       bitVectUnSetBit (ic->rUsed, R0_IDX);
1299       break;
1300
1301     case AOP_R1:
1302       if (_G.r1Pushed)
1303         {
1304           if (pop)
1305             {
1306               emitcode ("pop", "ar1");
1307               _G.r1Pushed--;
1308             }
1309         }
1310       bitVectUnSetBit (ic->rUsed, R1_IDX);
1311       break;
1312
1313     case AOP_STK:
1314       {
1315         int sz = aop->size;
1316         int stk = aop->aopu.aop_stk + aop->size;
1317         bitVectUnSetBit (ic->rUsed, R0_IDX);
1318         bitVectUnSetBit (ic->rUsed, R1_IDX);
1319
1320         getFreePtr (ic, &aop, FALSE);
1321
1322         if (options.stack10bit)
1323           {
1324             /* I'm not sure what to do here yet... */
1325             /* #STUB */
1326             fprintf (stderr,
1327                      "*** Warning: probably generating bad code for "
1328                      "10 bit stack mode.\n");
1329           }
1330
1331         if (stk)
1332           {
1333             emitcode ("mov", "a,_bp");
1334             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1335             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1336           }
1337         else
1338           {
1339             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1340           }
1341
1342         while (sz--)
1343           {
1344             emitcode ("pop", "acc");
1345             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1346             if (!sz)
1347               break;
1348             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1349           }
1350         op->aop = aop;
1351         freeAsmop (op, NULL, ic, TRUE);
1352         if (_G.r1Pushed)
1353           {
1354             emitcode ("pop", "ar1");
1355             _G.r1Pushed--;
1356           }
1357         if (_G.r0Pushed)
1358           {
1359             emitcode ("pop", "ar0");
1360             _G.r0Pushed--;
1361           }
1362       }
1363     case AOP_DPTR2:
1364         if (_G.dptr1InUse) {
1365             emitcode ("pop","dpx1");
1366             emitcode ("pop","dph1");
1367             emitcode ("pop","dpl1");
1368         }
1369         break;
1370     case AOP_DPTR:
1371         if (_G.dptrInUse) {
1372             emitcode ("pop","dpx");
1373             emitcode ("pop","dph");
1374             emitcode ("pop","dpl");
1375         }
1376         break;
1377     }
1378
1379 dealloc:
1380   /* all other cases just dealloc */
1381   if (op)
1382     {
1383       op->aop = NULL;
1384       if (IS_SYMOP (op))
1385         {
1386           OP_SYMBOL (op)->aop = NULL;
1387           /* if the symbol has a spill */
1388           if (SPIL_LOC (op))
1389             SPIL_LOC (op)->aop = NULL;
1390         }
1391     }
1392 }
1393
1394 #define DEFAULT_ACC_WARNING 0
1395 static int saveAccWarn = DEFAULT_ACC_WARNING;
1396
1397
1398 /*-----------------------------------------------------------------*/
1399 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1400 /*                 clobber the accumulator                         */
1401 /*-----------------------------------------------------------------*/
1402 static bool
1403 aopGetUsesAcc (operand * oper, int offset)
1404 {
1405   asmop * aop = AOP (oper);
1406
1407   if (offset > (aop->size - 1))
1408     return FALSE;
1409
1410   switch (aop->type)
1411     {
1412
1413     case AOP_R0:
1414     case AOP_R1:
1415       if (aop->paged)
1416         return TRUE;
1417       return FALSE;
1418     case AOP_DPTR:
1419     case AOP_DPTR2:
1420     case AOP_DPTRn:
1421       return TRUE;
1422     case AOP_IMMD:
1423       return FALSE;
1424     case AOP_DIR:
1425       return FALSE;
1426     case AOP_REG:
1427       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1428       return FALSE;
1429     case AOP_CRY:
1430       return TRUE;
1431     case AOP_ACC:
1432       if (offset)
1433         return FALSE;
1434       return TRUE;
1435     case AOP_LIT:
1436       return FALSE;
1437     case AOP_STR:
1438       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1439         return TRUE;
1440       return FALSE;
1441     case AOP_DUMMY:
1442       return FALSE;
1443     default:
1444       /* Error case --- will have been caught already */
1445       wassert(0);
1446       return FALSE;
1447     }
1448 }
1449
1450 /*-------------------------------------------------------------------*/
1451 /* aopGet - for fetching value of the aop                            */
1452 /*                                                                   */
1453 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1454 /* in the accumulator. Set it to the name of a free register         */
1455 /* if acc must be preserved; the register will be used to preserve   */
1456 /* acc temporarily and to return the result byte.                    */
1457 /*-------------------------------------------------------------------*/
1458 static char *
1459 aopGet (operand * oper,
1460         int   offset,
1461         bool  bit16,
1462         bool  dname,
1463         char  *saveAcc)
1464 {
1465   asmop * aop = AOP (oper);
1466
1467   /* offset is greater than
1468      size then zero */
1469   if (offset > (aop->size - 1) &&
1470       aop->type != AOP_LIT)
1471     return zero;
1472
1473   /* depending on type */
1474   switch (aop->type)
1475     {
1476     case AOP_DUMMY:
1477       return zero;
1478
1479     case AOP_R0:
1480     case AOP_R1:
1481       /* if we need to increment it */
1482       while (offset > aop->coff)
1483         {
1484           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1485           aop->coff++;
1486         }
1487
1488       while (offset < aop->coff)
1489         {
1490           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1491           aop->coff--;
1492         }
1493
1494       aop->coff = offset;
1495       if (aop->paged)
1496         {
1497           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1498           return (dname ? "acc" : "a");
1499         }
1500       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1501       return Safe_strdup(buffer);
1502
1503     case AOP_DPTRn:
1504         assert(offset <= 3);
1505         return dptrn[aop->aopu.dptr][offset];
1506
1507     case AOP_DPTR:
1508     case AOP_DPTR2:
1509
1510       if (aop->type == AOP_DPTR2)
1511         {
1512           genSetDPTR (1);
1513         }
1514
1515       if (saveAcc)
1516         {
1517             TR_AP("#1");
1518 //          if (aop->type != AOP_DPTR2)
1519 //          {
1520 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1521 //              emitcode(";", "spanky: saveAcc for DPTR");
1522 //          }
1523
1524             emitcode ("xch", "a, %s", saveAcc);
1525         }
1526
1527       _flushLazyDPS ();
1528
1529       while (offset > aop->coff)
1530         {
1531           emitcode ("inc", "dptr");
1532           aop->coff++;
1533         }
1534
1535       while (offset < aop->coff)
1536         {
1537           emitcode ("lcall", "__decdptr");
1538           aop->coff--;
1539         }
1540
1541       aop->coff = offset;
1542       if (aop->code)
1543         {
1544           emitcode ("clr", "a");
1545           emitcode ("movc", "a,@a+dptr");
1546         }
1547       else
1548         {
1549           emitcode ("movx", "a,@dptr");
1550         }
1551
1552       if (aop->type == AOP_DPTR2)
1553         {
1554           genSetDPTR (0);
1555         }
1556
1557       if (saveAcc)
1558         {
1559           TR_AP("#2");
1560           emitcode ("xch", "a, %s", saveAcc);
1561 //        if (strcmp(saveAcc, "_ap"))
1562 //          {
1563 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1564 //          }
1565
1566           return saveAcc;
1567         }
1568       return (dname ? "acc" : "a");
1569
1570     case AOP_IMMD:
1571       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1572         {
1573           SNPRINTF(buffer, sizeof(buffer),
1574                    "%s",aop->aopu.aop_immd.aop_immd2);
1575         }
1576       else if (bit16)
1577         {
1578           SNPRINTF(buffer, sizeof(buffer),
1579                    "#%s", aop->aopu.aop_immd.aop_immd1);
1580         }
1581       else if (offset)
1582         {
1583           switch (offset) {
1584           case 1:
1585               tsprintf(buffer, sizeof(buffer),
1586                        "#!his",aop->aopu.aop_immd.aop_immd1);
1587               break;
1588           case 2:
1589               tsprintf(buffer, sizeof(buffer),
1590                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1591               break;
1592           case 3:
1593               tsprintf(buffer, sizeof(buffer),
1594                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1595               break;
1596           default: /* should not need this (just in case) */
1597               SNPRINTF (buffer, sizeof(buffer),
1598                         "#(%s >> %d)",
1599                        aop->aopu.aop_immd.aop_immd1,
1600                        offset * 8);
1601           }
1602         }
1603       else
1604         {
1605           SNPRINTF (buffer, sizeof(buffer),
1606                     "#%s",
1607                     aop->aopu.aop_immd.aop_immd1);
1608         }
1609       return Safe_strdup(buffer);
1610
1611     case AOP_DIR:
1612       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1613         {
1614           SNPRINTF (buffer, sizeof(buffer),
1615                     "(%s >> %d)",
1616                     aop->aopu.aop_dir, offset * 8);
1617         }
1618       else if (offset)
1619         {
1620           SNPRINTF (buffer, sizeof(buffer),
1621                     "(%s + %d)",
1622                     aop->aopu.aop_dir,
1623                     offset);
1624         }
1625       else
1626         {
1627           SNPRINTF (buffer, sizeof(buffer),
1628                     "%s",
1629                     aop->aopu.aop_dir);
1630         }
1631
1632       return Safe_strdup(buffer);
1633
1634     case AOP_REG:
1635       if (dname)
1636         return aop->aopu.aop_reg[offset]->dname;
1637       else
1638         return aop->aopu.aop_reg[offset]->name;
1639
1640     case AOP_CRY:
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("clr", "a");
1643       emitcode ("rlc", "a");
1644       return (dname ? "acc" : "a");
1645
1646     case AOP_ACC:
1647       if (!offset && dname)
1648         return "acc";
1649       return aop->aopu.aop_str[offset];
1650
1651     case AOP_LIT:
1652       return aopLiteral (aop->aopu.aop_lit, offset);
1653
1654     case AOP_STR:
1655       aop->coff = offset;
1656       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1657           dname)
1658         return "acc";
1659
1660       return aop->aopu.aop_str[offset];
1661
1662     }
1663
1664   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1665           "aopget got unsupported aop->type");
1666   exit (1);
1667
1668   return NULL;  // not reached, but makes compiler happy.
1669 }
1670
1671 /*-----------------------------------------------------------------*/
1672 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1673 /*                 clobber the accumulator                         */
1674 /*-----------------------------------------------------------------*/
1675 static bool
1676 aopPutUsesAcc (operand * oper, const char *s, int offset)
1677 {
1678   asmop * aop = AOP (oper);
1679
1680   if (offset > (aop->size - 1))
1681     return FALSE;
1682
1683   switch (aop->type)
1684     {
1685     case AOP_DUMMY:
1686       return TRUE;
1687     case AOP_DIR:
1688       return FALSE;
1689     case AOP_REG:
1690       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1691       return FALSE;
1692     case AOP_DPTRn:
1693       return FALSE;
1694     case AOP_DPTR:
1695     case AOP_DPTR2:
1696       return TRUE;
1697     case AOP_R0:
1698     case AOP_R1:
1699       return ((aop->paged) || (*s == '@'));
1700     case AOP_STK:
1701       return (*s == '@');
1702     case AOP_CRY:
1703       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1704     case AOP_STR:
1705       return FALSE;
1706     case AOP_IMMD:
1707       return FALSE;
1708     case AOP_ACC:
1709       return FALSE;
1710     default:
1711       /* Error case --- will have been caught already */
1712       wassert(0);
1713       return FALSE;
1714     }
1715 }
1716
1717 /*-----------------------------------------------------------------*/
1718 /* aopPut - puts a string for a aop and indicates if acc is in use */
1719 /*-----------------------------------------------------------------*/
1720 static bool
1721 aopPut (operand * result, const char *s, int offset)
1722 {
1723   bool bvolatile = isOperandVolatile (result, FALSE);
1724   bool accuse = FALSE;
1725   asmop * aop = AOP (result);
1726   const char *d = NULL;
1727
1728   if (aop->size && offset > (aop->size - 1))
1729     {
1730       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1731               "aopPut got offset > aop->size");
1732       exit (1);
1733     }
1734
1735   /* will assign value to value */
1736   /* depending on where it is ofcourse */
1737   switch (aop->type)
1738     {
1739     case AOP_DUMMY:
1740       MOVA (s);         /* read s in case it was volatile */
1741       accuse = TRUE;
1742       break;
1743
1744     case AOP_DIR:
1745       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1746         {
1747           SNPRINTF (buffer, sizeof(buffer),
1748                     "(%s >> %d)",
1749                     aop->aopu.aop_dir, offset * 8);
1750         }
1751       else if (offset)
1752         {
1753           SNPRINTF (buffer, sizeof(buffer),
1754                     "(%s + %d)",
1755                     aop->aopu.aop_dir, offset);
1756         }
1757       else
1758         {
1759           SNPRINTF (buffer, sizeof(buffer),
1760                     "%s",
1761                     aop->aopu.aop_dir);
1762         }
1763
1764       if (strcmp (buffer, s) || bvolatile)
1765         {
1766           emitcode ("mov", "%s,%s", buffer, s);
1767         }
1768       if (!strcmp (buffer, "acc"))
1769         {
1770           accuse = TRUE;
1771         }
1772       break;
1773
1774     case AOP_REG:
1775       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1776           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1777         {
1778           if (*s == '@' ||
1779               strcmp (s, "r0") == 0 ||
1780               strcmp (s, "r1") == 0 ||
1781               strcmp (s, "r2") == 0 ||
1782               strcmp (s, "r3") == 0 ||
1783               strcmp (s, "r4") == 0 ||
1784               strcmp (s, "r5") == 0 ||
1785               strcmp (s, "r6") == 0 ||
1786               strcmp (s, "r7") == 0)
1787             {
1788               emitcode ("mov", "%s,%s",
1789                         aop->aopu.aop_reg[offset]->dname, s);
1790             }
1791           else
1792             {
1793               emitcode ("mov", "%s,%s",
1794                         aop->aopu.aop_reg[offset]->name, s);
1795             }
1796         }
1797       break;
1798
1799     case AOP_DPTRn:
1800         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1801         break;
1802
1803     case AOP_DPTR:
1804     case AOP_DPTR2:
1805
1806       if (aop->type == AOP_DPTR2)
1807         {
1808           genSetDPTR (1);
1809         }
1810       _flushLazyDPS ();
1811
1812       if (aop->code)
1813         {
1814           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1815                   "aopPut writing to code space");
1816           exit (1);
1817         }
1818
1819       while (offset > aop->coff)
1820         {
1821           aop->coff++;
1822           emitcode ("inc", "dptr");
1823         }
1824
1825       while (offset < aop->coff)
1826         {
1827           aop->coff--;
1828           emitcode ("lcall", "__decdptr");
1829         }
1830
1831       aop->coff = offset;
1832
1833       /* if not in accumulator */
1834       MOVA (s);
1835
1836       emitcode ("movx", "@dptr,a");
1837
1838       if (aop->type == AOP_DPTR2)
1839         {
1840           genSetDPTR (0);
1841         }
1842       break;
1843
1844     case AOP_R0:
1845     case AOP_R1:
1846       while (offset > aop->coff)
1847         {
1848           aop->coff++;
1849           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1850         }
1851       while (offset < aop->coff)
1852         {
1853           aop->coff--;
1854           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1855         }
1856       aop->coff = offset;
1857
1858       if (aop->paged)
1859         {
1860           MOVA (s);
1861           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1862         }
1863       else if (*s == '@')
1864         {
1865           MOVA (s);
1866           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1867         }
1868       else if (strcmp (s, "r0") == 0 ||
1869                strcmp (s, "r1") == 0 ||
1870                strcmp (s, "r2") == 0 ||
1871                strcmp (s, "r3") == 0 ||
1872                strcmp (s, "r4") == 0 ||
1873                strcmp (s, "r5") == 0 ||
1874                strcmp (s, "r6") == 0 ||
1875                strcmp (s, "r7") == 0)
1876         {
1877           char buffer[10];
1878           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1879           emitcode ("mov", "@%s,%s",
1880                     aop->aopu.aop_ptr->name, buffer);
1881         }
1882       else
1883         {
1884           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1885         }
1886       break;
1887
1888     case AOP_STK:
1889       if (strcmp (s, "a") == 0)
1890         {
1891           emitcode ("push", "acc");
1892         }
1893       else if (*s=='@')
1894         {
1895           MOVA(s);
1896           emitcode ("push", "acc");
1897         }
1898       else if (strcmp (s, "r0") == 0 ||
1899                strcmp (s, "r1") == 0 ||
1900                strcmp (s, "r2") == 0 ||
1901                strcmp (s, "r3") == 0 ||
1902                strcmp (s, "r4") == 0 ||
1903                strcmp (s, "r5") == 0 ||
1904                strcmp (s, "r6") == 0 ||
1905                strcmp (s, "r7") == 0)
1906         {
1907           char buffer[10];
1908           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1909           emitcode ("push", buffer);
1910         }
1911       else
1912         {
1913           emitcode ("push", s);
1914         }
1915
1916       break;
1917
1918     case AOP_CRY:
1919       // destination is carry for return-use-only
1920       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1921       
1922       // source is no literal and not in carry
1923       if ((s != zero) && (s != one) && strcmp (s, "c"))
1924         {
1925           MOVA (s);
1926           /* set C, if a >= 1 */
1927           emitcode ("add", "a,#!constbyte",0xff);
1928           s = "c";
1929         }
1930       // now source is zero, one or carry
1931
1932       /* if result no bit variable */
1933       if (!d)
1934         {
1935           if (!strcmp (s, "c"))
1936             {
1937               /* inefficient: move carry into A and use jz/jnz */
1938               emitcode ("clr", "a");
1939               emitcode ("rlc", "a");
1940               accuse = TRUE;
1941             }
1942           else
1943             {
1944               MOVA (s);
1945               accuse = TRUE;
1946             }
1947         }
1948       else if (s == zero)
1949           emitcode ("clr", "%s", d);
1950       else if (s == one)
1951           emitcode ("setb", "%s", d);
1952       else if (strcmp (s, d))
1953           emitcode ("mov", "%s,c", d);
1954       break;
1955
1956     case AOP_STR:
1957       aop->coff = offset;
1958       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1959         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1960       break;
1961
1962     case AOP_ACC:
1963       accuse = TRUE;
1964       aop->coff = offset;
1965       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1966         break;
1967
1968       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1969         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1970       break;
1971
1972     default:
1973       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1974               "aopPut got unsupported aop->type");
1975       exit (1);
1976     }
1977
1978     return accuse;
1979 }
1980
1981
1982 /*--------------------------------------------------------------------*/
1983 /* reAdjustPreg - points a register back to where it should (coff==0) */
1984 /*--------------------------------------------------------------------*/
1985 static void
1986 reAdjustPreg (asmop * aop)
1987 {
1988   if ((aop->coff==0) || (aop->size <= 1))
1989     return;
1990
1991   switch (aop->type)
1992     {
1993     case AOP_R0:
1994     case AOP_R1:
1995       while (aop->coff--)
1996         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1997       break;
1998     case AOP_DPTR:
1999     case AOP_DPTR2:
2000       if (aop->type == AOP_DPTR2)
2001         {
2002           genSetDPTR (1);
2003           _flushLazyDPS ();
2004         }
2005       while (aop->coff--)
2006         {
2007           emitcode ("lcall", "__decdptr");
2008         }
2009
2010       if (aop->type == AOP_DPTR2)
2011         {
2012           genSetDPTR (0);
2013         }
2014       break;
2015     }
2016   aop->coff = 0;
2017 }
2018
2019 /*-----------------------------------------------------------------*/
2020 /* opIsGptr: returns non-zero if the passed operand is             */
2021 /* a generic pointer type.                                         */
2022 /*-----------------------------------------------------------------*/
2023 static int
2024 opIsGptr (operand * op)
2025 {
2026   if (op && IS_GENPTR (operandType (op)) && (AOP_SIZE (op) == GPTRSIZE))
2027     {
2028       return 1;
2029     }
2030   return 0;
2031 }
2032
2033 /*-----------------------------------------------------------------*/
2034 /* getDataSize - get the operand data size                         */
2035 /*-----------------------------------------------------------------*/
2036 static int
2037 getDataSize (operand * op)
2038 {
2039   int size = AOP_SIZE (op);
2040
2041   if (size == GPTRSIZE)
2042     {
2043       sym_link *type = operandType (op);
2044       if (IS_GENPTR (type))
2045         {
2046           /* generic pointer; arithmetic operations
2047            * should ignore the high byte (pointer type).
2048            */
2049           size--;
2050         }
2051     }
2052   return size;
2053 }
2054
2055 /*-----------------------------------------------------------------*/
2056 /* outAcc - output Acc                                             */
2057 /*-----------------------------------------------------------------*/
2058 static void
2059 outAcc (operand * result)
2060 {
2061   int size, offset;
2062   size = getDataSize (result);
2063   if (size)
2064     {
2065       aopPut (result, "a", 0);
2066       size--;
2067       offset = 1;
2068       /* unsigned or positive */
2069       while (size--)
2070         {
2071           aopPut (result, zero, offset++);
2072         }
2073     }
2074 }
2075
2076 /*-----------------------------------------------------------------*/
2077 /* outBitC - output a bit C                                        */
2078 /*-----------------------------------------------------------------*/
2079 static void
2080 outBitC (operand * result)
2081 {
2082   /* if the result is bit */
2083   if (AOP_TYPE (result) == AOP_CRY)
2084     {
2085       aopPut (result, "c", 0);
2086     }
2087   else
2088     {
2089       emitcode ("clr", "a");
2090       emitcode ("rlc", "a");
2091       outAcc (result);
2092     }
2093 }
2094
2095 /*-----------------------------------------------------------------*/
2096 /* toBoolean - emit code for orl a,operator(sizeop)                */
2097 /*-----------------------------------------------------------------*/
2098 static void
2099 toBoolean (operand * oper)
2100 {
2101   int  size = AOP_SIZE (oper) - 1;
2102   int  offset = 1;
2103   bool pushedB;
2104
2105   /* The generic part of a generic pointer should
2106    * not participate in it's truth value.
2107    *
2108    * i.e. 0x10000000 is zero.
2109    */
2110   if (opIsGptr (oper))
2111     {
2112       D (emitcode (";", "toBoolean: generic ptr special case."));
2113       size--;
2114     }
2115
2116   _startLazyDPSEvaluation ();
2117   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2118   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2119     {
2120       pushedB = pushB ();
2121       emitcode("mov", "b,a");
2122       while (--size)
2123         {
2124           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2125           emitcode ("orl", "b,a");
2126         }
2127       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2128       emitcode ("orl", "a,b");
2129       popB (pushedB);
2130     }
2131   else
2132     {
2133       while (size--)
2134         {
2135           emitcode ("orl", "a,%s",
2136                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2137         }
2138     }
2139   _endLazyDPSEvaluation ();
2140 }
2141
2142
2143 /*-----------------------------------------------------------------*/
2144 /* genNot - generate code for ! operation                          */
2145 /*-----------------------------------------------------------------*/
2146 static void
2147 genNot (iCode * ic)
2148 {
2149   symbol *tlbl;
2150
2151   D (emitcode (";", "genNot"));
2152
2153   /* assign asmOps to operand & result */
2154   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2155   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2156
2157   /* if in bit space then a special case */
2158   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2159     {
2160       /* if left==result then cpl bit */
2161       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2162         {
2163           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2164         }
2165       else
2166         {
2167           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2168           emitcode ("cpl", "c");
2169           outBitC (IC_RESULT (ic));
2170         }
2171       goto release;
2172     }
2173
2174   toBoolean (IC_LEFT (ic));
2175
2176   /* set C, if a == 0 */
2177   tlbl = newiTempLabel (NULL);
2178   emitcode ("cjne", "a,#0x01,!tlabel", tlbl->key + 100);
2179   emitLabel (tlbl);
2180   outBitC (IC_RESULT (ic));
2181
2182 release:
2183   /* release the aops */
2184   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2185   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2186 }
2187
2188
2189 /*-----------------------------------------------------------------*/
2190 /* genCpl - generate code for complement                           */
2191 /*-----------------------------------------------------------------*/
2192 static void
2193 genCpl (iCode * ic)
2194 {
2195   int offset = 0;
2196   int size;
2197   symbol *tlbl;
2198   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2199
2200   D(emitcode (";", "genCpl"));
2201
2202   /* assign asmOps to operand & result */
2203   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2204   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2205
2206   /* special case if in bit space */
2207   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2208     {
2209       char *l;
2210
2211       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2212           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2213         {
2214           /* promotion rules are responsible for this strange result:
2215              bit -> int -> ~int -> bit
2216              uchar -> int -> ~int -> bit
2217           */
2218           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2219           goto release;
2220         }
2221
2222       tlbl=newiTempLabel(NULL);
2223       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2224       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2225           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2226           IS_AOP_PREG (IC_LEFT (ic)))
2227         {
2228           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2229         }
2230       else
2231         {
2232           MOVA (l);
2233           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2234         }
2235       emitLabel (tlbl);
2236       outBitC (IC_RESULT(ic));
2237       goto release;
2238     }
2239
2240   size = AOP_SIZE (IC_RESULT (ic));
2241   _startLazyDPSEvaluation ();
2242   while (size--)
2243     {
2244       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2245       MOVA (l);
2246       emitcode ("cpl", "a");
2247       aopPut (IC_RESULT (ic), "a", offset++);
2248     }
2249   _endLazyDPSEvaluation ();
2250
2251
2252 release:
2253   /* release the aops */
2254   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2255   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2256 }
2257
2258 /*-----------------------------------------------------------------*/
2259 /* genUminusFloat - unary minus for floating points                */
2260 /*-----------------------------------------------------------------*/
2261 static void
2262 genUminusFloat (operand * op, operand * result)
2263 {
2264   int size, offset = 0;
2265   char *l;
2266
2267   D (emitcode (";", "genUminusFloat"));
2268
2269   /* for this we just copy and then flip the bit */
2270
2271   _startLazyDPSEvaluation ();
2272   size = AOP_SIZE (op) - 1;
2273
2274   while (size--)
2275     {
2276       aopPut (result,
2277               aopGet (op, offset, FALSE, FALSE, NULL),
2278               offset);
2279       offset++;
2280     }
2281
2282   l = aopGet (op, offset, FALSE, FALSE, NULL);
2283   MOVA (l);
2284
2285   emitcode ("cpl", "acc.7");
2286   aopPut (result, "a", offset);
2287   _endLazyDPSEvaluation ();
2288 }
2289
2290 /*-----------------------------------------------------------------*/
2291 /* genUminus - unary minus code generation                         */
2292 /*-----------------------------------------------------------------*/
2293 static void
2294 genUminus (iCode * ic)
2295 {
2296   int offset, size;
2297   sym_link *optype;
2298
2299   D (emitcode (";", "genUminus"));
2300
2301   /* assign asmops */
2302   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2303   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2304
2305   /* if both in bit space then special
2306      case */
2307   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2308       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2309     {
2310
2311       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2312       emitcode ("cpl", "c");
2313       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2314       goto release;
2315     }
2316
2317   optype = operandType (IC_LEFT (ic));
2318
2319   /* if float then do float stuff */
2320   if (IS_FLOAT (optype))
2321     {
2322       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2323       goto release;
2324     }
2325
2326   /* otherwise subtract from zero */
2327   size = AOP_SIZE (IC_LEFT (ic));
2328   offset = 0;
2329   _startLazyDPSEvaluation ();
2330   while (size--)
2331     {
2332       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2333       if (!strcmp (l, "a"))
2334         {
2335           if (offset == 0)
2336             SETC;
2337           emitcode ("cpl", "a");
2338           emitcode ("addc", "a,#0x00");
2339         }
2340       else
2341         {
2342           if (offset == 0)
2343             CLRC;
2344           emitcode ("clr", "a");
2345           emitcode ("subb", "a,%s", l);
2346         }
2347       aopPut (IC_RESULT (ic), "a", offset++);
2348     }
2349   _endLazyDPSEvaluation ();
2350
2351   /* if any remaining bytes in the result */
2352   /* we just need to propagate the sign   */
2353   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2354     {
2355       emitcode ("rlc", "a");
2356       emitcode ("subb", "a,acc");
2357       while (size--)
2358         aopPut (IC_RESULT (ic), "a", offset++);
2359     }
2360
2361 release:
2362   /* release the aops */
2363   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2364   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2365 }
2366
2367 /*-----------------------------------------------------------------*/
2368 /* savermask - saves registers in the mask                         */
2369 /*-----------------------------------------------------------------*/
2370 static void savermask(bitVect *rs_mask)
2371 {
2372   int i;
2373
2374   if (options.useXstack)
2375     {
2376       if (bitVectBitValue (rs_mask, R0_IDX))
2377           emitcode ("mov", "b,r0");
2378       emitcode ("mov", "r0,%s", spname);
2379       for (i = 0; i < ds390_nRegs; i++)
2380         {
2381           if (bitVectBitValue (rs_mask, i))
2382             {
2383               if (i == R0_IDX)
2384                   emitcode ("mov", "a,b");
2385               else
2386                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2387               emitcode ("movx", "@r0,a");
2388               emitcode ("inc", "r0");
2389             }
2390         }
2391       emitcode ("mov", "%s,r0", spname);
2392       if (bitVectBitValue (rs_mask, R0_IDX))
2393           emitcode ("mov", "r0,b");
2394     }
2395   else
2396     {
2397       bool bits_pushed = FALSE;
2398       for (i = 0; i < ds390_nRegs; i++)
2399         {
2400           if (bitVectBitValue (rs_mask, i))
2401             {
2402               bits_pushed = pushReg (i, bits_pushed);
2403             }
2404         }
2405     }
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* saveRegisters - will look for a call and save the registers     */
2410 /*-----------------------------------------------------------------*/
2411 static void
2412 saveRegisters (iCode * lic)
2413 {
2414   iCode *ic;
2415   bitVect *rsave;
2416
2417   /* look for call */
2418   for (ic = lic; ic; ic = ic->next)
2419     if (ic->op == CALL || ic->op == PCALL)
2420       break;
2421
2422   if (!ic)
2423     {
2424       fprintf (stderr, "found parameter push with no function call\n");
2425       return;
2426     }
2427
2428   /* if the registers have been saved already or don't need to be then
2429      do nothing */
2430   if (ic->regsSaved
2431       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2432     return;
2433
2434   /* special case if DPTR alive across a function call then must save it
2435      even though callee saves */
2436   if (IS_SYMOP(IC_LEFT(ic)) &&
2437       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2438     {
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     }
2447   else
2448     {
2449       /* save the registers in use at this time but skip the
2450          ones for the result */
2451       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2452                              ds390_rUmaskForOp (IC_RESULT(ic)));
2453     }
2454   ic->regsSaved = 1;
2455   savermask(rsave);
2456 }
2457
2458 /*-----------------------------------------------------------------*/
2459 /* usavermask - restore registers with mask                        */
2460 /*-----------------------------------------------------------------*/
2461 static void unsavermask(bitVect *rs_mask)
2462 {
2463   int i;
2464
2465   if (options.useXstack)
2466     {
2467       emitcode ("mov", "r0,%s", spname);
2468       for (i = ds390_nRegs; i >= 0; i--)
2469         {
2470           if (bitVectBitValue (rs_mask, i))
2471             {
2472               regs * reg = REG_WITH_INDEX (i);
2473               emitcode ("dec", "r0");
2474               emitcode ("movx", "a,@r0");
2475               if (i == R0_IDX)
2476                 {
2477                   emitcode ("push", "acc");
2478                 }
2479               else
2480                 {
2481                   emitcode ("mov", "%s,a", reg->name);
2482                 }
2483             }
2484         }
2485       emitcode ("mov", "%s,r0", spname);
2486       if (bitVectBitValue (rs_mask, R0_IDX))
2487         {
2488           emitcode ("pop", "ar0");
2489         }
2490     }
2491   else
2492     {
2493       bool bits_popped = FALSE;
2494       for (i = ds390_nRegs; i >= 0; i--)
2495         {
2496           if (bitVectBitValue (rs_mask, i))
2497             {
2498               bits_popped = popReg (i, bits_popped);
2499             }
2500         }
2501     }
2502 }
2503
2504 /*-----------------------------------------------------------------*/
2505 /* unsaveRegisters - pop the pushed registers                      */
2506 /*-----------------------------------------------------------------*/
2507 static void
2508 unsaveRegisters (iCode * ic)
2509 {
2510   bitVect *rsave;
2511
2512   if (IS_SYMOP(IC_LEFT (ic)) &&
2513       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2514       int i;
2515       rsave = newBitVect(ic->rMask->size);
2516       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2517           if (bitVectBitValue(ic->rMask,i))
2518               rsave = bitVectSetBit(rsave,i);
2519       }
2520       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2521   } else {
2522     /* restore the registers in use at this time but skip the
2523        ones for the result */
2524     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2525                            ds390_rUmaskForOp (IC_RESULT(ic)));
2526   }
2527   unsavermask(rsave);
2528 }
2529
2530
2531 /*-----------------------------------------------------------------*/
2532 /* pushSide -                                                      */
2533 /*-----------------------------------------------------------------*/
2534 static void
2535 pushSide (operand * oper, int size, iCode * ic)
2536 {
2537   int offset = 0;
2538   int nPushed = _G.r0Pushed + _G.r1Pushed;
2539
2540   aopOp (oper, ic, FALSE, FALSE);
2541
2542   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2543     {
2544       while (offset < size)
2545         {
2546           char *l = aopGet (oper, offset, FALSE, TRUE, NULL);
2547           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2548         }
2549       freeAsmop (oper, NULL, ic, TRUE);
2550       offset = 0;
2551       while (offset < size)
2552         {
2553           emitcode ("push", "%s", fReturn[offset++]);
2554         }
2555       return;
2556     }
2557
2558   _startLazyDPSEvaluation ();
2559   while (size--)
2560     {
2561       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2562       if (AOP_TYPE (oper) != AOP_REG &&
2563           AOP_TYPE (oper) != AOP_DIR &&
2564           strcmp (l, "a"))
2565         {
2566           MOVA (l);
2567           emitcode ("push", "acc");
2568         }
2569       else
2570         {
2571           emitcode ("push", "%s", l);
2572         }
2573     }
2574   _endLazyDPSEvaluation ();
2575   freeAsmop (oper, NULL, ic, TRUE);
2576 }
2577
2578 /*-----------------------------------------------------------------*/
2579 /* assignResultValue - also indicates if acc is in use afterwards  */
2580 /*-----------------------------------------------------------------*/
2581 static bool
2582 assignResultValue (operand * oper, operand * func)
2583 {
2584   int offset = 0;
2585   unsigned size = AOP_SIZE (oper);
2586   bool accuse = FALSE;
2587   bool pushedA = FALSE;
2588
2589   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2590     {
2591       outBitC (oper);
2592       return FALSE;
2593     }
2594
2595   if (size == fReturnSizeDS390)
2596   {
2597       /* I don't think this case can ever happen... */
2598       /* ACC is the last part of this. If writing the result
2599        * uses ACC, we must preserve it.
2600        */
2601       if (AOP_NEEDSACC(oper))
2602       {
2603           emitcode(";", "assignResultValue special case for ACC.");
2604           emitcode("push", "acc");
2605           pushedA = TRUE;
2606           size--;
2607       }
2608   }
2609
2610   _startLazyDPSEvaluation ();
2611   while (size--)
2612     {
2613       accuse |= aopPut (oper, fReturn[offset], offset);
2614       offset++;
2615     }
2616   _endLazyDPSEvaluation ();
2617
2618   if (pushedA)
2619     {
2620         emitcode ("pop", "acc");
2621         accuse |= aopPut (oper, "a", offset);
2622     }
2623   return accuse;
2624 }
2625
2626
2627 /*-----------------------------------------------------------------*/
2628 /* genXpush - pushes onto the external stack                       */
2629 /*-----------------------------------------------------------------*/
2630 static void
2631 genXpush (iCode * ic)
2632 {
2633   asmop *aop = newAsmop (0);
2634   regs *r;
2635   int size, offset = 0;
2636
2637   D (emitcode (";", "genXpush"));
2638
2639   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2640   r = getFreePtr (ic, &aop, FALSE);
2641
2642   size = AOP_SIZE (IC_LEFT (ic));
2643
2644   if (size == 1)
2645     {
2646       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2647       emitcode ("mov", "%s,_spx", r->name);
2648       emitcode ("inc", "_spx"); // allocate space first
2649       emitcode ("movx", "@%s,a", r->name);
2650     }
2651   else
2652     {
2653       // allocate space first
2654       emitcode ("mov", "%s,_spx", r->name);
2655       MOVA (r->name);
2656       emitcode ("add", "a,#%d", size);
2657       emitcode ("mov", "_spx,a");
2658
2659       _startLazyDPSEvaluation ();
2660       while (size--)
2661         {
2662           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2663           emitcode ("movx", "@%s,a", r->name);
2664           emitcode ("inc", "%s", r->name);
2665         }
2666       _endLazyDPSEvaluation ();
2667     }
2668
2669   freeAsmop (NULL, aop, ic, TRUE);
2670   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2671 }
2672
2673 /*-----------------------------------------------------------------*/
2674 /* genIpush - generate code for pushing this gets a little complex */
2675 /*-----------------------------------------------------------------*/
2676 static void
2677 genIpush (iCode * ic)
2678 {
2679   int size, offset = 0;
2680   char *l;
2681   char *prev = "";
2682
2683   D (emitcode (";", "genIpush"));
2684
2685   /* if this is not a parm push : ie. it is spill push
2686      and spill push is always done on the local stack */
2687   if (!ic->parmPush)
2688     {
2689
2690       /* and the item is spilt then do nothing */
2691       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2692         return;
2693
2694       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2695       size = AOP_SIZE (IC_LEFT (ic));
2696       /* push it on the stack */
2697       _startLazyDPSEvaluation ();
2698       while (size--)
2699         {
2700           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2701           if (*l == '#')
2702             {
2703               MOVA (l);
2704               l = "acc";
2705             }
2706           emitcode ("push", "%s", l);
2707         }
2708       _endLazyDPSEvaluation ();
2709       return;
2710     }
2711
2712   /* this is a parameter push: in this case we call
2713      the routine to find the call and save those
2714      registers that need to be saved */
2715   saveRegisters (ic);
2716
2717   /* if use external stack then call the external
2718      stack pushing routine */
2719   if (options.useXstack)
2720     {
2721       genXpush (ic);
2722       return;
2723     }
2724
2725   /* then do the push */
2726   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2727
2728   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2729   size = AOP_SIZE (IC_LEFT (ic));
2730
2731   _startLazyDPSEvaluation ();
2732   while (size--)
2733     {
2734       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2735       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2736           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2737           strcmp (l, "acc"))
2738         {
2739           if (strcmp (l, prev) || *l == '@')
2740             MOVA (l);
2741           emitcode ("push", "acc");
2742         }
2743       else
2744         {
2745           emitcode ("push", "%s", l);
2746         }
2747       prev = l;
2748     }
2749   _endLazyDPSEvaluation ();
2750
2751   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2752 }
2753
2754 /*-----------------------------------------------------------------*/
2755 /* genIpop - recover the registers: can happen only for spilling   */
2756 /*-----------------------------------------------------------------*/
2757 static void
2758 genIpop (iCode * ic)
2759 {
2760   int size, offset;
2761
2762   D (emitcode (";", "genIpop"));
2763
2764   /* if the temp was not pushed then */
2765   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2766     return;
2767
2768   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2769   size = AOP_SIZE (IC_LEFT (ic));
2770   offset = (size - 1);
2771   _startLazyDPSEvaluation ();
2772   while (size--)
2773     {
2774       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2775                                      FALSE, TRUE, NULL));
2776     }
2777   _endLazyDPSEvaluation ();
2778
2779   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2780 }
2781
2782 /*-----------------------------------------------------------------*/
2783 /* popForBranch - recover the spilt registers for a branch         */
2784 /*-----------------------------------------------------------------*/
2785 static void
2786 popForBranch (iCode * ic, bool markGenerated)
2787 {
2788   while (ic && ic->op == IPOP)
2789     {
2790       genIpop (ic);
2791       if (markGenerated)
2792         ic->generated = 1;    /* mark the icode as generated */
2793       ic = ic->next;
2794     }
2795 }
2796
2797 /*-----------------------------------------------------------------*/
2798 /* saveRBank - saves an entire register bank on the stack          */
2799 /*-----------------------------------------------------------------*/
2800 static void
2801 saveRBank (int bank, iCode * ic, bool pushPsw)
2802 {
2803   int i;
2804   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2805   asmop *aop = NULL;
2806   regs *r = NULL;
2807
2808   if (options.useXstack)
2809     {
2810       if (!ic)
2811         {
2812           /* Assume r0 is available for use. */
2813           r = REG_WITH_INDEX (R0_IDX);
2814         }
2815       else
2816         {
2817           aop = newAsmop (0);
2818           r = getFreePtr (ic, &aop, FALSE);
2819         }
2820       // allocate space first
2821       emitcode ("mov", "%s,_spx", r->name);
2822       MOVA (r->name);
2823       emitcode ("add", "a,#%d", count);
2824       emitcode ("mov", "_spx,a");
2825     }
2826
2827   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2828     {
2829       if (options.useXstack)
2830         {
2831           emitcode ("mov", "a,(%s+%d)",
2832                     regs390[i].base, 8 * bank + regs390[i].offset);
2833           emitcode ("movx", "@%s,a", r->name);
2834           if (--count)
2835             emitcode ("inc", "%s", r->name);
2836         }
2837       else
2838         emitcode ("push", "(%s+%d)",
2839                   regs390[i].base, 8 * bank + regs390[i].offset);
2840     }
2841
2842   if (ds390_nBitRegs > 0)
2843     {
2844       if (options.useXstack)
2845         {
2846           emitcode ("mov", "a,bits");
2847           emitcode ("movx", "@%s,a", r->name);
2848           if (--count)
2849             emitcode ("inc", "%s", r->name);
2850         }
2851       else
2852         {
2853           emitcode ("push", "bits");
2854         }
2855       BitBankUsed = 1;
2856     }
2857
2858   if (pushPsw)
2859     {
2860       if (options.useXstack)
2861         {
2862           emitcode ("mov", "a,psw");
2863           emitcode ("movx", "@%s,a", r->name);
2864         }
2865       else
2866       {
2867         emitcode ("push", "psw");
2868       }
2869
2870       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2871     }
2872
2873   if (aop)
2874     {
2875       freeAsmop (NULL, aop, ic, TRUE);
2876     }
2877
2878   if (ic)
2879     {
2880       ic->bankSaved = 1;
2881     }
2882 }
2883
2884 /*-----------------------------------------------------------------*/
2885 /* unsaveRBank - restores the register bank from stack             */
2886 /*-----------------------------------------------------------------*/
2887 static void
2888 unsaveRBank (int bank, iCode * ic, bool popPsw)
2889 {
2890   int i;
2891   asmop *aop = NULL;
2892   regs *r = NULL;
2893
2894   if (options.useXstack)
2895     {
2896       if (!ic)
2897         {
2898           /* Assume r0 is available for use. */
2899           r = REG_WITH_INDEX (R0_IDX);
2900         }
2901       else
2902         {
2903           aop = newAsmop (0);
2904           r = getFreePtr (ic, &aop, FALSE);
2905         }
2906       emitcode ("mov", "%s,_spx", r->name);
2907     }
2908
2909   if (popPsw)
2910     {
2911       if (options.useXstack)
2912         {
2913           emitcode ("dec", "%s", r->name);
2914           emitcode ("movx", "a,@%s", r->name);
2915           emitcode ("mov", "psw,a");
2916         }
2917       else
2918       {
2919         emitcode ("pop", "psw");
2920       }
2921     }
2922
2923   if (ds390_nBitRegs > 0)
2924     {
2925       if (options.useXstack)
2926         {
2927           emitcode ("dec", "%s", r->name);
2928           emitcode ("movx", "a,@%s", r->name);
2929           emitcode ("mov", "bits,a");
2930         }
2931       else
2932         {
2933           emitcode ("pop", "bits");
2934         }
2935     }
2936
2937   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2938     {
2939       if (options.useXstack)
2940         {
2941           emitcode ("dec", "%s", r->name);
2942           emitcode ("movx", "a,@%s", r->name);
2943           emitcode ("mov", "(%s+%d),a",
2944                     regs390[i].base, 8 * bank + regs390[i].offset);
2945         }
2946       else
2947         {
2948           emitcode ("pop", "(%s+%d)",
2949                     regs390[i].base, 8 * bank + regs390[i].offset);
2950         }
2951     }
2952
2953   if (options.useXstack)
2954     {
2955       emitcode ("mov", "_spx,%s", r->name);
2956     }
2957
2958   if (aop)
2959     {
2960       freeAsmop (NULL, aop, ic, TRUE);
2961     }
2962 }
2963
2964 /*-----------------------------------------------------------------*/
2965 /* genSend - gen code for SEND                                     */
2966 /*-----------------------------------------------------------------*/
2967 static void genSend(set *sendSet)
2968 {
2969   iCode *sic;
2970   int bit_count = 0;
2971   int sendCount = 0 ;
2972   static int rb1_count = 0;
2973
2974   /* first we do all bit parameters */
2975   for (sic = setFirstItem (sendSet); sic;
2976        sic = setNextItem (sendSet))
2977     {
2978       if (sic->argreg > 12)
2979         {
2980           int bit = sic->argreg-13;
2981
2982           aopOp (IC_LEFT (sic), sic, FALSE,
2983                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2984
2985           /* if left is a literal then
2986              we know what the value is */
2987           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2988             {
2989               if (((int) operandLitValue (IC_LEFT (sic))))
2990                   emitcode ("setb", "b[%d]", bit);
2991               else
2992                   emitcode ("clr", "b[%d]", bit);
2993             }
2994           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2995             {
2996               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2997                 if (strcmp (l, "c"))
2998                     emitcode ("mov", "c,%s", l);
2999                 emitcode ("mov", "b[%d],c", bit);
3000             }
3001           else
3002             {
3003               /* we need to or */
3004               toBoolean (IC_LEFT (sic));
3005               /* set C, if a >= 1 */
3006               emitcode ("add", "a,#0xff");
3007               emitcode ("mov", "b[%d],c", bit);
3008             }
3009           bit_count++;
3010           BitBankUsed = 1;
3011
3012           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
3013         }
3014     }
3015
3016   if (bit_count)
3017     {
3018       saveRegisters (setFirstItem (sendSet));
3019       emitcode ("mov", "bits,b");
3020     }
3021
3022   /* then we do all other parameters */
3023   for (sic = setFirstItem (sendSet); sic;
3024        sic = setNextItem (sendSet))
3025     {
3026       if (sic->argreg <= 12)
3027         {
3028           int size, offset = 0;
3029
3030           size = getSize (operandType (IC_LEFT (sic)));
3031           D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
3032           if (sendCount == 0)
3033             { /* first parameter */
3034               // we know that dpl(hxb) is the result, so
3035               rb1_count = 0 ;
3036               _startLazyDPSEvaluation ();
3037               if (size>1)
3038                 {
3039                   aopOp (IC_LEFT (sic), sic, FALSE,
3040                          (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
3041                 }
3042               else
3043                 {
3044                   aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
3045                 }
3046               while (size--)
3047                 {
3048                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
3049                   if (strcmp (l, fReturn[offset]))
3050                     {
3051                       emitcode ("mov", "%s,%s", fReturn[offset], l);
3052                     }
3053                   offset++;
3054                 }
3055               _endLazyDPSEvaluation ();
3056               freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
3057               rb1_count =0;
3058             }
3059           else
3060             { /* if more parameter in registers */
3061               aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
3062               while (size--)
3063                 {
3064                   emitcode ("mov","b1_%d,%s",rb1_count++,
3065                             aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL));
3066                   offset++;
3067                 }
3068               freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
3069             }
3070           sendCount++;
3071         }
3072     }
3073 }
3074
3075 static void
3076 adjustEsp(const char *reg)
3077 {
3078     emitcode ("anl","%s,#3", reg);
3079     if (TARGET_IS_DS400)
3080     {
3081         emitcode ("orl","%s,#!constbyte",
3082                   reg,
3083                   (options.stack_loc >> 8) & 0xff);
3084     }
3085 }
3086
3087 /*-----------------------------------------------------------------*/
3088 /* selectRegBank - emit code to select the register bank           */
3089 /*-----------------------------------------------------------------*/
3090 static void
3091 selectRegBank (short bank, bool keepFlags)
3092 {
3093   /* if f.e. result is in carry */
3094   if (keepFlags)
3095     {
3096       emitcode ("anl", "psw,#0xE7");
3097       if (bank)
3098         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3099     }
3100   else
3101     {
3102       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3103     }
3104 }
3105
3106 /*-----------------------------------------------------------------*/
3107 /* genCall - generates a call statement                            */
3108 /*-----------------------------------------------------------------*/
3109 static void
3110 genCall (iCode * ic)
3111 {
3112   sym_link *dtype;
3113   sym_link *etype;
3114   bool restoreBank = FALSE;
3115   bool swapBanks = FALSE;
3116   bool accuse = FALSE;
3117   bool accPushed = FALSE;
3118   bool resultInF0 = FALSE;
3119   bool assignResultGenerated = FALSE;
3120
3121   D (emitcode (";", "genCall"));
3122
3123   /* if we are calling a not _naked function that is not using
3124      the same register bank then we need to save the
3125      destination registers on the stack */
3126   dtype = operandType (IC_LEFT (ic));
3127   etype = getSpec(dtype);
3128   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3129       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3130       IFFUNC_ISISR (currFunc->type))
3131   {
3132       if (!ic->bankSaved)
3133       {
3134            /* This is unexpected; the bank should have been saved in
3135             * genFunction.
3136             */
3137            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3138            restoreBank = TRUE;
3139       }
3140       swapBanks = TRUE;
3141   }
3142
3143   /* if caller saves & we have not saved then */
3144   if (!ic->regsSaved)
3145       saveRegisters (ic);
3146
3147   /* if send set is not empty then assign */
3148   /* We've saved all the registers we care about;
3149   * therefore, we may clobber any register not used
3150   * in the calling convention (i.e. anything not in
3151   * fReturn.
3152   */
3153   if (_G.sendSet)
3154     {
3155         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3156             genSend(reverseSet(_G.sendSet));
3157         } else {
3158             genSend(_G.sendSet);
3159         }
3160       _G.sendSet = NULL;
3161     }
3162
3163   if (swapBanks)
3164     {
3165       emitcode ("mov", "psw,#!constbyte",
3166          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3167     }
3168
3169   /* make the call */
3170   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3171                             OP_SYMBOL (IC_LEFT (ic))->rname :
3172                             OP_SYMBOL (IC_LEFT (ic))->name));
3173
3174   if (swapBanks)
3175     {
3176       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3177     }
3178
3179   /* if we need assign a result value */
3180   if ((IS_ITEMP (IC_RESULT (ic)) &&
3181        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3182        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3183         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3184         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3185       IS_TRUE_SYMOP (IC_RESULT (ic)))
3186     {
3187       if (isOperandInFarSpace (IC_RESULT (ic))
3188           && getSize (operandType (IC_RESULT (ic))) <= 2)
3189         {
3190           int size = getSize (operandType (IC_RESULT (ic)));
3191           bool pushedB = FALSE;
3192
3193           /* Special case for 1 or 2 byte return in far space. */
3194           MOVA (fReturn[0]);
3195           if (size > 1)
3196             {
3197               pushedB = pushB ();
3198               emitcode ("mov", "b,%s", fReturn[1]);
3199             }
3200
3201           _G.accInUse++;
3202           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3203           _G.accInUse--;
3204
3205           popB (pushedB);
3206
3207           aopPut (IC_RESULT (ic), "a", 0);
3208
3209           if (size > 1)
3210             {
3211               aopPut (IC_RESULT (ic), "b", 1);
3212             }
3213           assignResultGenerated = TRUE;
3214           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3215         }
3216       else
3217         {
3218           bool pushedB = pushB ();
3219           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3220           popB (pushedB);
3221
3222           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3223           assignResultGenerated = TRUE;
3224           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3225         }
3226     }
3227
3228   /* adjust the stack for parameters if required */
3229   if (ic->parmBytes)
3230     {
3231       int i;
3232       if (options.stack10bit) {
3233           if (ic->parmBytes <= 10) {
3234               emitcode(";","stack adjustment for parms");
3235               for (i=0; i < ic->parmBytes ; i++) {
3236                   emitcode("pop","acc");
3237               }
3238           } else {
3239               PROTECT_SP;
3240               emitcode ("clr","c");
3241               emitcode ("mov","a,sp");
3242               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3243               emitcode ("mov","sp,a");
3244               emitcode ("mov","a,esp");
3245               adjustEsp("a");
3246               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3247               emitcode ("mov","esp,a");
3248               UNPROTECT_SP;
3249           }
3250       } else {
3251           if (ic->parmBytes > 3)
3252             {
3253               if (accuse)
3254                 {
3255                   emitcode ("push", "acc");
3256                   accPushed = TRUE;
3257                 }
3258               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3259                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3260                   !assignResultGenerated)
3261                 {
3262                   emitcode ("mov", "F0,c");
3263                   resultInF0 = TRUE;
3264                 }
3265
3266               emitcode ("mov", "a,%s", spname);
3267               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3268               emitcode ("mov", "%s,a", spname);
3269
3270               /* unsaveRegisters from xstack needs acc, but */
3271               /* unsaveRegisters from stack needs this popped */
3272               if (accPushed && !options.useXstack)
3273                 {
3274                   emitcode ("pop", "acc");
3275                   accPushed = FALSE;
3276                 }
3277             }
3278           else
3279               for (i = 0; i < ic->parmBytes; i++)
3280                   emitcode ("dec", "%s", spname);
3281       }
3282   }
3283
3284   /* if we had saved some registers then unsave them */
3285   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3286     {
3287       if (accuse && !accPushed && options.useXstack)
3288         {
3289           /* xstack needs acc, but doesn't touch normal stack */
3290           emitcode ("push", "acc");
3291           accPushed = TRUE;
3292         }
3293       unsaveRegisters (ic);
3294     }
3295
3296   /* if register bank was saved then pop them */
3297   if (restoreBank)
3298     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3299
3300   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3301     {
3302       if (resultInF0)
3303           emitcode ("mov", "c,F0");
3304
3305       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3306       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3307       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3308     }
3309
3310   if (accPushed)
3311     emitcode ("pop", "acc");
3312 }
3313
3314 /*-----------------------------------------------------------------*/
3315 /* genPcall - generates a call by pointer statement                */
3316 /*-----------------------------------------------------------------*/
3317 static void
3318 genPcall (iCode * ic)
3319 {
3320   sym_link *dtype;
3321   sym_link *etype;
3322   symbol *rlbl = newiTempLabel (NULL);
3323   bool restoreBank=FALSE;
3324   bool resultInF0 = FALSE;
3325
3326   D (emitcode (";", "genPcall"));
3327
3328   dtype = operandType (IC_LEFT (ic))->next;
3329   etype = getSpec(dtype);
3330   /* if caller saves & we have not saved then */
3331   if (!ic->regsSaved)
3332     saveRegisters (ic);
3333
3334   /* if we are calling a not _naked function that is not using
3335      the same register bank then we need to save the
3336      destination registers on the stack */
3337   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3338       IFFUNC_ISISR (currFunc->type) &&
3339       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3340     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3341     restoreBank=TRUE;
3342   }
3343
3344   /* push the return address on to the stack */
3345   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3346   emitcode ("push", "acc");
3347   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3348   emitcode ("push", "acc");
3349
3350   if (options.model == MODEL_FLAT24)
3351     {
3352       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3353       emitcode ("push", "acc");
3354     }
3355
3356   /* now push the function address */
3357   pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3358
3359   /* if send set is not empty then assign */
3360   if (_G.sendSet)
3361     {
3362         genSend(reverseSet(_G.sendSet));
3363         _G.sendSet = NULL;
3364     }
3365
3366   /* make the call */
3367   emitcode ("ret", "");
3368   emitLabel (rlbl);
3369
3370
3371   /* if we need assign a result value */
3372   if ((IS_ITEMP (IC_RESULT (ic)) &&
3373        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3374        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3375         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3376       IS_TRUE_SYMOP (IC_RESULT (ic)))
3377     {
3378
3379       _G.accInUse++;
3380       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3381       _G.accInUse--;
3382
3383       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3384
3385       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3386     }
3387
3388   /* adjust the stack for parameters if required */
3389   if (ic->parmBytes)
3390     {
3391       int i;
3392       if (options.stack10bit) {
3393           if (ic->parmBytes <= 10) {
3394               emitcode(";","stack adjustment for parms");
3395               for (i=0; i < ic->parmBytes ; i++) {
3396                   emitcode("pop","acc");
3397               }
3398           } else {
3399               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3400                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3401                 {
3402                   emitcode ("mov", "F0,c");
3403                   resultInF0 = TRUE;
3404                 }
3405
3406               PROTECT_SP;
3407               emitcode ("clr","c");
3408               emitcode ("mov","a,sp");
3409               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3410               emitcode ("mov","sp,a");
3411               emitcode ("mov","a,esp");
3412               adjustEsp("a");
3413               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3414               emitcode ("mov","esp,a");
3415               UNPROTECT_SP;
3416           }
3417       } else {
3418           if (ic->parmBytes > 3) {
3419               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3420                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3421                 {
3422                   emitcode ("mov", "F0,c");
3423                   resultInF0 = TRUE;
3424                 }
3425
3426               emitcode ("mov", "a,%s", spname);
3427               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3428               emitcode ("mov", "%s,a", spname);
3429           }
3430           else
3431               for (i = 0; i < ic->parmBytes; i++)
3432                   emitcode ("dec", "%s", spname);
3433       }
3434     }
3435   /* if register bank was saved then unsave them */
3436   if (restoreBank)
3437     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3438
3439   /* if we had saved some registers then unsave them */
3440   if (ic->regsSaved)
3441     unsaveRegisters (ic);
3442
3443   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3444     {
3445       if (resultInF0)
3446           emitcode ("mov", "c,F0");
3447
3448       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3449       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3450       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3451     }
3452 }
3453
3454 /*-----------------------------------------------------------------*/
3455 /* resultRemat - result  is rematerializable                       */
3456 /*-----------------------------------------------------------------*/
3457 static int
3458 resultRemat (iCode * ic)
3459 {
3460   if (SKIP_IC (ic) || ic->op == IFX)
3461     return 0;
3462
3463   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3464     {
3465       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3466       if (sym->remat && !POINTER_SET (ic))
3467         return 1;
3468     }
3469
3470   return 0;
3471 }
3472
3473 /*-----------------------------------------------------------------*/
3474 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3475 /*-----------------------------------------------------------------*/
3476 static int
3477 regsCmp(void *p1, void *p2)
3478 {
3479   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3480 }
3481
3482 static bool
3483 inExcludeList (char *s)
3484 {
3485   const char *p = setFirstItem(options.excludeRegsSet);
3486
3487   if (p == NULL || STRCASECMP(p, "none") == 0)
3488     return FALSE;
3489
3490
3491   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3492 }
3493
3494 /*-----------------------------------------------------------------*/
3495 /* genFunction - generated code for function entry                 */
3496 /*-----------------------------------------------------------------*/
3497 static void
3498 genFunction (iCode * ic)
3499 {
3500   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3501   sym_link *ftype;
3502   bool     switchedPSW = FALSE;
3503   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3504
3505   D (emitcode (";", "genFunction"));
3506
3507   _G.nRegsSaved = 0;
3508   /* create the function header */
3509   emitcode (";", "-----------------------------------------");
3510   emitcode (";", " function %s", sym->name);
3511   emitcode (";", "-----------------------------------------");
3512
3513   emitcode ("", "%s:", sym->rname);
3514   lineCurr->isLabel = 1;
3515   ftype = operandType (IC_LEFT (ic));
3516   _G.currentFunc = sym;
3517
3518   if (IFFUNC_ISNAKED(ftype))
3519   {
3520       emitcode(";", "naked function: no prologue.");
3521       return;
3522   }
3523
3524   if (options.stack_probe)
3525       emitcode ("lcall","__stack_probe");
3526
3527   /* here we need to generate the equates for the
3528      register bank if required */
3529   if (FUNC_REGBANK (ftype) != rbank)
3530     {
3531       int i;
3532
3533       rbank = FUNC_REGBANK (ftype);
3534       for (i = 0; i < ds390_nRegs; i++)
3535         {
3536           if (regs390[i].print) {
3537               if (strcmp (regs390[i].base, "0") == 0)
3538                   emitcode ("", "%s !equ !constbyte",
3539                             regs390[i].dname,
3540                             8 * rbank + regs390[i].offset);
3541               else
3542                   emitcode ("", "%s !equ %s + !constbyte",
3543                             regs390[i].dname,
3544                             regs390[i].base,
3545                             8 * rbank + regs390[i].offset);
3546           }
3547         }
3548     }
3549
3550   /* if this is an interrupt service routine then
3551      save acc, b, dpl, dph  */
3552   if (IFFUNC_ISISR (sym->type))
3553     { /* is ISR */
3554       if (!inExcludeList ("acc"))
3555         emitcode ("push", "acc");
3556       if (!inExcludeList ("b"))
3557         emitcode ("push", "b");
3558       if (!inExcludeList ("dpl"))
3559         emitcode ("push", "dpl");
3560       if (!inExcludeList ("dph"))
3561         emitcode ("push", "dph");
3562       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3563         {
3564           emitcode ("push", "dpx");
3565           /* Make sure we're using standard DPTR */
3566           emitcode ("push", "dps");
3567           emitcode ("mov", "dps,#0");
3568           if (options.stack10bit)
3569             {
3570               /* This ISR could conceivably use DPTR2. Better save it. */
3571               emitcode ("push", "dpl1");
3572               emitcode ("push", "dph1");
3573               emitcode ("push", "dpx1");
3574               emitcode ("push",  DP2_RESULT_REG);
3575             }
3576         }
3577       /* if this isr has no bank i.e. is going to
3578          run with bank 0 , then we need to save more
3579          registers :-) */
3580       if (!FUNC_REGBANK (sym->type))
3581         {
3582           int i;
3583
3584           /* if this function does not call any other
3585              function then we can be economical and
3586              save only those registers that are used */
3587           if (!IFFUNC_HASFCALL(sym->type))
3588             {
3589               /* if any registers used */
3590               if (sym->regsUsed)
3591                 {
3592                   bool bits_pushed = FALSE;
3593                   /* save the registers used */
3594                   for (i = 0; i < sym->regsUsed->size; i++)
3595                     {
3596                       if (bitVectBitValue (sym->regsUsed, i))
3597                         bits_pushed = pushReg (i, bits_pushed);
3598                     }
3599                 }
3600             }
3601           else
3602             {
3603               /* this function has a function call. We cannot
3604                  determine register usage so we will have to push the
3605                  entire bank */
3606               saveRBank (0, ic, FALSE);
3607               if (options.parms_in_bank1)
3608                 {
3609                   for (i=0; i < 8 ; i++ )
3610                     {
3611                       emitcode ("push","%s",rb1regs[i]);
3612                     }
3613                 }
3614             }
3615         }
3616       else
3617         {
3618             /* This ISR uses a non-zero bank.
3619              *
3620              * We assume that the bank is available for our
3621              * exclusive use.
3622              *
3623              * However, if this ISR calls a function which uses some
3624              * other bank, we must save that bank entirely.
3625              */
3626             unsigned long banksToSave = 0;
3627
3628             if (IFFUNC_HASFCALL(sym->type))
3629             {
3630
3631 #define MAX_REGISTER_BANKS 4
3632
3633                 iCode *i;
3634                 int ix;
3635
3636                 for (i = ic; i; i = i->next)
3637                 {
3638                     if (i->op == ENDFUNCTION)
3639                     {
3640                         /* we got to the end OK. */
3641                         break;
3642                     }
3643
3644                     if (i->op == CALL)
3645                     {
3646                         sym_link *dtype;
3647
3648                         dtype = operandType (IC_LEFT(i));
3649                         if (dtype
3650                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3651                         {
3652                              /* Mark this bank for saving. */
3653                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3654                              {
3655                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3656                              }
3657                              else
3658                              {
3659                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3660                              }
3661
3662                              /* And note that we don't need to do it in
3663                               * genCall.
3664                               */
3665                              i->bankSaved = 1;
3666                         }
3667                     }
3668                     if (i->op == PCALL)
3669                     {
3670                         /* This is a mess; we have no idea what
3671                          * register bank the called function might
3672                          * use.
3673                          *
3674                          * The only thing I can think of to do is
3675                          * throw a warning and hope.
3676                          */
3677                         werror(W_FUNCPTR_IN_USING_ISR);
3678                     }
3679                 }
3680
3681                 if (banksToSave && options.useXstack)
3682                 {
3683                     /* Since we aren't passing it an ic,
3684                      * saveRBank will assume r0 is available to abuse.
3685                      *
3686                      * So switch to our (trashable) bank now, so
3687                      * the caller's R0 isn't trashed.
3688                      */
3689                     emitcode ("push", "psw");
3690                     emitcode ("mov", "psw,#!constbyte",
3691                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3692                     switchedPSW = TRUE;
3693                 }
3694
3695                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3696                 {
3697                      if (banksToSave & (1 << ix))
3698                      {
3699                          saveRBank(ix, NULL, FALSE);
3700                      }
3701                 }
3702             }
3703             // TODO: this needs a closer look
3704             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3705         }
3706     }
3707   else
3708     {
3709       /* if callee-save to be used for this function
3710          then save the registers being used in this function */
3711       if (IFFUNC_CALLEESAVES(sym->type))
3712         {
3713           int i;
3714
3715           /* if any registers used */
3716           if (sym->regsUsed)
3717             {
3718               bool bits_pushed = FALSE;
3719               /* save the registers used */
3720               for (i = 0; i < sym->regsUsed->size; i++)
3721                 {
3722                   if (bitVectBitValue (sym->regsUsed, i))
3723                     {
3724                       bits_pushed = pushReg (i, bits_pushed);
3725                       _G.nRegsSaved++;
3726                     }
3727                 }
3728             }
3729         }
3730     }
3731
3732   /* set the register bank to the desired value */
3733   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3734    && !switchedPSW)
3735     {
3736       emitcode ("push", "psw");
3737       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3738     }
3739
3740   if (fReentrant &&
3741        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3742       if (options.stack10bit) {
3743           emitcode ("push","_bpx");
3744           emitcode ("push","_bpx+1");
3745           emitcode ("mov","_bpx,%s",spname);
3746           emitcode ("mov","_bpx+1,esp");
3747           adjustEsp("_bpx+1");
3748       } else {
3749           if (options.useXstack)
3750           {
3751               emitcode ("mov", "r0,%s", spname);
3752               emitcode ("mov", "a,_bp");
3753               emitcode ("movx", "@r0,a");
3754               emitcode ("inc", "%s", spname);
3755           } else {
3756               /* set up the stack */
3757               emitcode ("push", "_bp"); /* save the callers stack  */
3758           }
3759           emitcode ("mov", "_bp,%s", spname);
3760       }
3761   }
3762
3763   /* adjust the stack for the function */
3764   if (sym->stack) {
3765       int i = sym->stack;
3766       if (options.stack10bit) {
3767           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3768           assert (sym->recvSize <= 4);
3769           if (sym->stack <= 8) {
3770               while (i--) emitcode ("push","acc");
3771           } else {
3772               PROTECT_SP;
3773               emitcode ("mov","a,sp");
3774               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3775               emitcode ("mov","sp,a");
3776               emitcode ("mov","a,esp");
3777               adjustEsp("a");
3778               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3779               emitcode ("mov","esp,a");
3780               UNPROTECT_SP;
3781           }
3782       } else {
3783           if (i > 256)
3784               werror (W_STACK_OVERFLOW, sym->name);
3785
3786           if (i > 3 && sym->recvSize < 4) {
3787
3788               emitcode ("mov", "a,sp");
3789               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3790               emitcode ("mov", "sp,a");
3791
3792           } else
3793               while (i--)
3794                   emitcode ("inc", "sp");
3795       }
3796   }
3797
3798   if (sym->xstack)
3799     {
3800
3801       emitcode ("mov", "a,_spx");
3802       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3803       emitcode ("mov", "_spx,a");
3804     }
3805
3806   /* if critical function then turn interrupts off */
3807   if (IFFUNC_ISCRITICAL (ftype))
3808     {
3809       symbol *tlbl = newiTempLabel (NULL);
3810       emitcode ("setb", "c");
3811       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3812       emitcode ("clr", "c");
3813       emitLabel (tlbl);
3814       emitcode ("push", "psw"); /* save old ea via c in psw */
3815     }
3816 }
3817
3818 /*-----------------------------------------------------------------*/
3819 /* genEndFunction - generates epilogue for functions               */
3820 /*-----------------------------------------------------------------*/
3821 static void
3822 genEndFunction (iCode * ic)
3823 {
3824   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3825   lineNode *lnp = lineCurr;
3826   bitVect  *regsUsed;
3827   bitVect  *regsUsedPrologue;
3828   bitVect  *regsUnneeded;
3829   int      idx;
3830
3831   D (emitcode (";", "genEndFunction"));
3832
3833   _G.currentFunc = NULL;
3834   if (IFFUNC_ISNAKED(sym->type))
3835   {
3836       emitcode(";", "naked function: no epilogue.");
3837       if (options.debug && currFunc)
3838         debugFile->writeEndFunction (currFunc, ic, 0);
3839       return;
3840   }
3841
3842   if (IFFUNC_ISCRITICAL (sym->type))
3843     {
3844       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3845         {
3846           emitcode ("rlc", "a");   /* save c in a */
3847           emitcode ("pop", "psw"); /* restore ea via c in psw */
3848           emitcode ("mov", "ea,c");
3849           emitcode ("rrc", "a");   /* restore c from a */
3850         }
3851       else
3852         {
3853           emitcode ("pop", "psw"); /* restore ea via c in psw */
3854           emitcode ("mov", "ea,c");
3855         }
3856     }
3857
3858   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3859        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3860
3861       if (options.stack10bit) {
3862           PROTECT_SP;
3863           emitcode ("mov", "sp,_bpx", spname);
3864           emitcode ("mov", "esp,_bpx+1", spname);
3865           UNPROTECT_SP;
3866       } else {
3867           emitcode ("mov", "%s,_bp", spname);
3868       }
3869   }
3870
3871   /* if use external stack but some variables were
3872      added to the local stack then decrement the
3873      local stack */
3874   if (options.useXstack && sym->stack) {
3875       emitcode ("mov", "a,sp");
3876       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3877       emitcode ("mov", "sp,a");
3878   }
3879
3880
3881   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3882        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3883
3884       if (options.useXstack) {
3885           emitcode ("mov", "r0,%s", spname);
3886           emitcode ("movx", "a,@r0");
3887           emitcode ("mov", "_bp,a");
3888           emitcode ("dec", "%s", spname);
3889       } else {
3890           if (options.stack10bit) {
3891               emitcode ("pop", "_bpx+1");
3892               emitcode ("pop", "_bpx");
3893           } else {
3894               emitcode ("pop", "_bp");
3895           }
3896       }
3897   }
3898
3899   /* restore the register bank  */
3900   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3901   {
3902     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3903      || !options.useXstack)
3904     {
3905         /* Special case of ISR using non-zero bank with useXstack
3906          * is handled below.
3907          */
3908         emitcode ("pop", "psw");
3909     }
3910   }
3911
3912   if (IFFUNC_ISISR (sym->type))
3913     { /* is ISR */
3914
3915       /* now we need to restore the registers */
3916       /* if this isr has no bank i.e. is going to
3917          run with bank 0 , then we need to save more
3918          registers :-) */
3919       if (!FUNC_REGBANK (sym->type))
3920         {
3921           int i;
3922           /* if this function does not call any other
3923              function then we can be economical and
3924              save only those registers that are used */
3925           if (!IFFUNC_HASFCALL(sym->type))
3926             {
3927               /* if any registers used */
3928               if (sym->regsUsed)
3929                 {
3930                   bool bits_popped = FALSE;
3931                   /* save the registers used */
3932                   for (i = sym->regsUsed->size; i >= 0; i--)
3933                     {
3934                       if (bitVectBitValue (sym->regsUsed, i))
3935                         bits_popped = popReg (i, bits_popped);
3936                     }
3937                 }
3938             }
3939           else
3940             {
3941               /* this function has a function call. We cannot
3942                  determine register usage so we will have to pop the
3943                  entire bank */
3944               if (options.parms_in_bank1)
3945                 {
3946                   for (i = 7 ; i >= 0 ; i-- )
3947                     {
3948                       emitcode ("pop","%s",rb1regs[i]);
3949                     }
3950                 }
3951               unsaveRBank (0, ic, FALSE);
3952             }
3953         }
3954       else
3955         {
3956             /* This ISR uses a non-zero bank.
3957              *
3958              * Restore any register banks saved by genFunction
3959              * in reverse order.
3960              */
3961             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3962             int ix;
3963
3964             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3965             {
3966                 if (savedBanks & (1 << ix))
3967                 {
3968                     unsaveRBank(ix, NULL, FALSE);
3969                 }
3970             }
3971
3972             if (options.useXstack)
3973             {
3974                 /* Restore bank AFTER calling unsaveRBank,
3975                  * since it can trash r0.
3976                  */
3977                 emitcode ("pop", "psw");
3978             }
3979         }
3980
3981       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3982         {
3983           if (options.stack10bit)
3984             {
3985               emitcode ("pop", DP2_RESULT_REG);
3986               emitcode ("pop", "dpx1");
3987               emitcode ("pop", "dph1");
3988               emitcode ("pop", "dpl1");
3989             }
3990           emitcode ("pop", "dps");
3991           emitcode ("pop", "dpx");
3992         }
3993       if (!inExcludeList ("dph"))
3994         emitcode ("pop", "dph");
3995       if (!inExcludeList ("dpl"))
3996         emitcode ("pop", "dpl");
3997       if (!inExcludeList ("b"))
3998         emitcode ("pop", "b");
3999       if (!inExcludeList ("acc"))
4000         emitcode ("pop", "acc");
4001
4002       /* if debug then send end of function */
4003       if (options.debug && currFunc)
4004         {
4005           debugFile->writeEndFunction (currFunc, ic, 1);
4006         }
4007
4008       emitcode ("reti", "");
4009     }
4010   else
4011     {
4012       if (IFFUNC_CALLEESAVES(sym->type))
4013         {
4014           int i;
4015
4016           /* if any registers used */
4017           if (sym->regsUsed)
4018             {
4019               /* save the registers used */
4020               for (i = sym->regsUsed->size; i >= 0; i--)
4021                 {
4022                   if (bitVectBitValue (sym->regsUsed, i))
4023                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
4024                 }
4025             }
4026         }
4027
4028       /* if debug then send end of function */
4029       if (options.debug && currFunc)
4030         {
4031           debugFile->writeEndFunction (currFunc, ic, 1);
4032         }
4033
4034       emitcode ("ret", "");
4035     }
4036
4037   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
4038     return;
4039
4040   /* If this was an interrupt handler using bank 0 that called another */
4041   /* function, then all registers must be saved; nothing to optimized. */
4042   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
4043       && !FUNC_REGBANK(sym->type))
4044     return;
4045
4046   /* There are no push/pops to optimize if not callee-saves or ISR */
4047   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
4048     return;
4049
4050   /* If there were stack parameters, we cannot optimize without also    */
4051   /* fixing all of the stack offsets; this is too dificult to consider. */
4052   if (FUNC_HASSTACKPARM(sym->type))
4053     return;
4054
4055   /* Compute the registers actually used */
4056   regsUsed = newBitVect (ds390_nRegs);
4057   regsUsedPrologue = newBitVect (ds390_nRegs);
4058   while (lnp)
4059     {
4060       if (lnp->ic && lnp->ic->op == FUNCTION)
4061         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
4062       else
4063         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
4064
4065       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
4066           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
4067         break;
4068       if (!lnp->prev)
4069         break;
4070       lnp = lnp->prev;
4071     }
4072
4073   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
4074       && !bitVectBitValue (regsUsed, DPS_IDX))
4075     {
4076       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
4077     }
4078
4079   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
4080       && !bitVectBitValue (regsUsed, CND_IDX))
4081     {
4082       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4083       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4084           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4085         bitVectUnSetBit (regsUsed, CND_IDX);
4086     }
4087   else
4088     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4089
4090   /* If this was an interrupt handler that called another function */
4091   /* function, then assume working registers may be modified by it. */
4092   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4093     {
4094       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
4095       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
4096       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
4097       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
4098       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
4099       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4100       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4101       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4102       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4103       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4104       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4105     }
4106
4107   /* Remove the unneeded push/pops */
4108   regsUnneeded = newBitVect (ds390_nRegs);
4109   while (lnp)
4110     {
4111       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4112         {
4113           if (!strncmp(lnp->line, "push", 4))
4114             {
4115               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4116               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4117                 {
4118                   connectLine (lnp->prev, lnp->next);
4119                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4120                 }
4121             }
4122           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4123             {
4124               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4125               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4126                 {
4127                   connectLine (lnp->prev, lnp->next);
4128                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4129                 }
4130             }
4131         }
4132       lnp = lnp->next;
4133     }
4134
4135   for (idx = 0; idx < regsUnneeded->size; idx++)
4136     if (bitVectBitValue (regsUnneeded, idx))
4137       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4138
4139   freeBitVect (regsUnneeded);
4140   freeBitVect (regsUsed);
4141   freeBitVect (regsUsedPrologue);
4142 }
4143
4144 /*-----------------------------------------------------------------*/
4145 /* genJavaNativeRet - generate code for return JavaNative          */
4146 /*-----------------------------------------------------------------*/
4147 static void genJavaNativeRet(iCode *ic)
4148 {
4149     int i, size;
4150
4151     aopOp (IC_LEFT (ic), ic, FALSE,
4152            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4153     size = AOP_SIZE (IC_LEFT (ic));
4154
4155     assert (size <= 4);
4156
4157     /* it is assigned to GPR0-R3 then push them */
4158     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4159         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4160         for (i = 0 ; i < size ; i++ ) {
4161             emitcode ("push","%s",
4162                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4163         }
4164         for (i = (size-1) ; i >= 0 ; i--) {
4165             emitcode ("pop","a%s",javaRet[i]);
4166         }
4167     } else {
4168         for (i = 0 ; i < size ; i++)
4169             emitcode ("mov","%s,%s",javaRet[i],
4170                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4171     }
4172     for (i = size ; i < 4 ; i++ )
4173             emitcode ("mov","%s,#0",javaRet[i]);
4174     return;
4175 }
4176
4177 /*-----------------------------------------------------------------*/
4178 /* genRet - generate code for return statement                     */
4179 /*-----------------------------------------------------------------*/
4180 static void
4181 genRet (iCode * ic)
4182 {
4183   int size, offset = 0, pushed = 0;
4184
4185   D (emitcode (";", "genRet"));
4186
4187   /* if we have no return value then
4188      just generate the "ret" */
4189   if (!IC_LEFT (ic))
4190     goto jumpret;
4191
4192   /* if this is a JavaNative function then return
4193      value in different register */
4194   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4195       genJavaNativeRet(ic);
4196       goto jumpret;
4197   }
4198   /* we have something to return then
4199      move the return value into place */
4200   aopOp (IC_LEFT (ic), ic, FALSE,
4201          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4202   size = AOP_SIZE (IC_LEFT (ic));
4203
4204   _startLazyDPSEvaluation ();
4205
4206   if (IS_BIT(_G.currentFunc->etype))
4207     {
4208       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4209       size = 0;
4210     }
4211
4212   while (size--)
4213     {
4214       char *l;
4215       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4216         {
4217           l = aopGet (IC_LEFT (ic), offset++,
4218                       FALSE, TRUE, NULL);
4219           emitcode ("push", "%s", l);
4220           pushed++;
4221         }
4222       else
4223         {
4224           /* Since A is the last element of fReturn,
4225            * it is OK to clobber it in the aopGet.
4226            */
4227           l = aopGet (IC_LEFT (ic), offset,
4228                       FALSE, FALSE, NULL);
4229           if (strcmp (fReturn[offset], l))
4230             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4231         }
4232     }
4233   _endLazyDPSEvaluation ();
4234
4235   while (pushed)
4236     {
4237       pushed--;
4238       if (strcmp (fReturn[pushed], "a"))
4239         emitcode ("pop", fReturn[pushed]);
4240       else
4241         emitcode ("pop", "acc");
4242     }
4243   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4244
4245 jumpret:
4246   /* generate a jump to the return label
4247      if the next is not the return statement */
4248   if (!(ic->next && ic->next->op == LABEL &&
4249         IC_LABEL (ic->next) == returnLabel))
4250
4251     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4252
4253 }
4254
4255 /*-----------------------------------------------------------------*/
4256 /* genLabel - generates a label                                    */
4257 /*-----------------------------------------------------------------*/
4258 static void
4259 genLabel (iCode * ic)
4260 {
4261   /* special case never generate */
4262   if (IC_LABEL (ic) == entryLabel)
4263     return;
4264
4265   D (emitcode (";", "genLabel"));
4266
4267   emitLabel (IC_LABEL (ic));
4268 }
4269
4270 /*-----------------------------------------------------------------*/
4271 /* genGoto - generates a ljmp                                      */
4272 /*-----------------------------------------------------------------*/
4273 static void
4274 genGoto (iCode * ic)
4275 {
4276   D (emitcode (";", "genGoto"));
4277
4278   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4279 }
4280
4281 /*-----------------------------------------------------------------*/
4282 /* findLabelBackwards: walks back through the iCode chain looking  */
4283 /* for the given label. Returns number of iCode instructions     */
4284 /* between that label and given ic.          */
4285 /* Returns zero if label not found.          */
4286 /*-----------------------------------------------------------------*/
4287 static int
4288 findLabelBackwards (iCode * ic, int key)
4289 {
4290   int count = 0;
4291
4292   while (ic->prev)
4293     {
4294       ic = ic->prev;
4295       count++;
4296
4297       /* If we have any pushes or pops, we cannot predict the distance.
4298          I don't like this at all, this should be dealt with in the
4299          back-end */
4300       if (ic->op == IPUSH || ic->op == IPOP) {
4301         return 0;
4302       }
4303
4304       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4305         {
4306           /* printf("findLabelBackwards = %d\n", count); */
4307           return count;
4308         }
4309     }
4310
4311   return 0;
4312 }
4313
4314 /*-----------------------------------------------------------------*/
4315 /* genPlusIncr :- does addition with increment if possible         */
4316 /*-----------------------------------------------------------------*/
4317 static bool
4318 genPlusIncr (iCode * ic)
4319 {
4320   unsigned int icount;
4321   unsigned int size = getDataSize (IC_RESULT (ic));
4322
4323   /* will try to generate an increment */
4324   /* if the right side is not a literal
4325      we cannot */
4326   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4327     return FALSE;
4328
4329   /* if the literal value of the right hand side
4330      is greater than 4 then it is not worth it */
4331   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4332     return FALSE;
4333
4334   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4335       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4336       while (icount--) {
4337           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4338       }
4339       return TRUE;
4340   }
4341   /* if increment 16 bits in register */
4342   if (
4343        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4344        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4345        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4346        (size > 1) &&
4347        (icount == 1))
4348     {
4349       symbol  *tlbl;
4350       int     emitTlbl;
4351       int     labelRange;
4352       char    *l;
4353
4354       /* If the next instruction is a goto and the goto target
4355        * is <= 5 instructions previous to this, we can generate
4356        * jumps straight to that target.
4357        */
4358       if (ic->next && ic->next->op == GOTO
4359           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4360           && labelRange <= 5)
4361         {
4362           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4363           tlbl = IC_LABEL (ic->next);
4364           emitTlbl = 0;
4365         }
4366       else
4367         {
4368           tlbl = newiTempLabel (NULL);
4369           emitTlbl = 1;
4370         }
4371       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4372       emitcode ("inc", "%s", l);
4373
4374       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4375           IS_AOP_PREG (IC_RESULT (ic)))
4376         {
4377           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4378         }
4379       else
4380         {
4381           emitcode ("clr", "a");
4382           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4383         }
4384
4385       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4386       emitcode ("inc", "%s", l);
4387       if (size > 2)
4388         {
4389           if (!strcmp(l, "acc"))
4390             {
4391               emitcode("jnz", "!tlabel", tlbl->key + 100);
4392             }
4393           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4394                    IS_AOP_PREG (IC_RESULT (ic)))
4395             {
4396               emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4397             }
4398           else
4399             {
4400               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4401             }
4402
4403           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4404           emitcode ("inc", "%s", l);
4405         }
4406       if (size > 3)
4407         {
4408           if (!strcmp(l, "acc"))
4409             {
4410               emitcode("jnz", "!tlabel", tlbl->key + 100);
4411             }
4412           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4413                    IS_AOP_PREG (IC_RESULT (ic)))
4414             {
4415               emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4416             }
4417           else
4418             {
4419               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4420             }
4421
4422           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4423           emitcode ("inc", "%s", l);
4424         }
4425
4426       if (emitTlbl)
4427         {
4428           emitLabel (tlbl);
4429         }
4430       return TRUE;
4431     }
4432
4433   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4434       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4435       options.model == MODEL_FLAT24 )
4436     {
4437       if (IC_RESULT(ic)->isGptr)
4438         {
4439           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4440         }
4441       switch (size) {
4442       case 3:
4443           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4444       case 2:
4445           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4446       case 1:
4447           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4448           break;
4449       }
4450       while (icount--)
4451         emitcode ("inc", "dptr");
4452       return TRUE;
4453     }
4454
4455   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4456       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4457       icount <= 5 )
4458     {
4459       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4460       while (icount--)
4461         emitcode ("inc", "dptr");
4462       emitcode ("mov", "dps,#0");
4463       return TRUE;
4464     }
4465
4466   /* if the sizes are greater than 1 then we cannot */
4467   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4468       AOP_SIZE (IC_LEFT (ic)) > 1)
4469     return FALSE;
4470
4471   /* we can if the aops of the left & result match or
4472      if they are in registers and the registers are the
4473      same */
4474   if (
4475        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4476        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4477        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4478     {
4479       if (icount > 3)
4480         {
4481           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4482           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4483           aopPut (IC_RESULT (ic), "a", 0);
4484         }
4485       else
4486         {
4487           _startLazyDPSEvaluation ();
4488           while (icount--)
4489             {
4490               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4491             }
4492           _endLazyDPSEvaluation ();
4493         }
4494
4495       return TRUE;
4496     }
4497
4498   return FALSE;
4499 }
4500
4501 /*-----------------------------------------------------------------*/
4502 /* outBitAcc - output a bit in acc                                 */
4503 /*-----------------------------------------------------------------*/
4504 static void
4505 outBitAcc (operand * result)
4506 {
4507   symbol *tlbl = newiTempLabel (NULL);
4508   /* if the result is a bit */
4509   if (AOP_TYPE (result) == AOP_CRY)
4510     {
4511       aopPut (result, "a", 0);
4512     }
4513   else
4514     {
4515       emitcode ("jz", "!tlabel", tlbl->key + 100);
4516       emitcode ("mov", "a,%s", one);
4517       emitLabel (tlbl);
4518       outAcc (result);
4519     }
4520 }
4521
4522 /*-----------------------------------------------------------------*/
4523 /* genPlusBits - generates code for addition of two bits           */
4524 /*-----------------------------------------------------------------*/
4525 static void
4526 genPlusBits (iCode * ic)
4527 {
4528   D (emitcode (";", "genPlusBits"));
4529
4530   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4531   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4532     {
4533       symbol *lbl = newiTempLabel (NULL);
4534       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4535       emitcode ("cpl", "c");
4536       emitLabel (lbl);
4537       outBitC (IC_RESULT (ic));
4538     }
4539   else
4540     {
4541       emitcode ("clr", "a");
4542       emitcode ("rlc", "a");
4543       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4544       emitcode ("addc", "a,%s", zero);
4545       outAcc (IC_RESULT (ic));
4546     }
4547 }
4548
4549 static void
4550 adjustArithmeticResult (iCode * ic)
4551 {
4552   if (opIsGptr (IC_RESULT (ic)) &&
4553       opIsGptr (IC_LEFT (ic)) &&
4554       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4555     {
4556       aopPut (IC_RESULT (ic),
4557               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4558               GPTRSIZE - 1);
4559     }
4560
4561   if (opIsGptr (IC_RESULT (ic)) &&
4562       opIsGptr (IC_RIGHT (ic)) &&
4563       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4564     {
4565       aopPut (IC_RESULT (ic),
4566               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4567               GPTRSIZE - 1);
4568     }
4569
4570   if (opIsGptr (IC_RESULT (ic)) &&
4571       IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4572       IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4573       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4574       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4575     {
4576       char buffer[5];
4577       SNPRINTF (buffer, sizeof(buffer),
4578                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4579       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4580     }
4581 }
4582
4583 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4584 // generates the result if possible. If result is generated, returns TRUE; otherwise
4585 // returns false and caller must deal with fact that result isn't aopOp'd.
4586 bool aopOp3(iCode * ic)
4587 {
4588     bool dp1InUse, dp2InUse;
4589     bool useDp2;
4590
4591     // First, generate the right opcode. DPTR may be used if neither left nor result are
4592     // of type AOP_STR.
4593
4594 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4595 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4596 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4597 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4598 //      );
4599 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4600 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4601 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4602 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4603 //      );
4604
4605     // Right uses DPTR unless left or result is an AOP_STR; however,
4606     // if right is an AOP_STR, it must use DPTR regardless.
4607     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4608      && !AOP_IS_STR (IC_RIGHT (ic)))
4609     {
4610         useDp2 = TRUE;
4611     }
4612     else
4613     {
4614         useDp2 = FALSE;
4615     }
4616
4617     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4618
4619     // if the right used DPTR, left MUST use DPTR2.
4620     // if the right used DPTR2, left MUST use DPTR.
4621     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4622     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4623     // enabling us to assign DPTR to result.
4624
4625     if (AOP_USESDPTR (IC_RIGHT (ic)))
4626     {
4627         useDp2 = TRUE;
4628     }
4629     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4630     {
4631         useDp2 = FALSE;
4632     }
4633     else
4634     {
4635         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4636         {
4637             useDp2 = TRUE;
4638         }
4639         else
4640         {
4641             useDp2 = FALSE;
4642         }
4643     }
4644
4645     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4646
4647
4648     // We've op'd the left & right. So, if left or right are the same operand as result,
4649     // we know aopOp will succeed, and we can just do it & bail.
4650     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4651       {
4652         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4653         return TRUE;
4654       }
4655     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4656       {
4657 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4658         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4659         return TRUE;
4660       }
4661
4662     // Operands may be equivalent (but not equal) if they share a spill location. If
4663     // so, use the same DPTR or DPTR2.
4664     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4665       {
4666         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4667         return TRUE;
4668       }
4669     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4670       {
4671         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4672         return TRUE;
4673       }
4674
4675     // Note which dptrs are currently in use.
4676     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4677     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4678
4679     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4680     // generate it.
4681     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4682     {
4683         return FALSE;
4684     }
4685
4686     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4687     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4688     {
4689         return FALSE;
4690     }
4691
4692     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4693     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4694     {
4695         return FALSE;
4696     }
4697
4698     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4699
4700     // Some sanity checking...
4701     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4702     {
4703         fprintf(stderr,
4704                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4705                 __FILE__, __LINE__, ic->filename, ic->lineno);
4706         emitcode(";", ">>> unexpected DPTR here.");
4707     }
4708
4709     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4710     {
4711         fprintf(stderr,
4712                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4713                 __FILE__, __LINE__, ic->filename, ic->lineno);
4714         emitcode(";", ">>> unexpected DPTR2 here.");
4715     }
4716
4717     return TRUE;
4718 }
4719
4720 // Macro to aopOp all three operands of an ic. If this cannot be done,
4721 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4722 // will be set TRUE. The caller must then handle the case specially, noting
4723 // that the IC_RESULT operand is not aopOp'd.
4724 //
4725 #define AOP_OP_3_NOFATAL(ic, rc) \
4726             do { rc = !aopOp3(ic); } while (0)
4727
4728 // aopOp the left & right operands of an ic.
4729 #define AOP_OP_2(ic) \
4730     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4731     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4732
4733 // convienience macro.
4734 #define AOP_SET_LOCALS(ic) \
4735     left = IC_LEFT(ic); \
4736     right = IC_RIGHT(ic); \
4737     result = IC_RESULT(ic);
4738
4739
4740 // Given an integer value of pushedSize bytes on the stack,
4741 // adjust it to be resultSize bytes, either by discarding
4742 // the most significant bytes or by zero-padding.
4743 //
4744 // On exit from this macro, pushedSize will have been adjusted to
4745 // equal resultSize, and ACC may be trashed.
4746 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4747       /* If the pushed data is bigger than the result,          \
4748        * simply discard unused bytes. Icky, but works.          \
4749        */                                                       \
4750       while (pushedSize > resultSize)                           \
4751       {                                                         \
4752           D (emitcode (";", "discarding unused result byte.")); \
4753           emitcode ("pop", "acc");                              \
4754           pushedSize--;                                         \
4755       }                                                         \
4756       if (pushedSize < resultSize)                              \
4757       {                                                         \
4758           emitcode ("clr", "a");                                \
4759           /* Conversly, we haven't pushed enough here.          \
4760            * just zero-pad, and all is well.                    \
4761            */                                                   \
4762           while (pushedSize < resultSize)                       \
4763           {                                                     \
4764               emitcode("push", "acc");                          \
4765               pushedSize++;                                     \
4766           }                                                     \
4767       }                                                         \
4768       assert(pushedSize == resultSize);
4769
4770 /*-----------------------------------------------------------------*/
4771 /* genPlus - generates code for addition                           */
4772 /*-----------------------------------------------------------------*/
4773 static void
4774 genPlus (iCode * ic)
4775 {
4776   int size, offset = 0;
4777   bool pushResult;
4778   int rSize;
4779   bool swappedLR = FALSE;
4780
4781   D (emitcode (";", "genPlus"));
4782
4783   /* special cases :- */
4784   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4785       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4786       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4787       size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4788       if (size <= 9) {
4789           while (size--) emitcode ("inc","dptr");
4790       } else {
4791           emitcode ("mov", "a,dpl");
4792           emitcode ("add", "a,#!constbyte", size & 0xff);
4793           emitcode ("mov", "dpl,a");
4794           emitcode ("mov", "a,dph");
4795           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4796           emitcode ("mov", "dph,a");
4797           emitcode ("mov", "a,dpx");
4798           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4799           emitcode ("mov", "dpx,a");
4800       }
4801       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4802       return ;
4803   }
4804   if ( IS_SYMOP (IC_LEFT (ic)) &&
4805        OP_SYMBOL (IC_LEFT (ic))->remat &&
4806        isOperandInFarSpace (IC_RIGHT (ic))) {
4807       operand *op = IC_RIGHT(ic);
4808       IC_RIGHT(ic) = IC_LEFT(ic);
4809       IC_LEFT(ic) = op;
4810   }
4811
4812   AOP_OP_3_NOFATAL (ic, pushResult);
4813
4814   if (pushResult)
4815     {
4816       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4817     }
4818
4819   if (!pushResult)
4820     {
4821       /* if literal, literal on the right or
4822          if left requires ACC or right is already
4823          in ACC */
4824       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4825           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4826           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4827         {
4828           operand *t = IC_RIGHT (ic);
4829           IC_RIGHT (ic) = IC_LEFT (ic);
4830           IC_LEFT (ic) = t;
4831           swappedLR = TRUE;
4832           D (emitcode (";", "Swapped plus args."));
4833         }
4834
4835       /* if both left & right are in bit
4836          space */
4837       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4838           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4839         {
4840           genPlusBits (ic);
4841           goto release;
4842         }
4843
4844       /* if left in bit space & right literal */
4845       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4846           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4847         {
4848           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4849           /* if result in bit space */
4850           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4851             {
4852               if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4853                 emitcode ("cpl", "c");
4854               outBitC (IC_RESULT (ic));
4855             }
4856           else
4857             {
4858               size = getDataSize (IC_RESULT (ic));
4859               _startLazyDPSEvaluation ();
4860               while (size--)
4861                 {
4862                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4863                   emitcode ("addc", "a,%s", zero);
4864                   aopPut (IC_RESULT (ic), "a", offset++);
4865                 }
4866               _endLazyDPSEvaluation ();
4867             }
4868           goto release;
4869         }
4870
4871       /* if I can do an increment instead
4872          of add then GOOD for ME */
4873       if (genPlusIncr (ic) == TRUE)
4874         {
4875           D (emitcode (";", "did genPlusIncr"));
4876           goto release;
4877         }
4878
4879     }
4880   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4881
4882   _startLazyDPSEvaluation ();
4883   while (size--)
4884     {
4885       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4886         {
4887           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4888           if (offset == 0)
4889             emitcode ("add", "a,%s",
4890                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4891           else
4892             emitcode ("addc", "a,%s",
4893                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4894         }
4895       else
4896         {
4897           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4898           {
4899               /* right is going to use ACC or we would have taken the
4900                * above branch.
4901                */
4902               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4903               TR_AP("#3");
4904               D(emitcode(";", "+ AOP_ACC special case."););
4905               emitcode("xch", "a, %s", DP2_RESULT_REG);
4906           }
4907           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4908           if (offset == 0)
4909           {
4910             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4911             {
4912                 TR_AP("#4");
4913                 emitcode("add", "a, %s", DP2_RESULT_REG);
4914             }
4915             else
4916             {
4917                 emitcode ("add", "a,%s",
4918                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4919                                   DP2_RESULT_REG));
4920             }
4921           }
4922           else
4923           {
4924             emitcode ("addc", "a,%s",
4925                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4926                           DP2_RESULT_REG));
4927           }
4928         }
4929       if (!pushResult)
4930         {
4931           aopPut (IC_RESULT (ic), "a", offset);
4932         }
4933       else
4934         {
4935           emitcode ("push", "acc");
4936         }
4937       offset++;
4938     }
4939   _endLazyDPSEvaluation ();
4940
4941   if (pushResult)
4942     {
4943       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4944
4945       size = getDataSize (IC_LEFT (ic));
4946       rSize = getDataSize (IC_RESULT (ic));
4947
4948       ADJUST_PUSHED_RESULT(size, rSize);
4949
4950       _startLazyDPSEvaluation ();
4951       while (size--)
4952         {
4953           emitcode ("pop", "acc");
4954           aopPut (IC_RESULT (ic), "a", size);
4955         }
4956       _endLazyDPSEvaluation ();
4957     }
4958
4959   adjustArithmeticResult (ic);
4960
4961 release:
4962   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4963   if (!swappedLR)
4964     {
4965       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4966       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4967     }
4968   else
4969     {
4970       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4971       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4972     }
4973 }
4974
4975 /*-----------------------------------------------------------------*/
4976 /* genMinusDec :- does subtraction with decrement if possible      */
4977 /*-----------------------------------------------------------------*/
4978 static bool
4979 genMinusDec (iCode * ic)
4980 {
4981   unsigned int icount;
4982   unsigned int size = getDataSize (IC_RESULT (ic));
4983
4984   /* will try to generate an increment */
4985   /* if the right side is not a literal
4986      we cannot */
4987   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4988     return FALSE;
4989
4990   /* if the literal value of the right hand side
4991      is greater than 4 then it is not worth it */
4992   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4993     return FALSE;
4994
4995   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4996       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4997       while (icount--) {
4998           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4999       }
5000       return TRUE;
5001   }
5002   /* if decrement 16 bits in register */
5003   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5004       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5005       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
5006       (size > 1) &&
5007       (icount == 1))
5008     {
5009       symbol *tlbl;
5010       int    emitTlbl;
5011       int    labelRange;
5012       char   *l;
5013
5014       /* If the next instruction is a goto and the goto target
5015          * is <= 5 instructions previous to this, we can generate
5016          * jumps straight to that target.
5017        */
5018       if (ic->next && ic->next->op == GOTO
5019           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
5020           && labelRange <= 5)
5021         {
5022           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
5023           tlbl = IC_LABEL (ic->next);
5024           emitTlbl = 0;
5025         }
5026       else
5027         {
5028           tlbl = newiTempLabel (NULL);
5029           emitTlbl = 1;
5030         }
5031
5032       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
5033       emitcode ("dec", "%s", l);
5034
5035       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
5036           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
5037           IS_AOP_PREG (IC_RESULT (ic)))
5038         {
5039           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
5040         }
5041       else
5042         {
5043           emitcode ("mov", "a,#!constbyte",0xff);
5044           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5045         }
5046       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
5047       emitcode ("dec", "%s", l);
5048       if (size > 2)
5049         {
5050           if (!strcmp(l, "acc"))
5051             {
5052               emitcode("jnz", "!tlabel", tlbl->key + 100);
5053             }
5054           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
5055                    AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
5056                    IS_AOP_PREG (IC_RESULT (ic)))
5057             {
5058               emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
5059             }
5060           else
5061             {
5062               emitcode ("mov", "a,#!constbyte",0xff);
5063               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5064             }
5065           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
5066           emitcode ("dec", "%s", l);
5067         }
5068       if (size > 3)
5069         {
5070           if (!strcmp(l, "acc"))
5071             {
5072               emitcode("jnz", "!tlabel", tlbl->key + 100);
5073             }
5074           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
5075                    AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
5076                    IS_AOP_PREG (IC_RESULT (ic)))
5077             {
5078               emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
5079             }
5080           else
5081             {
5082               emitcode ("mov", "a,#!constbyte",0xff);
5083               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5084             }
5085           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
5086           emitcode ("dec", "%s", l);
5087         }
5088       if (emitTlbl)
5089         {
5090           emitLabel (tlbl);
5091         }
5092       return TRUE;
5093     }
5094
5095   /* if the sizes are greater than 1 then we cannot */
5096   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
5097       AOP_SIZE (IC_LEFT (ic)) > 1)
5098     return FALSE;
5099
5100   /* we can if the aops of the left & result match or
5101      if they are in registers and the registers are the
5102      same */
5103   if (
5104        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5105        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5106        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5107     {
5108       char *l;
5109
5110       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5111         {
5112           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5113           l = "a";
5114         }
5115       else
5116         {
5117           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5118         }
5119
5120       _startLazyDPSEvaluation ();
5121       while (icount--)
5122         {
5123           emitcode ("dec", "%s", l);
5124         }
5125       _endLazyDPSEvaluation ();
5126
5127       if (AOP_NEEDSACC (IC_RESULT (ic)))
5128         aopPut (IC_RESULT (ic), "a", 0);
5129
5130       return TRUE;
5131     }
5132
5133   return FALSE;
5134 }
5135
5136 /*-----------------------------------------------------------------*/
5137 /* addSign - complete with sign                                    */
5138 /*-----------------------------------------------------------------*/
5139 static void
5140 addSign (operand * result, int offset, int sign)
5141 {
5142   int size = (getDataSize (result) - offset);
5143   if (size > 0)
5144     {
5145       _startLazyDPSEvaluation();
5146       if (sign)
5147         {
5148           emitcode ("rlc", "a");
5149           emitcode ("subb", "a,acc");
5150           while (size--)
5151             {
5152               aopPut (result, "a", offset++);
5153             }
5154         }
5155       else
5156         {
5157           while (size--)
5158             {
5159               aopPut (result, zero, offset++);
5160             }
5161         }
5162       _endLazyDPSEvaluation();
5163     }
5164 }
5165
5166 /*-----------------------------------------------------------------*/
5167 /* genMinusBits - generates code for subtraction  of two bits      */
5168 /*-----------------------------------------------------------------*/
5169 static void
5170 genMinusBits (iCode * ic)
5171 {
5172   symbol *lbl = newiTempLabel (NULL);
5173
5174   D (emitcode (";", "genMinusBits"));
5175
5176   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5177     {
5178       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5179       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5180       emitcode ("cpl", "c");
5181       emitLabel (lbl);
5182       outBitC (IC_RESULT (ic));
5183     }
5184   else
5185     {
5186       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5187       emitcode ("subb", "a,acc");
5188       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5189       emitcode ("inc", "a");
5190       emitLabel (lbl);
5191       aopPut (IC_RESULT (ic), "a", 0);
5192       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5193     }
5194 }
5195
5196 /*-----------------------------------------------------------------*/
5197 /* genMinus - generates code for subtraction                       */
5198 /*-----------------------------------------------------------------*/
5199 static void
5200 genMinus (iCode * ic)
5201 {
5202     int size, offset = 0;
5203     int rSize;
5204     long lit = 0L;
5205     bool pushResult;
5206
5207     D (emitcode (";", "genMinus"));
5208
5209     AOP_OP_3_NOFATAL(ic, pushResult);
5210
5211     if (!pushResult)
5212     {
5213       /* special cases :- */
5214       /* if both left & right are in bit space */
5215       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5216           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5217         {
5218           genMinusBits (ic);
5219           goto release;
5220         }
5221
5222       /* if I can do an decrement instead
5223          of subtract then GOOD for ME */
5224       if (genMinusDec (ic) == TRUE)
5225         goto release;
5226
5227     }
5228
5229   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5230
5231   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5232     {
5233       CLRC;
5234     }
5235   else
5236     {
5237       lit = (long) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5238       lit = -lit;
5239     }
5240
5241
5242   /* if literal, add a,#-lit, else normal subb */
5243   _startLazyDPSEvaluation ();
5244   while (size--) {
5245       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5246           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5247               emitcode ("mov","b,%s",
5248                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5249               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5250               emitcode ("subb","a,b");
5251           } else {
5252               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5253               emitcode ("subb", "a,%s",
5254                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5255                                 DP2_RESULT_REG));
5256           }
5257       } else {
5258           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5259           /* first add without previous c */
5260           if (!offset) {
5261               if (!size && lit==-1) {
5262                   emitcode ("dec", "a");
5263               } else {
5264                   emitcode ("add", "a,#!constbyte",
5265                             (unsigned int) (lit & 0x0FFL));
5266               }
5267           } else {
5268               emitcode ("addc", "a,#!constbyte",
5269                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5270           }
5271       }
5272
5273       if (pushResult) {
5274           emitcode ("push", "acc");
5275       } else {
5276           aopPut (IC_RESULT (ic), "a", offset);
5277       }
5278       offset++;
5279   }
5280   _endLazyDPSEvaluation ();
5281
5282   if (pushResult)
5283     {
5284       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5285
5286       size = getDataSize (IC_LEFT (ic));
5287       rSize = getDataSize (IC_RESULT (ic));
5288
5289       ADJUST_PUSHED_RESULT(size, rSize);
5290
5291       _startLazyDPSEvaluation ();
5292       while (size--)
5293         {
5294           emitcode ("pop", "acc");
5295           aopPut (IC_RESULT (ic), "a", size);
5296         }
5297       _endLazyDPSEvaluation ();
5298     }
5299
5300   adjustArithmeticResult (ic);
5301
5302 release:
5303   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5304   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5305   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5306 }
5307
5308
5309 /*-----------------------------------------------------------------*/
5310 /* genMultbits :- multiplication of bits                           */
5311 /*-----------------------------------------------------------------*/
5312 static void
5313 genMultbits (operand * left,
5314              operand * right,
5315              operand * result,
5316              iCode   * ic)
5317 {
5318   D (emitcode (";", "genMultbits"));
5319
5320   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5321   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5322   aopOp(result, ic, TRUE, FALSE);
5323   outBitC (result);
5324 }
5325
5326 /*-----------------------------------------------------------------*/
5327 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5328 /*-----------------------------------------------------------------*/
5329 static void
5330 genMultOneByte (operand * left,
5331                 operand * right,
5332                 operand * result,
5333                 iCode   * ic)
5334 {
5335   symbol *lbl;
5336   int size;
5337   bool runtimeSign, compiletimeSign;
5338   bool lUnsigned, rUnsigned, pushedB;
5339
5340   /* (if two literals: the value is computed before) */
5341   /* if one literal, literal on the right */
5342   if (AOP_TYPE (left) == AOP_LIT)
5343     {
5344       operand *t = right;
5345       right = left;
5346       left = t;
5347       /* emitcode (";", "swapped left and right"); */
5348     }
5349   /* if no literal, unsigned on the right: shorter code */
5350   if (   AOP_TYPE (right) != AOP_LIT
5351       && SPEC_USIGN (getSpec (operandType (left))))
5352     {
5353       operand *t = right;
5354       right = left;
5355       left = t;
5356     }
5357
5358   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5359   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5360
5361   pushedB = pushB ();
5362
5363   if ((lUnsigned && rUnsigned)
5364 /* sorry, I don't know how to get size
5365    without calling aopOp (result,...);
5366    see Feature Request  */
5367       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5368                    no need to take care about the signedness! */
5369     {
5370       /* just an unsigned 8 * 8 = 8 multiply
5371          or 8u * 8u = 16u */
5372       /* emitcode (";","unsigned"); */
5373       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5374       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5375       emitcode ("mul", "ab");
5376
5377       _G.accInUse++;
5378       aopOp (result, ic, TRUE, FALSE);
5379       size = AOP_SIZE (result);
5380
5381       if (size < 1 || size > 2)
5382         {
5383           /* this should never happen */
5384           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5385                    size, __FILE__, lineno);
5386           exit (1);
5387         }
5388
5389       aopPut (result, "a", 0);
5390       _G.accInUse--;
5391       if (size == 2)
5392         aopPut (result, "b", 1);
5393
5394       popB (pushedB);
5395       return;
5396     }
5397
5398   /* we have to do a signed multiply */
5399   /* emitcode (";", "signed"); */
5400
5401   /* now sign adjust for both left & right */
5402
5403   /* let's see what's needed: */
5404   /* apply negative sign during runtime */
5405   runtimeSign = FALSE;
5406   /* negative sign from literals */
5407   compiletimeSign = FALSE;
5408
5409   if (!lUnsigned)
5410     {
5411       if (AOP_TYPE(left) == AOP_LIT)
5412         {
5413           /* signed literal */
5414           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5415           if (val < 0)
5416             compiletimeSign = TRUE;
5417         }
5418       else
5419         /* signed but not literal */
5420         runtimeSign = TRUE;
5421     }
5422
5423   if (!rUnsigned)
5424     {
5425       if (AOP_TYPE(right) == AOP_LIT)
5426         {
5427           /* signed literal */
5428           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5429           if (val < 0)
5430             compiletimeSign ^= TRUE;
5431         }
5432       else
5433         /* signed but not literal */
5434         runtimeSign = TRUE;
5435     }
5436
5437   /* initialize F0, which stores the runtime sign */
5438   if (runtimeSign)
5439     {
5440       if (compiletimeSign)
5441         emitcode ("setb", "F0"); /* set sign flag */
5442       else
5443         emitcode ("clr", "F0"); /* reset sign flag */
5444     }
5445
5446   /* save the signs of the operands */
5447   if (AOP_TYPE(right) == AOP_LIT)
5448     {
5449       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5450
5451       if (!rUnsigned && val < 0)
5452         emitcode ("mov", "b,#!constbyte", -val);
5453       else
5454         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5455     }
5456   else /* ! literal */
5457     {
5458       if (rUnsigned)  /* emitcode (";", "signed"); */
5459         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5460       else
5461         {
5462           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5463           lbl = newiTempLabel (NULL);
5464           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5465           emitcode ("cpl", "F0"); /* complement sign flag */
5466           emitcode ("cpl", "a");  /* 2's complement */
5467           emitcode ("inc", "a");
5468           emitLabel (lbl);
5469           emitcode ("mov", "b,a");
5470         }
5471     }
5472
5473   if (AOP_TYPE(left) == AOP_LIT)
5474     {
5475       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5476
5477       if (!lUnsigned && val < 0)
5478         emitcode ("mov", "a,#!constbyte", -val);
5479       else
5480         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5481     }
5482   else /* ! literal */
5483     {
5484       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5485
5486       if (!lUnsigned)  /* emitcode (";", "signed"); */
5487         {
5488           lbl = newiTempLabel (NULL);
5489           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5490           emitcode ("cpl", "F0"); /* complement sign flag */
5491           emitcode ("cpl", "a");  /* 2's complement */
5492           emitcode ("inc", "a");
5493           emitLabel (lbl);
5494         }
5495     }
5496
5497   /* now the multiplication */
5498   emitcode ("mul", "ab");
5499   _G.accInUse++;
5500   aopOp(result, ic, TRUE, FALSE);
5501   size = AOP_SIZE (result);
5502
5503   if (size < 1 || size > 2)
5504     {
5505       /* this should never happen */
5506       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5507                size, __FILE__, lineno);
5508       exit (1);
5509     }
5510
5511   if (runtimeSign || compiletimeSign)
5512     {
5513       lbl = newiTempLabel (NULL);
5514       if (runtimeSign)
5515         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5516       emitcode ("cpl", "a"); /* lsb 2's complement */
5517       if (size != 2)
5518         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5519       else
5520         {
5521           emitcode ("add", "a,#0x01"); /* this sets carry flag */
5522           emitcode ("xch", "a,b");
5523           emitcode ("cpl", "a"); /* msb 2's complement */
5524           emitcode ("addc", "a,#0x00");
5525           emitcode ("xch", "a,b");
5526         }
5527       emitLabel (lbl);
5528     }
5529   aopPut (result, "a", 0);
5530   _G.accInUse--;
5531   if (size == 2)
5532     aopPut (result, "b", 1);
5533
5534   popB (pushedB);
5535 }
5536
5537 /*-----------------------------------------------------------------*/
5538 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5539 /*-----------------------------------------------------------------*/
5540 static void genMultTwoByte (operand *left, operand *right,
5541                             operand *result, iCode *ic)
5542 {
5543         sym_link *retype = getSpec(operandType(right));
5544         sym_link *letype = getSpec(operandType(left));
5545         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5546         symbol *lbl;
5547
5548         if (AOP_TYPE (left) == AOP_LIT) {
5549                 operand *t = right;
5550                 right = left;
5551                 left = t;
5552         }
5553         /* save EA bit in F1 */
5554         lbl = newiTempLabel(NULL);
5555         emitcode ("setb","F1");
5556         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5557         emitcode ("clr","F1");
5558         emitLabel (lbl);
5559
5560         /* load up MB with right */
5561         if (!umult) {
5562                 emitcode("clr","F0");
5563                 if (AOP_TYPE(right) == AOP_LIT) {
5564                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5565                         if (val < 0) {
5566                                 emitcode("setb","F0");
5567                                 val = -val;
5568                         }
5569                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5570                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5571                 } else {
5572                         lbl = newiTempLabel(NULL);
5573                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5574                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5575                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5576                         emitcode ("xch", "a,b");
5577                         emitcode ("cpl","a");
5578                         emitcode ("add", "a,#1");
5579                         emitcode ("xch", "a,b");
5580                         emitcode ("cpl", "a"); // msb
5581                         emitcode ("addc", "a,#0");
5582                         emitcode ("setb","F0");
5583                         emitLabel (lbl);
5584                         emitcode ("mov","mb,b");
5585                         emitcode ("mov","mb,a");
5586                 }
5587         } else {
5588                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5589                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5590         }
5591         /* load up MA with left */
5592         if (!umult) {
5593                 lbl = newiTempLabel(NULL);
5594                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5595                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5596                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5597                 emitcode ("xch", "a,b");
5598                 emitcode ("cpl","a");
5599                 emitcode ("add", "a,#1");
5600                 emitcode ("xch", "a,b");
5601                 emitcode ("cpl", "a"); // msb
5602                 emitcode ("addc","a,#0");
5603                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5604                 emitcode ("setb","F0");
5605                 emitLabel (lbl);
5606                 emitcode ("mov","ma,b");
5607                 emitcode ("mov","ma,a");
5608         } else {
5609                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5610                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5611         }
5612         /* wait for multiplication to finish */
5613         lbl = newiTempLabel(NULL);
5614         emitLabel (lbl);
5615         emitcode("mov","a,mcnt1");
5616         emitcode("anl","a,#!constbyte",0x80);
5617         emitcode("jnz","!tlabel",lbl->key+100);
5618
5619         freeAsmop (left, NULL, ic, TRUE);
5620         freeAsmop (right, NULL, ic,TRUE);
5621         aopOp(result, ic, TRUE, FALSE);
5622
5623         /* if unsigned then simple */
5624         if (umult) {
5625                 emitcode ("mov","a,ma");
5626                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5627                 emitcode ("mov","a,ma");
5628                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5629                 aopPut(result,"ma",1);
5630                 aopPut(result,"ma",0);
5631         } else {
5632                 emitcode("push","ma");
5633                 emitcode("push","ma");
5634                 emitcode("push","ma");
5635                 MOVA("ma");
5636                 /* negate result if needed */
5637                 lbl = newiTempLabel(NULL);
5638                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5639                 emitcode("cpl","a");
5640                 emitcode("add","a,#1");
5641                 emitLabel (lbl);
5642                 if (AOP_TYPE(result) == AOP_ACC)
5643                 {
5644                     D (emitcode(";", "ACC special case."));
5645                     /* We know result is the only live aop, and
5646                      * it's obviously not a DPTR2, so AP is available.
5647                      */
5648                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5649                 }
5650                 else
5651                 {
5652                     aopPut(result,"a",0);
5653                 }
5654
5655                 emitcode("pop","acc");
5656                 lbl = newiTempLabel(NULL);
5657                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5658                 emitcode("cpl","a");
5659                 emitcode("addc","a,#0");
5660                 emitLabel (lbl);
5661                 aopPut(result,"a",1);
5662                 emitcode("pop","acc");
5663                 if (AOP_SIZE(result) >= 3) {
5664                         lbl = newiTempLabel(NULL);
5665                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5666                         emitcode("cpl","a");
5667                         emitcode("addc","a,#0");
5668                         emitLabel (lbl);
5669                         aopPut(result,"a",2);
5670                 }
5671                 emitcode("pop","acc");
5672                 if (AOP_SIZE(result) >= 4) {
5673                         lbl = newiTempLabel(NULL);
5674                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5675                         emitcode("cpl","a");
5676                         emitcode("addc","a,#0");
5677                         emitLabel (lbl);
5678                         aopPut(result,"a",3);
5679                 }
5680                 if (AOP_TYPE(result) == AOP_ACC)
5681                 {
5682                     /* We stashed the result away above. */
5683                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5684                 }
5685
5686         }
5687         freeAsmop (result, NULL, ic, TRUE);
5688
5689         /* restore EA bit in F1 */
5690         lbl = newiTempLabel(NULL);
5691         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5692         emitcode ("setb","EA");
5693         emitLabel (lbl);
5694         return ;
5695 }
5696
5697 /*-----------------------------------------------------------------*/
5698 /* genMult - generates code for multiplication                     */
5699 /*-----------------------------------------------------------------*/
5700 static void
5701 genMult (iCode * ic)
5702 {
5703   operand *left = IC_LEFT (ic);
5704   operand *right = IC_RIGHT (ic);
5705   operand *result = IC_RESULT (ic);
5706
5707   D (emitcode (";", "genMult"));
5708
5709   /* assign the asmops */
5710   AOP_OP_2 (ic);
5711
5712   /* special cases first */
5713   /* both are bits */
5714   if (AOP_TYPE (left) == AOP_CRY &&
5715       AOP_TYPE (right) == AOP_CRY)
5716     {
5717       genMultbits (left, right, result, ic);
5718       goto release;
5719     }
5720
5721   /* if both are of size == 1 */
5722   if (AOP_SIZE (left) == 1 &&
5723       AOP_SIZE (right) == 1)
5724     {
5725       genMultOneByte (left, right, result, ic);
5726       goto release;
5727     }
5728
5729   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5730           /* use the ds390 ARITHMETIC accel UNIT */
5731           genMultTwoByte (left, right, result, ic);
5732           return ;
5733   }
5734   /* should have been converted to function call */
5735   assert (0);
5736
5737 release:
5738   freeAsmop (result, NULL, ic, TRUE);
5739   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5740   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5741 }
5742
5743 /*-----------------------------------------------------------------*/
5744 /* genDivbits :- division of bits                                  */
5745 /*-----------------------------------------------------------------*/
5746 static void
5747 genDivbits (operand * left,
5748             operand * right,
5749             operand * result,
5750             iCode   * ic)
5751 {
5752   char *l;
5753   bool pushedB;
5754
5755   D(emitcode (";", "genDivbits"));
5756
5757   pushedB = pushB ();
5758
5759   /* the result must be bit */
5760   LOAD_AB_FOR_DIV (left, right, l);
5761   emitcode ("div", "ab");
5762   emitcode ("rrc", "a");
5763   aopOp(result, ic, TRUE, FALSE);
5764
5765   popB (pushedB);
5766
5767   aopPut (result, "c", 0);
5768 }
5769
5770 /*-----------------------------------------------------------------*/
5771 /* genDivOneByte : 8 bit division                                  */
5772 /*-----------------------------------------------------------------*/
5773 static void
5774 genDivOneByte (operand * left,
5775                operand * right,
5776                operand * result,
5777                iCode   * ic)
5778 {
5779   bool lUnsigned, rUnsigned, pushedB;
5780   bool runtimeSign, compiletimeSign;
5781   char *l;
5782   symbol *lbl;
5783   int size, offset;
5784
5785   D(emitcode (";", "genDivOneByte"));
5786
5787   offset = 1;
5788   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5789   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5790
5791   pushedB = pushB ();
5792
5793   /* signed or unsigned */
5794   if (lUnsigned && rUnsigned)
5795     {
5796       /* unsigned is easy */
5797       LOAD_AB_FOR_DIV (left, right, l);
5798       emitcode ("div", "ab");
5799
5800       _G.accInUse++;
5801       aopOp (result, ic, TRUE, FALSE);
5802       aopPut (result, "a", 0);
5803       _G.accInUse--;
5804
5805       size = AOP_SIZE (result) - 1;
5806
5807       while (size--)
5808         aopPut (result, zero, offset++);
5809
5810       popB (pushedB);
5811       return;
5812     }
5813
5814   /* signed is a little bit more difficult */
5815
5816   /* now sign adjust for both left & right */
5817
5818   /* let's see what's needed: */
5819   /* apply negative sign during runtime */
5820   runtimeSign = FALSE;
5821   /* negative sign from literals */
5822   compiletimeSign = FALSE;
5823
5824   if (!lUnsigned)
5825     {
5826       if (AOP_TYPE(left) == AOP_LIT)
5827         {
5828           /* signed literal */
5829           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5830           if (val < 0)
5831             compiletimeSign = TRUE;
5832         }
5833       else
5834         /* signed but not literal */
5835         runtimeSign = TRUE;
5836     }
5837
5838   if (!rUnsigned)
5839     {
5840       if (AOP_TYPE(right) == AOP_LIT)
5841         {
5842           /* signed literal */
5843           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5844           if (val < 0)
5845             compiletimeSign ^= TRUE;
5846         }
5847       else
5848         /* signed but not literal */
5849         runtimeSign = TRUE;
5850     }
5851
5852   /* initialize F0, which stores the runtime sign */
5853   if (runtimeSign)
5854     {
5855       if (compiletimeSign)
5856         emitcode ("setb", "F0"); /* set sign flag */
5857       else
5858         emitcode ("clr", "F0"); /* reset sign flag */
5859     }
5860
5861   /* save the signs of the operands */
5862   if (AOP_TYPE(right) == AOP_LIT)
5863     {
5864       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5865
5866       if (!rUnsigned && val < 0)
5867         emitcode ("mov", "b,#0x%02x", -val);
5868       else
5869         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5870     }
5871   else /* ! literal */
5872     {
5873       if (rUnsigned)
5874         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5875       else
5876         {
5877           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5878           lbl = newiTempLabel (NULL);
5879           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5880           emitcode ("cpl", "F0"); /* complement sign flag */
5881           emitcode ("cpl", "a");  /* 2's complement */
5882           emitcode ("inc", "a");
5883           emitLabel (lbl);
5884           emitcode ("mov", "b,a");
5885         }
5886     }
5887
5888   if (AOP_TYPE(left) == AOP_LIT)
5889     {
5890       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5891
5892       if (!lUnsigned && val < 0)
5893         emitcode ("mov", "a,#0x%02x", -val);
5894       else
5895         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5896     }
5897   else /* ! literal */
5898     {
5899       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5900
5901       if (!lUnsigned)
5902         {
5903           lbl = newiTempLabel (NULL);
5904           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5905           emitcode ("cpl", "F0"); /* complement sign flag */
5906           emitcode ("cpl", "a");  /* 2's complement */
5907           emitcode ("inc", "a");
5908           emitLabel (lbl);
5909         }
5910     }
5911
5912   /* now the division */
5913   emitcode ("nop", "; workaround for DS80C390 div bug.");
5914   emitcode ("div", "ab");
5915
5916   if (runtimeSign || compiletimeSign)
5917     {
5918       lbl = newiTempLabel (NULL);
5919       if (runtimeSign)
5920         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5921       emitcode ("cpl", "a"); /* lsb 2's complement */
5922       emitcode ("inc", "a");
5923       emitLabel (lbl);
5924
5925       _G.accInUse++;
5926       aopOp (result, ic, TRUE, FALSE);
5927       size = AOP_SIZE (result) - 1;
5928
5929       if (size > 0)
5930         {
5931           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5932              then the result will be in b, a */
5933           emitcode ("mov", "b,a"); /* 1 */
5934           /* msb is 0x00 or 0xff depending on the sign */
5935           if (runtimeSign)
5936             {
5937               emitcode ("mov",  "c,F0");
5938               emitcode ("subb", "a,acc");
5939               emitcode ("xch",  "a,b"); /* 2 */
5940               while (size--)
5941                 aopPut (result, "b", offset++); /* write msb's */
5942             }
5943           else /* compiletimeSign */
5944             while (size--)
5945               aopPut (result, "#0xff", offset++); /* write msb's */
5946         }
5947       aopPut (result, "a", 0); /* 3: write lsb */
5948     }
5949   else
5950     {
5951       _G.accInUse++;
5952       aopOp(result, ic, TRUE, FALSE);
5953       size = AOP_SIZE (result) - 1;
5954
5955       aopPut (result, "a", 0);
5956       while (size--)
5957         aopPut (result, zero, offset++);
5958     }
5959   _G.accInUse--;
5960   popB (pushedB);
5961 }
5962
5963 /*-----------------------------------------------------------------*/
5964 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5965 /*-----------------------------------------------------------------*/
5966 static void genDivTwoByte (operand *left, operand *right,
5967                             operand *result, iCode *ic)
5968 {
5969         sym_link *retype = getSpec(operandType(right));
5970         sym_link *letype = getSpec(operandType(left));
5971         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5972         symbol *lbl;
5973
5974         /* save EA bit in F1 */
5975         lbl = newiTempLabel(NULL);
5976         emitcode ("setb","F1");
5977         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5978         emitcode ("clr","F1");
5979         emitLabel (lbl);
5980
5981         /* load up MA with left */
5982         if (!umult) {
5983                 emitcode("clr","F0");
5984                 lbl = newiTempLabel(NULL);
5985                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5986                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5987                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5988                 emitcode ("xch", "a,b");
5989                 emitcode ("cpl","a");
5990                 emitcode ("add", "a,#1");
5991                 emitcode ("xch", "a,b");
5992                 emitcode ("cpl", "a"); // msb
5993                 emitcode ("addc","a,#0");
5994                 emitcode ("setb","F0");
5995                 emitLabel (lbl);
5996                 emitcode ("mov","ma,b");
5997                 emitcode ("mov","ma,a");
5998         } else {
5999                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6000                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6001         }
6002
6003         /* load up MB with right */
6004         if (!umult) {
6005                 if (AOP_TYPE(right) == AOP_LIT) {
6006                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6007                         if (val < 0) {
6008                                 lbl = newiTempLabel(NULL);
6009                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
6010                                 emitcode("setb","F0");
6011                                 emitLabel (lbl);
6012                                 val = -val;
6013                         }
6014                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6015                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6016                 } else {
6017                         lbl = newiTempLabel(NULL);
6018                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6019                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6020                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6021                         emitcode ("xch", "a,b");
6022                         emitcode ("cpl","a");
6023                         emitcode ("add", "a,#1");
6024                         emitcode ("xch", "a,b");
6025                         emitcode ("cpl", "a"); // msb
6026                         emitcode ("addc", "a,#0");
6027                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
6028                         emitcode ("setb","F0");
6029                         emitLabel (lbl);
6030                         emitcode ("mov","mb,b");
6031                         emitcode ("mov","mb,a");
6032                 }
6033         } else {
6034                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6035                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6036         }
6037
6038         /* wait for multiplication to finish */
6039         lbl = newiTempLabel(NULL);
6040         emitLabel (lbl);
6041         emitcode("mov","a,mcnt1");
6042         emitcode("anl","a,#!constbyte",0x80);
6043         emitcode("jnz","!tlabel",lbl->key+100);
6044
6045         freeAsmop (left, NULL, ic, TRUE);
6046         freeAsmop (right, NULL, ic,TRUE);
6047         aopOp(result, ic, TRUE, FALSE);
6048
6049         /* if unsigned then simple */
6050         if (umult) {
6051                 aopPut(result,"ma",1);
6052                 aopPut(result,"ma",0);
6053         } else {
6054                 emitcode("push","ma");
6055                 MOVA("ma");
6056                 /* negate result if needed */
6057                 lbl = newiTempLabel(NULL);
6058                 emitcode("jnb","F0,!tlabel",lbl->key+100);
6059                 emitcode("cpl","a");
6060                 emitcode("add","a,#1");
6061                 emitLabel (lbl);
6062                 aopPut(result,"a",0);
6063                 emitcode("pop","acc");
6064                 lbl = newiTempLabel(NULL);
6065                 emitcode("jnb","F0,!tlabel",lbl->key+100);
6066                 emitcode("cpl","a");
6067                 emitcode("addc","a,#0");
6068                 emitLabel (lbl);
6069                 aopPut(result,"a",1);
6070         }
6071         freeAsmop (result, NULL, ic, TRUE);
6072         /* restore EA bit in F1 */
6073         lbl = newiTempLabel(NULL);
6074         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6075         emitcode ("setb","EA");
6076         emitLabel (lbl);
6077         return ;
6078 }
6079
6080 /*-----------------------------------------------------------------*/
6081 /* genDiv - generates code for division                            */
6082 /*-----------------------------------------------------------------*/
6083 static void
6084 genDiv (iCode * ic)
6085 {
6086   operand *left = IC_LEFT (ic);
6087   operand *right = IC_RIGHT (ic);
6088   operand *result = IC_RESULT (ic);
6089
6090   D (emitcode (";", "genDiv"));
6091
6092   /* assign the amsops */
6093   AOP_OP_2 (ic);
6094
6095   /* special cases first */
6096   /* both are bits */
6097   if (AOP_TYPE (left) == AOP_CRY &&
6098       AOP_TYPE (right) == AOP_CRY)
6099     {
6100       genDivbits (left, right, result, ic);
6101       goto release;
6102     }
6103
6104   /* if both are of size == 1 */
6105   if (AOP_SIZE (left) == 1 &&
6106       AOP_SIZE (right) == 1)
6107     {
6108       genDivOneByte (left, right, result, ic);
6109       goto release;
6110     }
6111
6112   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6113           /* use the ds390 ARITHMETIC accel UNIT */
6114           genDivTwoByte (left, right, result, ic);
6115           return ;
6116   }
6117   /* should have been converted to function call */
6118   assert (0);
6119 release:
6120   freeAsmop (result, NULL, ic, TRUE);
6121   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6122   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6123 }
6124
6125 /*-----------------------------------------------------------------*/
6126 /* genModbits :- modulus of bits                                   */
6127 /*-----------------------------------------------------------------*/
6128 static void
6129 genModbits (operand * left,
6130             operand * right,
6131             operand * result,
6132             iCode   * ic)
6133 {
6134   char *l;
6135   bool pushedB;
6136
6137   D (emitcode (";", "genModbits"));
6138
6139   pushedB = pushB ();
6140
6141   /* the result must be bit */
6142   LOAD_AB_FOR_DIV (left, right, l);
6143   emitcode ("div", "ab");
6144   emitcode ("mov", "a,b");
6145   emitcode ("rrc", "a");
6146   aopOp(result, ic, TRUE, FALSE);
6147
6148   popB (pushedB);
6149
6150   aopPut (result, "c", 0);
6151 }
6152
6153 /*-----------------------------------------------------------------*/
6154 /* genModOneByte : 8 bit modulus                                   */
6155 /*-----------------------------------------------------------------*/
6156 static void
6157 genModOneByte (operand * left,
6158                operand * right,
6159                operand * result,
6160                iCode   * ic)
6161 {
6162   bool lUnsigned, rUnsigned, pushedB;
6163   bool runtimeSign, compiletimeSign;
6164   char *l;
6165   symbol *lbl;
6166   int size, offset;
6167
6168   D (emitcode (";", "genModOneByte"));
6169
6170   offset = 1;
6171   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6172   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6173
6174   pushedB = pushB ();
6175
6176   /* signed or unsigned */
6177   if (lUnsigned && rUnsigned)
6178     {
6179       /* unsigned is easy */
6180       LOAD_AB_FOR_DIV (left, right, l);
6181       emitcode ("div", "ab");
6182       aopOp (result, ic, TRUE, FALSE);
6183       aopPut (result, "b", 0);
6184
6185       for (size = AOP_SIZE (result) - 1; size--;)
6186         aopPut (result, zero, offset++);
6187
6188       popB (pushedB);
6189       return;
6190     }
6191
6192   /* signed is a little bit more difficult */
6193
6194   /* now sign adjust for both left & right */
6195
6196   /* modulus: sign of the right operand has no influence on the result! */
6197   if (AOP_TYPE(right) == AOP_LIT)
6198     {
6199       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
6200
6201       if (!rUnsigned && val < 0)
6202         emitcode ("mov", "b,#0x%02x", -val);
6203       else
6204         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6205     }
6206   else /* not literal */
6207     {
6208       if (rUnsigned)
6209         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6210       else
6211         {
6212           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6213           lbl = newiTempLabel (NULL);
6214           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6215           emitcode ("cpl", "a");  /* 2's complement */
6216           emitcode ("inc", "a");
6217           emitLabel (lbl);
6218           emitcode ("mov", "b,a");
6219         }
6220     }
6221
6222   /* let's see what's needed: */
6223   /* apply negative sign during runtime */
6224   runtimeSign = FALSE;
6225   /* negative sign from literals */
6226   compiletimeSign = FALSE;
6227
6228   /* sign adjust left side */
6229   if (AOP_TYPE(left) == AOP_LIT)
6230     {
6231       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
6232
6233       if (!lUnsigned && val < 0)
6234         {
6235           compiletimeSign = TRUE; /* set sign flag */
6236           emitcode ("mov", "a,#0x%02x", -val);
6237         }
6238       else
6239         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6240     }
6241   else /* ! literal */
6242     {
6243       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6244
6245       if (!lUnsigned)
6246         {
6247           runtimeSign = TRUE;
6248           emitcode ("clr", "F0"); /* clear sign flag */
6249
6250           lbl = newiTempLabel (NULL);
6251           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6252           emitcode ("setb", "F0"); /* set sign flag */
6253           emitcode ("cpl", "a");   /* 2's complement */
6254           emitcode ("inc", "a");
6255           emitLabel (lbl);
6256         }
6257     }
6258
6259   /* now the modulus */
6260   emitcode ("nop", "; workaround for DS80C390 div bug.");
6261   emitcode ("div", "ab");
6262
6263   if (runtimeSign || compiletimeSign)
6264     {
6265       emitcode ("mov", "a,b");
6266       lbl = newiTempLabel (NULL);
6267       if (runtimeSign)
6268         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6269       emitcode ("cpl", "a"); /* lsb 2's complement */
6270       emitcode ("inc", "a");
6271       emitLabel (lbl);
6272
6273       _G.accInUse++;
6274       aopOp (result, ic, TRUE, FALSE);
6275       size = AOP_SIZE (result) - 1;
6276
6277       if (size > 0)
6278         {
6279           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6280              then the result will be in b, a */
6281           emitcode ("mov", "b,a"); /* 1 */
6282           /* msb is 0x00 or 0xff depending on the sign */
6283           if (runtimeSign)
6284             {
6285               emitcode ("mov",  "c,F0");
6286               emitcode ("subb", "a,acc");
6287               emitcode ("xch",  "a,b"); /* 2 */
6288               while (size--)
6289                 aopPut (result, "b", offset++); /* write msb's */
6290             }
6291           else /* compiletimeSign */
6292             while (size--)
6293               aopPut (result, "#0xff", offset++); /* write msb's */
6294         }
6295       aopPut (result, "a", 0); /* 3: write lsb */
6296     }
6297   else
6298     {
6299       _G.accInUse++;
6300       aopOp(result, ic, TRUE, FALSE);
6301       size = AOP_SIZE (result) - 1;
6302
6303       aopPut (result, "b", 0);
6304       while (size--)
6305         aopPut (result, zero, offset++);
6306     }
6307   _G.accInUse--;
6308   popB (pushedB);
6309 }
6310
6311 /*-----------------------------------------------------------------*/
6312 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6313 /*-----------------------------------------------------------------*/
6314 static void genModTwoByte (operand *left, operand *right,
6315                             operand *result, iCode *ic)
6316 {
6317         sym_link *retype = getSpec(operandType(right));
6318         sym_link *letype = getSpec(operandType(left));
6319         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6320         symbol *lbl;
6321
6322         /* load up MA with left */
6323         /* save EA bit in F1 */
6324         lbl = newiTempLabel(NULL);
6325         emitcode ("setb","F1");
6326         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6327         emitcode ("clr","F1");
6328         emitLabel (lbl);
6329
6330         if (!umult) {
6331                 lbl = newiTempLabel(NULL);
6332                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6333                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6334                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6335                 emitcode ("xch", "a,b");
6336                 emitcode ("cpl","a");
6337                 emitcode ("add", "a,#1");
6338                 emitcode ("xch", "a,b");
6339                 emitcode ("cpl", "a"); // msb
6340                 emitcode ("addc","a,#0");
6341                 emitLabel (lbl);
6342                 emitcode ("mov","ma,b");
6343                 emitcode ("mov","ma,a");
6344         } else {
6345                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6346                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6347         }
6348
6349         /* load up MB with right */
6350         if (!umult) {
6351                 if (AOP_TYPE(right) == AOP_LIT) {
6352                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6353                         if (val < 0) {
6354                                 val = -val;
6355                         }
6356                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6357                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6358                 } else {
6359                         lbl = newiTempLabel(NULL);
6360                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6361                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6362                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6363                         emitcode ("xch", "a,b");
6364                         emitcode ("cpl","a");
6365                         emitcode ("add", "a,#1");
6366                         emitcode ("xch", "a,b");
6367                         emitcode ("cpl", "a"); // msb
6368                         emitcode ("addc", "a,#0");
6369                         emitLabel (lbl);
6370                         emitcode ("mov","mb,b");
6371                         emitcode ("mov","mb,a");
6372                 }
6373         } else {
6374                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6375                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6376         }
6377
6378         /* wait for multiplication to finish */
6379         lbl = newiTempLabel(NULL);
6380         emitLabel (lbl);
6381         emitcode("mov","a,mcnt1");
6382         emitcode("anl","a,#!constbyte",0x80);
6383         emitcode("jnz","!tlabel",lbl->key+100);
6384
6385         freeAsmop (left, NULL, ic, TRUE);
6386         freeAsmop (right, NULL, ic,TRUE);
6387         aopOp(result, ic, TRUE, FALSE);
6388
6389         aopPut(result,"mb",1);
6390         aopPut(result,"mb",0);
6391         freeAsmop (result, NULL, ic, TRUE);
6392
6393         /* restore EA bit in F1 */
6394         lbl = newiTempLabel(NULL);
6395         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6396         emitcode ("setb","EA");
6397         emitLabel (lbl);
6398 }
6399
6400 /*-----------------------------------------------------------------*/
6401 /* genMod - generates code for division                            */
6402 /*-----------------------------------------------------------------*/
6403 static void
6404 genMod (iCode * ic)
6405 {
6406   operand *left = IC_LEFT (ic);
6407   operand *right = IC_RIGHT (ic);
6408   operand *result = IC_RESULT (ic);
6409
6410   D (emitcode (";", "genMod"));
6411
6412   /* assign the asmops */
6413   AOP_OP_2 (ic);
6414
6415   /* special cases first */
6416   /* both are bits */
6417   if (AOP_TYPE (left) == AOP_CRY &&
6418       AOP_TYPE (right) == AOP_CRY)
6419     {
6420       genModbits (left, right, result, ic);
6421       goto release;
6422     }
6423
6424   /* if both are of size == 1 */
6425   if (AOP_SIZE (left) == 1 &&
6426       AOP_SIZE (right) == 1)
6427     {
6428       genModOneByte (left, right, result, ic);
6429       goto release;
6430     }
6431
6432   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6433           /* use the ds390 ARITHMETIC accel UNIT */
6434           genModTwoByte (left, right, result, ic);
6435           return ;
6436   }
6437
6438   /* should have been converted to function call */
6439   assert (0);
6440
6441 release:
6442   freeAsmop (result, NULL, ic, TRUE);
6443   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6444   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6445 }
6446
6447 /*-----------------------------------------------------------------*/
6448 /* genIfxJump :- will create a jump depending on the ifx           */
6449 /*-----------------------------------------------------------------*/
6450 static void
6451 genIfxJump (iCode * ic, char *jval, iCode *popIc)
6452 {
6453   symbol *jlbl;
6454   symbol *tlbl = newiTempLabel (NULL);
6455   char *inst;
6456
6457   /* if there is something to be popped then do it first */
6458   popForBranch (popIc, TRUE);
6459
6460   D (emitcode (";", "genIfxJump"));
6461
6462   /* if true label then we jump if condition
6463      supplied is true */
6464   if (IC_TRUE (ic))
6465     {
6466       jlbl = IC_TRUE (ic);
6467       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6468                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6469     }
6470   else
6471     {
6472       /* false label is present */
6473       jlbl = IC_FALSE (ic);
6474       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6475                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6476     }
6477   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6478     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6479   else
6480     emitcode (inst, "!tlabel", tlbl->key + 100);
6481   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6482   emitLabel (tlbl);
6483
6484   /* mark the icode as generated */
6485   ic->generated = 1;
6486 }
6487
6488 /*-----------------------------------------------------------------*/
6489 /* genCmp :- greater or less than comparison                       */
6490 /*-----------------------------------------------------------------*/
6491 static void
6492 genCmp (operand * left, operand * right,
6493         iCode * ic, iCode * ifx, int sign)
6494 {
6495   int size, offset = 0;
6496   unsigned long lit = 0L;
6497   operand *result;
6498
6499   D (emitcode (";", "genCmp"));
6500
6501   result = IC_RESULT (ic);
6502
6503   /* if left & right are bit variables */
6504   if (AOP_TYPE (left) == AOP_CRY &&
6505       AOP_TYPE (right) == AOP_CRY)
6506     {
6507       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6508       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6509     }
6510   else
6511     {
6512       /* subtract right from left if at the
6513          end the carry flag is set then we know that
6514          left is greater than right */
6515       size = max (AOP_SIZE (left), AOP_SIZE (right));
6516
6517       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6518       if ((size == 1) && !sign &&
6519           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6520         {
6521           symbol *lbl = newiTempLabel (NULL);
6522           emitcode ("cjne", "%s,%s,!tlabel",
6523                     aopGet (left, offset, FALSE, FALSE, NULL),
6524                     aopGet (right, offset, FALSE, FALSE, NULL),
6525                     lbl->key + 100);
6526           emitLabel (lbl);
6527         }
6528       else
6529         {
6530           if (AOP_TYPE (right) == AOP_LIT)
6531             {
6532               lit = ulFromVal (AOP (right)->aopu.aop_lit);
6533               /* optimize if(x < 0) or if(x >= 0) */
6534               if (lit == 0L)
6535                 {
6536                   if (!sign)
6537                     {
6538                       CLRC;
6539                     }
6540                   else
6541                     {
6542                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6543
6544                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6545                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6546
6547                       aopOp (result, ic, FALSE, FALSE);
6548
6549                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6550                         {
6551                           freeAsmop (result, NULL, ic, TRUE);
6552                           genIfxJump (ifx, "acc.7", ic->next);
6553                           return;
6554                         }
6555                       else
6556                         {
6557                           emitcode ("rlc", "a");
6558                         }
6559                       goto release_freedLR;
6560                     }
6561                   goto release;
6562                 }
6563             }
6564           CLRC;
6565           while (size--)
6566             {
6567               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6568               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6569               // emitcode (";", "genCmp #2");
6570               if (sign && (size == 0))
6571                 {
6572                   // emitcode (";", "genCmp #3");
6573                   emitcode ("xrl", "a,#!constbyte",0x80);
6574                   if (AOP_TYPE (right) == AOP_LIT)
6575                     {
6576                       unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
6577                       // emitcode (";", "genCmp #3.1");
6578                       emitcode ("subb", "a,#!constbyte",
6579                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6580                     }
6581                   else
6582                     {
6583                       // emitcode (";", "genCmp #3.2");
6584                       saveAccWarn = 0;
6585                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6586                       saveAccWarn = DEFAULT_ACC_WARNING;
6587                       emitcode ("xrl", "b,#!constbyte",0x80);
6588                       emitcode ("subb", "a,b");
6589                     }
6590                 }
6591               else
6592                 {
6593                   const char *s;
6594
6595                   // emitcode (";", "genCmp #4");
6596                   saveAccWarn = 0;
6597                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6598                   saveAccWarn = DEFAULT_ACC_WARNING;
6599
6600                   emitcode ("subb", "a,%s", s);
6601                 }
6602             }
6603         }
6604     }
6605
6606 release:
6607 /* Don't need the left & right operands any more; do need the result. */
6608   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6609   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6610
6611   aopOp (result, ic, FALSE, FALSE);
6612
6613 release_freedLR:
6614
6615   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6616     {
6617       outBitC (result);
6618     }
6619   else
6620     {
6621       /* if the result is used in the next
6622          ifx conditional branch then generate
6623          code a little differently */
6624       if (ifx)
6625         {
6626           genIfxJump (ifx, "c", ic->next);
6627         }
6628       else
6629         {
6630           outBitC (result);
6631         }
6632       /* leave the result in acc */
6633     }
6634   freeAsmop (result, NULL, ic, TRUE);
6635 }
6636
6637 /*-----------------------------------------------------------------*/
6638 /* genCmpGt :- greater than comparison                             */
6639 /*-----------------------------------------------------------------*/
6640 static void
6641 genCmpGt (iCode * ic, iCode * ifx)
6642 {
6643   operand *left, *right;
6644   sym_link *letype, *retype;
6645   int sign;
6646
6647   D (emitcode (";", "genCmpGt"));
6648
6649   left = IC_LEFT (ic);
6650   right = IC_RIGHT (ic);
6651
6652   letype = getSpec (operandType (left));
6653   retype = getSpec (operandType (right));
6654   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6655
6656   /* assign the left & right amsops */
6657   AOP_OP_2 (ic);
6658
6659   genCmp (right, left, ic, ifx, sign);
6660 }
6661
6662 /*-----------------------------------------------------------------*/
6663 /* genCmpLt - less than comparisons                                */
6664 /*-----------------------------------------------------------------*/
6665 static void
6666 genCmpLt (iCode * ic, iCode * ifx)
6667 {
6668   operand *left, *right;
6669   sym_link *letype, *retype;
6670   int sign;
6671
6672   D (emitcode (";", "genCmpLt"));
6673
6674   left = IC_LEFT (ic);
6675   right = IC_RIGHT (ic);
6676
6677   letype = getSpec (operandType (left));
6678   retype = getSpec (operandType (right));
6679   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6680
6681   /* assign the left & right amsops */
6682   AOP_OP_2 (ic);
6683
6684   genCmp (left, right, ic, ifx, sign);
6685 }
6686
6687 /*-----------------------------------------------------------------*/
6688 /* gencjneshort - compare and jump if not equal                    */
6689 /*-----------------------------------------------------------------*/
6690 static void
6691 gencjneshort (operand * left, operand * right, symbol * lbl)
6692 {
6693   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6694   int offset = 0;
6695   unsigned long lit = 0L;
6696
6697   D (emitcode (";", "gencjneshort"));
6698
6699   /* if the left side is a literal or
6700      if the right is in a pointer register and left
6701      is not */
6702   if ((AOP_TYPE (left) == AOP_LIT)  ||
6703       (AOP_TYPE (left) == AOP_IMMD) ||
6704       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6705     {
6706       operand *t = right;
6707       right = left;
6708       left = t;
6709     }
6710
6711   if (AOP_TYPE (right) == AOP_LIT)
6712     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6713
6714   if (opIsGptr (left) || opIsGptr (right))
6715     {
6716       /* We are comparing a generic pointer to something.
6717        * Exclude the generic type byte from the comparison.
6718        */
6719       size--;
6720       D (emitcode (";", "cjneshort: generic ptr special case."););
6721     }
6722
6723
6724   /* if the right side is a literal then anything goes */
6725   if (AOP_TYPE (right) == AOP_LIT &&
6726       AOP_TYPE (left) != AOP_DIR)
6727     {
6728       while (size--)
6729         {
6730           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6731           emitcode ("cjne", "a,%s,!tlabel",
6732                     aopGet (right, offset, FALSE, FALSE, NULL),
6733                     lbl->key + 100);
6734           offset++;
6735         }
6736     }
6737
6738   /* if the right side is in a register or in direct space or
6739      if the left is a pointer register & right is not */
6740   else if (AOP_TYPE (right) == AOP_REG ||
6741            AOP_TYPE (right) == AOP_DIR ||
6742            AOP_TYPE (right) == AOP_LIT ||
6743            AOP_TYPE (right) == AOP_IMMD ||
6744            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6745            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6746     {
6747       while (size--)
6748         {
6749           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6750           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6751               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6752             emitcode ("jnz", "!tlabel", lbl->key + 100);
6753           else
6754             emitcode ("cjne", "a,%s,!tlabel",
6755                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6756                       lbl->key + 100);
6757           offset++;
6758         }
6759     }
6760   else
6761     {
6762       /* right is a pointer reg need both a & b */
6763       while (size--)
6764         {
6765           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6766           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6767           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6768           offset++;
6769         }
6770     }
6771 }
6772
6773 /*-----------------------------------------------------------------*/
6774 /* gencjne - compare and jump if not equal                         */
6775 /*-----------------------------------------------------------------*/
6776 static void
6777 gencjne (operand * left, operand * right, symbol * lbl)
6778 {
6779   symbol *tlbl = newiTempLabel (NULL);
6780
6781   D (emitcode (";", "gencjne"));
6782
6783   gencjneshort (left, right, lbl);
6784
6785   emitcode ("mov", "a,%s", one);
6786   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6787   emitLabel (lbl);
6788   emitcode ("clr", "a");
6789   emitLabel (tlbl);
6790 }
6791
6792 /*-----------------------------------------------------------------*/
6793 /* genCmpEq - generates code for equal to                          */
6794 /*-----------------------------------------------------------------*/
6795 static void
6796 genCmpEq (iCode * ic, iCode * ifx)
6797 {
6798   operand *left, *right, *result;
6799   iCode * popIc = ic->next;
6800
6801   D (emitcode (";", "genCmpEq"));
6802
6803   AOP_OP_2 (ic);
6804   AOP_SET_LOCALS (ic);
6805
6806   /* if literal, literal on the right or
6807      if the right is in a pointer register and left
6808      is not */
6809   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6810       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6811     {
6812       operand *t = IC_RIGHT (ic);
6813       IC_RIGHT (ic) = IC_LEFT (ic);
6814       IC_LEFT (ic) = t;
6815     }
6816
6817   if (ifx &&                    /* !AOP_SIZE(result) */
6818       OP_SYMBOL (result) &&
6819       OP_SYMBOL (result)->regType == REG_CND)
6820     {
6821       symbol *tlbl;
6822       /* if they are both bit variables */
6823       if (AOP_TYPE (left) == AOP_CRY &&
6824           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6825         {
6826           if (AOP_TYPE (right) == AOP_LIT)
6827             {
6828               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6829               if (lit == 0L)
6830                 {
6831                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6832                   emitcode ("cpl", "c");
6833                 }
6834               else if (lit == 1L)
6835                 {
6836                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6837                 }
6838               else
6839                 {
6840                   emitcode ("clr", "c");
6841                 }
6842               /* AOP_TYPE(right) == AOP_CRY */
6843             }
6844           else
6845             {
6846               symbol *lbl = newiTempLabel (NULL);
6847               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6848               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6849               emitcode ("cpl", "c");
6850               emitLabel (lbl);
6851             }
6852           /* if true label then we jump if condition
6853              supplied is true */
6854           tlbl = newiTempLabel (NULL);
6855           if (IC_TRUE (ifx))
6856             {
6857               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6858               popForBranch (popIc, FALSE);
6859               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6860             }
6861           else
6862             {
6863               emitcode ("jc", "!tlabel", tlbl->key + 100);
6864               popForBranch (popIc, FALSE);
6865               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6866             }
6867           emitLabel (tlbl);
6868         }
6869       else
6870         {
6871           tlbl = newiTempLabel (NULL);
6872           gencjneshort (left, right, tlbl);
6873           if (IC_TRUE (ifx))
6874             {
6875               popForBranch (popIc, FALSE);
6876               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6877               emitLabel (tlbl);
6878             }
6879           else
6880             {
6881               symbol *lbl = newiTempLabel (NULL);
6882               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6883               emitLabel (tlbl);
6884               popForBranch (popIc, FALSE);
6885               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6886               emitLabel (lbl);
6887             }
6888         }
6889       /* mark the icode as generated */
6890       ifx->generated = 1;
6891
6892       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6893       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6894       return;
6895     }
6896
6897   /* if they are both bit variables */
6898   if (AOP_TYPE (left) == AOP_CRY &&
6899       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6900     {
6901       if (AOP_TYPE (right) == AOP_LIT)
6902         {
6903           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6904           if (lit == 0L)
6905             {
6906               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6907               emitcode ("cpl", "c");
6908             }
6909           else if (lit == 1L)
6910             {
6911               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6912             }
6913           else
6914             {
6915               emitcode ("clr", "c");
6916             }
6917           /* AOP_TYPE(right) == AOP_CRY */
6918         }
6919       else
6920         {
6921           symbol *lbl = newiTempLabel (NULL);
6922           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6923           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6924           emitcode ("cpl", "c");
6925           emitLabel (lbl);
6926         }
6927
6928       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6929       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6930
6931       aopOp (result, ic, TRUE, FALSE);
6932
6933       /* c = 1 if egal */
6934       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6935         {
6936           outBitC (result);
6937           goto release;
6938         }
6939       if (ifx)
6940         {
6941           genIfxJump (ifx, "c", popIc);
6942           goto release;
6943         }
6944       /* if the result is used in an arithmetic operation
6945          then put the result in place */
6946       outBitC (result);
6947     }
6948   else
6949     {
6950       gencjne (left, right, newiTempLabel (NULL));
6951
6952       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6953       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6954
6955       aopOp (result, ic, TRUE, FALSE);
6956
6957       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6958         {
6959           aopPut (result, "a", 0);
6960           goto release;
6961         }
6962       if (ifx)
6963         {
6964           genIfxJump (ifx, "a", popIc);
6965           goto release;
6966         }
6967       /* if the result is used in an arithmetic operation
6968          then put the result in place */
6969       if (AOP_TYPE (result) != AOP_CRY)
6970         outAcc (result);
6971       /* leave the result in acc */
6972     }
6973
6974 release:
6975   freeAsmop (result, NULL, ic, TRUE);
6976 }
6977
6978 /*-----------------------------------------------------------------*/
6979 /* ifxForOp - returns the icode containing the ifx for operand     */
6980 /*-----------------------------------------------------------------*/
6981 static iCode *
6982 ifxForOp (operand * op, iCode * ic)
6983 {
6984   iCode *ifxIc;
6985
6986   /* if true symbol then needs to be assigned */
6987   if (IS_TRUE_SYMOP (op))
6988     return NULL;
6989
6990   /* if this has register type condition and
6991      while skipping ipop's (see bug 1509084),
6992      the next instruction is ifx with the same operand
6993      and live to of the operand is upto the ifx only then */
6994   for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
6995   if (ifxIc && ifxIc->op == IFX &&
6996       IC_COND (ifxIc)->key == op->key &&
6997       OP_SYMBOL (op)->liveTo <= ifxIc->seq)
6998     return ifxIc;
6999
7000   return NULL;
7001 }
7002
7003 /*-----------------------------------------------------------------*/
7004 /* hasInc - operand is incremented before any other use            */
7005 /*-----------------------------------------------------------------*/
7006 static iCode *
7007 hasInc (operand *op, iCode *ic, int osize)
7008 {
7009   sym_link *type = operandType(op);
7010   sym_link *retype = getSpec (type);
7011   iCode *lic = ic->next;
7012   int isize ;
7013
7014   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
7015   if (!IS_SYMOP(op)) return NULL;
7016
7017   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
7018   if (IS_AGGREGATE(type->next)) return NULL;
7019   if (osize != (isize = getSize(type->next))) return NULL;
7020
7021   while (lic)
7022     {
7023       /* if operand of the form op = op + <sizeof *op> */
7024       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
7025           isOperandEqual(IC_RESULT(lic),op) &&
7026           isOperandLiteral(IC_RIGHT(lic)) &&
7027           operandLitValue(IC_RIGHT(lic)) == isize)
7028         {
7029           return lic;
7030         }
7031       /* if the operand used or deffed */
7032       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key)
7033         {
7034           return NULL;
7035         }
7036       /* if GOTO or IFX */
7037       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
7038       lic = lic->next;
7039     }
7040   return NULL;
7041 }
7042
7043 /*-----------------------------------------------------------------*/
7044 /* genAndOp - for && operation                                     */
7045 /*-----------------------------------------------------------------*/
7046 static void
7047 genAndOp (iCode * ic)
7048 {
7049   operand *left, *right, *result;
7050   symbol *tlbl;
7051
7052   D (emitcode (";", "genAndOp"));
7053
7054   /* note here that && operations that are in an
7055      if statement are taken away by backPatchLabels
7056      only those used in arthmetic operations remain */
7057   AOP_OP_2 (ic);
7058   AOP_SET_LOCALS (ic);
7059
7060   /* if both are bit variables */
7061   if (AOP_TYPE (left) == AOP_CRY &&
7062       AOP_TYPE (right) == AOP_CRY)
7063     {
7064       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7065       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
7066       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7067       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7068
7069       aopOp (result,ic,FALSE, FALSE);
7070       outBitC (result);
7071     }
7072   else
7073     {
7074       tlbl = newiTempLabel (NULL);
7075       toBoolean (left);
7076       emitcode ("jz", "!tlabel", tlbl->key + 100);
7077       toBoolean (right);
7078       emitLabel (tlbl);
7079       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7080       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7081
7082       aopOp (result,ic,FALSE, FALSE);
7083       outBitAcc (result);
7084     }
7085
7086   freeAsmop (result, NULL, ic, TRUE);
7087 }
7088
7089
7090 /*-----------------------------------------------------------------*/
7091 /* genOrOp - for || operation                                      */
7092 /*-----------------------------------------------------------------*/
7093 static void
7094 genOrOp (iCode * ic)
7095 {
7096   operand *left, *right, *result;
7097   symbol *tlbl;
7098
7099   D (emitcode (";", "genOrOp"));
7100
7101   /* note here that || operations that are in an
7102      if statement are taken away by backPatchLabels
7103      only those used in arthmetic operations remain */
7104   AOP_OP_2 (ic);
7105   AOP_SET_LOCALS (ic);
7106
7107   /* if both are bit variables */
7108   if (AOP_TYPE (left) == AOP_CRY &&
7109       AOP_TYPE (right) == AOP_CRY)
7110     {
7111       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7112       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7113       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7114       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7115
7116       aopOp (result,ic,FALSE, FALSE);
7117
7118       outBitC (result);
7119     }
7120   else
7121     {
7122       tlbl = newiTempLabel (NULL);
7123       toBoolean (left);
7124       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7125       toBoolean (right);
7126       emitLabel (tlbl);
7127       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7128       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7129
7130       aopOp (result,ic,FALSE, FALSE);
7131
7132       outBitAcc (result);
7133     }
7134
7135   freeAsmop (result, NULL, ic, TRUE);
7136 }
7137
7138 /*-----------------------------------------------------------------*/
7139 /* isLiteralBit - test if lit == 2^n                               */
7140 /*-----------------------------------------------------------------*/
7141 static int
7142 isLiteralBit (unsigned long lit)
7143 {
7144   unsigned long pw[32] =
7145   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7146    0x100L, 0x200L, 0x400L, 0x800L,
7147    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7148    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7149    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7150    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7151    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7152   int idx;
7153
7154   for (idx = 0; idx < 32; idx++)
7155     if (lit == pw[idx])
7156       return idx + 1;
7157   return 0;
7158 }
7159
7160 /*-----------------------------------------------------------------*/
7161 /* continueIfTrue -                                                */
7162 /*-----------------------------------------------------------------*/
7163 static void
7164 continueIfTrue (iCode * ic)
7165 {
7166   if (IC_TRUE (ic))
7167     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7168   ic->generated = 1;
7169 }
7170
7171 /*-----------------------------------------------------------------*/
7172 /* jmpIfTrue -                                                     */
7173 /*-----------------------------------------------------------------*/
7174 static void
7175 jumpIfTrue (iCode * ic)
7176 {
7177   if (!IC_TRUE (ic))
7178     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7179   ic->generated = 1;
7180 }
7181
7182 /*-----------------------------------------------------------------*/
7183 /* jmpTrueOrFalse -                                                */
7184 /*-----------------------------------------------------------------*/
7185 static void
7186 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7187 {
7188   // ugly but optimized by peephole
7189   if (IC_TRUE (ic))
7190     {
7191       symbol *nlbl = newiTempLabel (NULL);
7192       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7193       emitLabel (tlbl);
7194       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7195       emitLabel (nlbl);
7196     }
7197   else
7198     {
7199       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7200       emitLabel (tlbl);
7201     }
7202   ic->generated = 1;
7203 }
7204
7205 // Generate code to perform a bit-wise logic operation
7206 // on two operands in far space (assumed to already have been
7207 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7208 // in far space. This requires pushing the result on the stack
7209 // then popping it into the result.
7210 static void
7211 genFarFarLogicOp(iCode *ic, char *logicOp)
7212 {
7213       int size, resultSize, compSize;
7214       int offset = 0;
7215
7216       TR_AP("#5");
7217       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7218       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7219                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7220
7221       _startLazyDPSEvaluation();
7222       for (size = compSize; (size--); offset++)
7223       {
7224           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7225           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7226           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7227
7228           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7229           emitcode ("push", "acc");
7230       }
7231       _endLazyDPSEvaluation();
7232
7233       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7234       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7235       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7236
7237       resultSize = AOP_SIZE(IC_RESULT(ic));
7238
7239       ADJUST_PUSHED_RESULT(compSize, resultSize);
7240
7241       _startLazyDPSEvaluation();
7242       while (compSize--)
7243       {
7244           emitcode ("pop", "acc");
7245           aopPut (IC_RESULT (ic), "a", compSize);
7246       }
7247       _endLazyDPSEvaluation();
7248       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7249 }
7250
7251
7252 /*-----------------------------------------------------------------*/
7253 /* genAnd  - code for and                                          */
7254 /*-----------------------------------------------------------------*/
7255 static void
7256 genAnd (iCode * ic, iCode * ifx)
7257 {
7258   operand *left, *right, *result;
7259   int size, offset = 0;
7260   unsigned long lit = 0L;
7261   int bytelit = 0;
7262   char buffer[10];
7263   bool pushResult;
7264
7265   D (emitcode (";", "genAnd"));
7266
7267   AOP_OP_3_NOFATAL (ic, pushResult);
7268   AOP_SET_LOCALS (ic);
7269
7270   if (pushResult)
7271   {
7272       genFarFarLogicOp(ic, "anl");
7273       return;
7274   }
7275
7276 #ifdef DEBUG_TYPE
7277   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7278             AOP_TYPE (result),
7279             AOP_TYPE (left), AOP_TYPE (right));
7280   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7281             AOP_SIZE (result),
7282             AOP_SIZE (left), AOP_SIZE (right));
7283 #endif
7284
7285   /* if left is a literal & right is not then exchange them */
7286   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7287 #ifdef LOGIC_OPS_BROKEN
7288     ||  AOP_NEEDSACC (left)
7289 #endif
7290     )
7291     {
7292       operand *tmp = right;
7293       right = left;
7294       left = tmp;
7295     }
7296
7297   /* if result = right then exchange left and right */
7298   if (sameRegs (AOP (result), AOP (right)))
7299     {
7300       operand *tmp = right;
7301       right = left;
7302       left = tmp;
7303     }
7304
7305   /* if right is bit then exchange them */
7306   if (AOP_TYPE (right) == AOP_CRY &&
7307       AOP_TYPE (left) != AOP_CRY)
7308     {
7309       operand *tmp = right;
7310       right = left;
7311       left = tmp;
7312     }
7313   if (AOP_TYPE (right) == AOP_LIT)
7314     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7315
7316   size = AOP_SIZE (result);
7317
7318   // if(bit & yy)
7319   // result = bit & yy;
7320   if (AOP_TYPE (left) == AOP_CRY)
7321     {
7322       // c = bit & literal;
7323       if (AOP_TYPE (right) == AOP_LIT)
7324         {
7325           if (lit & 1)
7326             {
7327               if (size && sameRegs (AOP (result), AOP (left)))
7328                 // no change
7329                 goto release;
7330               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7331             }
7332           else
7333             {
7334               // bit(result) = 0;
7335               if (size && (AOP_TYPE (result) == AOP_CRY))
7336                 {
7337                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7338                   goto release;
7339                 }
7340               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7341                 {
7342                   jumpIfTrue (ifx);
7343                   goto release;
7344                 }
7345               emitcode ("clr", "c");
7346             }
7347         }
7348       else
7349         {
7350           if (AOP_TYPE (right) == AOP_CRY)
7351             {
7352               // c = bit & bit;
7353               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7354               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7355             }
7356           else
7357             {
7358               // c = bit & val;
7359               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7360               // c = lsb
7361               emitcode ("rrc", "a");
7362               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7363             }
7364         }
7365       // bit = c
7366       // val = c
7367       if (size)
7368         outBitC (result);
7369       // if(bit & ...)
7370       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7371         genIfxJump (ifx, "c", ic->next);
7372       goto release;
7373     }
7374
7375   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7376   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7377   if ((AOP_TYPE (right) == AOP_LIT) &&
7378       (AOP_TYPE (result) == AOP_CRY) &&
7379       (AOP_TYPE (left) != AOP_CRY))
7380     {
7381       int posbit = isLiteralBit (lit);
7382       /* left &  2^n */
7383       if (posbit)
7384         {
7385           posbit--;
7386           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7387           // bit = left & 2^n
7388           if (size)
7389             {
7390               switch (posbit & 0x07)
7391                 {
7392                   case 0: emitcode ("rrc", "a");
7393                           break;
7394                   case 7: emitcode ("rlc", "a");
7395                           break;
7396                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7397                           break;
7398                 }
7399             }
7400           // if(left &  2^n)
7401           else
7402             {
7403               if (ifx)
7404                 {
7405                   SNPRINTF (buffer, sizeof(buffer),
7406                             "acc.%d", posbit & 0x07);
7407                   genIfxJump (ifx, buffer, ic->next);
7408                 }
7409               else
7410                 {
7411                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7412                 }
7413               goto release;
7414             }
7415         }
7416       else
7417         {
7418           symbol *tlbl = newiTempLabel (NULL);
7419           int sizel = AOP_SIZE (left);
7420           if (size)
7421             emitcode ("setb", "c");
7422           while (sizel--)
7423             {
7424               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7425                 {
7426                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7427                   // byte ==  2^n ?
7428                   if ((posbit = isLiteralBit (bytelit)) != 0)
7429                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7430                   else
7431                     {
7432                       if (bytelit != 0x0FFL)
7433                         emitcode ("anl", "a,%s",
7434                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7435                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7436                     }
7437                 }
7438               offset++;
7439             }
7440           // bit = left & literal
7441           if (size)
7442             {
7443               emitcode ("clr", "c");
7444               emitLabel (tlbl);
7445             }
7446           // if(left & literal)
7447           else
7448             {
7449               if (ifx)
7450                 jmpTrueOrFalse (ifx, tlbl);
7451               else
7452                 emitLabel (tlbl);
7453               goto release;
7454             }
7455         }
7456       outBitC (result);
7457       goto release;
7458     }
7459
7460   /* if left is same as result */
7461   if (sameRegs (AOP (result), AOP (left)))
7462     {
7463       for (; size--; offset++)
7464         {
7465           if (AOP_TYPE (right) == AOP_LIT)
7466             {
7467               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7468               if (bytelit == 0x0FF)
7469                 {
7470                   /* dummy read of volatile operand */
7471                   if (isOperandVolatile (left, FALSE))
7472                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7473                   else
7474                     continue;
7475                 }
7476               else if (bytelit == 0)
7477                 {
7478                   aopPut (result, zero, offset);
7479                 }
7480               else if (IS_AOP_PREG (result))
7481                 {
7482                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7483                   emitcode ("anl", "a,%s",
7484                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7485                   aopPut (result, "a", offset);
7486                 }
7487               else
7488                 emitcode ("anl", "%s,%s",
7489                           aopGet (left, offset, FALSE, TRUE, NULL),
7490                           aopGet (right, offset, FALSE, FALSE, NULL));
7491             }
7492           else
7493             {
7494               if (AOP_TYPE (left) == AOP_ACC)
7495                 {
7496                   if (offset)
7497                     emitcode("mov", "a,b");
7498                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7499                 }
7500               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7501                 {
7502                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7503                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7504                   emitcode ("anl", "a,b");
7505                   aopPut (result, "a", offset);
7506                 }
7507               else if (aopGetUsesAcc (left, offset))
7508                 {
7509                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7510                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7511                   aopPut (result, "a", offset);
7512                 }
7513               else
7514                 {
7515                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7516                   if (IS_AOP_PREG (result))
7517                     {
7518                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7519                       aopPut (result, "a", offset);
7520                     }
7521                   else
7522                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7523                 }
7524             }
7525         }
7526     }
7527   else
7528     {
7529       // left & result in different registers
7530       if (AOP_TYPE (result) == AOP_CRY)
7531         {
7532           // result = bit
7533           // if(size), result in bit
7534           // if(!size && ifx), conditional oper: if(left & right)
7535           symbol *tlbl = newiTempLabel (NULL);
7536           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7537           if (size)
7538             emitcode ("setb", "c");
7539           while (sizer--)
7540             {
7541               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7542                   && AOP_TYPE(left)==AOP_ACC)
7543                 {
7544                   if (offset)
7545                     emitcode("mov", "a,b");
7546                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7547                 }
7548               else if (AOP_TYPE(left)==AOP_ACC)
7549                 {
7550                   if (!offset)
7551                     {
7552                       bool pushedB = pushB ();
7553                       emitcode("mov", "b,a");
7554                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7555                       emitcode("anl", "a,b");
7556                       popB (pushedB);
7557                     }
7558                   else
7559                     {
7560                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7561                       emitcode("anl", "a,b");
7562                     }
7563                 }
7564               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7565                 {
7566                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7567                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7568                   emitcode ("anl", "a,b");
7569                 }
7570               else if (aopGetUsesAcc (left, offset))
7571                 {
7572                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7573                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7574                 }
7575               else
7576                 {
7577                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7578                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7579                 }
7580
7581               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7582               offset++;
7583             }
7584           if (size)
7585             {
7586               CLRC;
7587               emitLabel (tlbl);
7588               outBitC (result);
7589             }
7590           else if (ifx)
7591             jmpTrueOrFalse (ifx, tlbl);
7592           else
7593             emitLabel (tlbl);
7594         }
7595       else
7596         {
7597           for (; (size--); offset++)
7598             {
7599               // normal case
7600               // result = left & right
7601               if (AOP_TYPE (right) == AOP_LIT)
7602                 {
7603                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7604                   if (bytelit == 0x0FF)
7605                     {
7606                       aopPut (result,
7607                               aopGet (left, offset, FALSE, FALSE, NULL),
7608                               offset);
7609                       continue;
7610                     }
7611                   else if (bytelit == 0)
7612                     {
7613                       /* dummy read of volatile operand */
7614                       if (isOperandVolatile (left, FALSE))
7615                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7616                       aopPut (result, zero, offset);
7617                       continue;
7618                     }
7619                   else if (AOP_TYPE (left) == AOP_ACC)
7620                     {
7621                       if (!offset)
7622                         {
7623                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7624                           aopPut (result, "a", offset);
7625                           continue;
7626                         }
7627                       else
7628                         {
7629                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7630                           aopPut (result, "b", offset);
7631                           continue;
7632                         }
7633                     }
7634                 }
7635               // faster than result <- left, anl result,right
7636               // and better if result is SFR
7637               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7638                   && AOP_TYPE(left)==AOP_ACC)
7639                 {
7640                   if (offset)
7641                     emitcode("mov", "a,b");
7642                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7643                 }
7644               else if (AOP_TYPE(left)==AOP_ACC)
7645                 {
7646                   if (!offset)
7647                     {
7648                       bool pushedB = pushB ();
7649                       emitcode("mov", "b,a");
7650                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7651                       emitcode("anl", "a,b");
7652                       popB (pushedB);
7653                     }
7654                   else
7655                     {
7656                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7657                       emitcode("anl", "a,b");
7658                     }
7659                 }
7660               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7661                 {
7662                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7663                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7664                   emitcode ("anl", "a,b");
7665                 }
7666               else if (aopGetUsesAcc (left, offset))
7667                 {
7668                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7669                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7670                 }
7671               else
7672                 {
7673                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7674                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7675                 }
7676               aopPut (result, "a", offset);
7677             }
7678         }
7679     }
7680
7681 release:
7682   freeAsmop (result, NULL, ic, TRUE);
7683   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7684   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7685 }
7686
7687 /*-----------------------------------------------------------------*/
7688 /* genOr  - code for or                                            */
7689 /*-----------------------------------------------------------------*/
7690 static void
7691 genOr (iCode * ic, iCode * ifx)
7692 {
7693   operand *left, *right, *result;
7694   int size, offset = 0;
7695   unsigned long lit = 0L;
7696   int bytelit = 0;
7697   bool     pushResult;
7698
7699   D (emitcode (";", "genOr"));
7700
7701   AOP_OP_3_NOFATAL (ic, pushResult);
7702   AOP_SET_LOCALS (ic);
7703
7704   if (pushResult)
7705   {
7706       genFarFarLogicOp(ic, "orl");
7707       return;
7708   }
7709
7710
7711 #ifdef DEBUG_TYPE
7712   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7713             AOP_TYPE (result),
7714             AOP_TYPE (left), AOP_TYPE (right));
7715   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7716             AOP_SIZE (result),
7717             AOP_SIZE (left), AOP_SIZE (right));
7718 #endif
7719
7720   /* if left is a literal & right is not then exchange them */
7721   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7722 #ifdef LOGIC_OPS_BROKEN
7723    || AOP_NEEDSACC (left) // I think this is a net loss now.
7724 #endif
7725       )
7726     {
7727       operand *tmp = right;
7728       right = left;
7729       left = tmp;
7730     }
7731
7732   /* if result = right then exchange them */
7733   if (sameRegs (AOP (result), AOP (right)))
7734     {
7735       operand *tmp = right;
7736       right = left;
7737       left = tmp;
7738     }
7739
7740   /* if right is bit then exchange them */
7741   if (AOP_TYPE (right) == AOP_CRY &&
7742       AOP_TYPE (left) != AOP_CRY)
7743     {
7744       operand *tmp = right;
7745       right = left;
7746       left = tmp;
7747     }
7748   if (AOP_TYPE (right) == AOP_LIT)
7749     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7750
7751   size = AOP_SIZE (result);
7752
7753   // if(bit | yy)
7754   // xx = bit | yy;
7755   if (AOP_TYPE (left) == AOP_CRY)
7756     {
7757       if (AOP_TYPE (right) == AOP_LIT)
7758         {
7759           // c = bit | literal;
7760           if (lit)
7761             {
7762               // lit != 0 => result = 1
7763               if (AOP_TYPE (result) == AOP_CRY)
7764                 {
7765                   if (size)
7766                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7767                   else if (ifx)
7768                     continueIfTrue (ifx);
7769                   goto release;
7770                 }
7771               emitcode ("setb", "c");
7772             }
7773           else
7774             {
7775               // lit == 0 => result = left
7776               if (size && sameRegs (AOP (result), AOP (left)))
7777                 goto release;
7778               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7779             }
7780         }
7781       else
7782         {
7783           if (AOP_TYPE (right) == AOP_CRY)
7784             {
7785               // c = bit | bit;
7786               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7787               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7788             }
7789           else
7790             {
7791               // c = bit | val;
7792               symbol *tlbl = newiTempLabel (NULL);
7793               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7794                 emitcode ("setb", "c");
7795               emitcode ("jb", "%s,!tlabel",
7796                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7797               toBoolean (right);
7798               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7799               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7800                 {
7801                   jmpTrueOrFalse (ifx, tlbl);
7802                   goto release;
7803                 }
7804               else
7805                 {
7806                   CLRC;
7807                   emitLabel (tlbl);
7808                 }
7809             }
7810         }
7811       // bit = c
7812       // val = c
7813       if (size)
7814         outBitC (result);
7815       // if(bit | ...)
7816       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7817         genIfxJump (ifx, "c", ic->next);
7818       goto release;
7819     }
7820
7821   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7822   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7823   if ((AOP_TYPE (right) == AOP_LIT) &&
7824       (AOP_TYPE (result) == AOP_CRY) &&
7825       (AOP_TYPE (left) != AOP_CRY))
7826     {
7827       if (lit)
7828         {
7829           // result = 1
7830           if (size)
7831             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7832           else
7833             continueIfTrue (ifx);
7834           goto release;
7835         }
7836       else
7837         {
7838           // lit = 0, result = boolean(left)
7839           if (size)
7840             emitcode ("setb", "c");
7841           toBoolean (right);
7842           if (size)
7843             {
7844               symbol *tlbl = newiTempLabel (NULL);
7845               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7846               CLRC;
7847               emitLabel (tlbl);
7848             }
7849           else
7850             {
7851               genIfxJump (ifx, "a", ic->next);
7852               goto release;
7853             }
7854         }
7855       outBitC (result);
7856       goto release;
7857     }
7858
7859   /* if left is same as result */
7860   if (sameRegs (AOP (result), AOP (left)))
7861     {
7862       for (; size--; offset++)
7863         {
7864           if (AOP_TYPE (right) == AOP_LIT)
7865             {
7866               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7867               if (bytelit == 0)
7868                 {
7869                   /* dummy read of volatile operand */
7870                   if (isOperandVolatile (left, FALSE))
7871                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7872                   else
7873                     continue;
7874                 }
7875               else if (bytelit == 0x0FF)
7876                 {
7877                   aopPut (result, "#0xFF", offset);
7878                 }
7879               else if (IS_AOP_PREG (left))
7880                 {
7881                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7882                   emitcode ("orl", "a,%s",
7883                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7884                   aopPut (result, "a", offset);
7885                 }
7886               else
7887                 {
7888                   emitcode ("orl", "%s,%s",
7889                             aopGet (left, offset, FALSE, TRUE, NULL),
7890                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7891                 }
7892             }
7893           else
7894             {
7895               if (AOP_TYPE (left) == AOP_ACC)
7896                 {
7897                   if (offset)
7898                     emitcode("mov", "a,b");
7899                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7900                 }
7901               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7902                 {
7903                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7904                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7905                   emitcode ("orl", "a,b");
7906                   aopPut (result, "a", offset);
7907                 }
7908               else if (aopGetUsesAcc (left, offset))
7909                 {
7910                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7911                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7912                   aopPut (result, "a", offset);
7913                 }
7914               else
7915                 {
7916                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7917                   if (IS_AOP_PREG (left))
7918                     {
7919                       emitcode ("orl", "a,%s",
7920                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7921                       aopPut (result, "a", offset);
7922                     }
7923                   else
7924                     {
7925                       emitcode ("orl", "%s,a",
7926                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7927                     }
7928                 }
7929             }
7930         }
7931     }
7932   else
7933     {
7934       // left & result in different registers
7935       if (AOP_TYPE (result) == AOP_CRY)
7936         {
7937           // result = bit
7938           // if(size), result in bit
7939           // if(!size && ifx), conditional oper: if(left | right)
7940           symbol *tlbl = newiTempLabel (NULL);
7941           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7942           if (size)
7943             emitcode ("setb", "c");
7944           while (sizer--)
7945             {
7946               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7947                   && AOP_TYPE(left)==AOP_ACC)
7948                 {
7949                   if (offset)
7950                     emitcode("mov", "a,b");
7951                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7952                 }
7953               else if (AOP_TYPE(left)==AOP_ACC)
7954                 {
7955                   if (!offset)
7956                     {
7957                       bool pushedB = pushB ();
7958                       emitcode("mov", "b,a");
7959                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7960                       emitcode("orl", "a,b");
7961                       popB (pushedB);
7962                     }
7963                   else
7964                     {
7965                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7966                       emitcode("orl", "a,b");
7967                     }
7968                 }
7969               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7970                 {
7971                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7972                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7973                   emitcode ("orl", "a,b");
7974                 }
7975               else if (aopGetUsesAcc (left, offset))
7976                 {
7977                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7978                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7979                 }
7980               else
7981                 {
7982                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7983                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7984               }
7985
7986               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7987               offset++;
7988             }
7989           if (size)
7990             {
7991               CLRC;
7992               emitLabel (tlbl);
7993               outBitC (result);
7994             }
7995           else if (ifx)
7996             jmpTrueOrFalse (ifx, tlbl);
7997           else
7998             emitLabel (tlbl);
7999         }
8000       else
8001         {
8002             _startLazyDPSEvaluation();
8003           for (; (size--); offset++)
8004             {
8005               // normal case
8006               // result = left | right
8007               if (AOP_TYPE (right) == AOP_LIT)
8008                 {
8009                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8010                   if (bytelit == 0)
8011                     {
8012                       aopPut (result,
8013                               aopGet (left, offset, FALSE, FALSE, NULL),
8014                               offset);
8015                       continue;
8016                     }
8017                   else if (bytelit == 0x0FF)
8018                     {
8019                       /* dummy read of volatile operand */
8020                       if (isOperandVolatile (left, FALSE))
8021                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8022                       aopPut (result, "#0xFF", offset);
8023                       continue;
8024                     }
8025                 }
8026               // faster than result <- left, orl result,right
8027               // and better if result is SFR
8028               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8029                   && AOP_TYPE(left)==AOP_ACC)
8030                 {
8031                   if (offset)
8032                     emitcode("mov", "a,b");
8033                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8034                 }
8035               else if (AOP_TYPE(left)==AOP_ACC)
8036                 {
8037                   if (!offset)
8038                     {
8039                       bool pushedB = pushB ();
8040                       emitcode("mov", "b,a");
8041                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8042                       emitcode("orl", "a,b");
8043                       popB (pushedB);
8044                     }
8045                   else
8046                     {
8047                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8048                       emitcode("orl", "a,b");
8049                     }
8050                 }
8051               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8052                 {
8053                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8054                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8055                   emitcode ("orl", "a,b");
8056                 }
8057               else if (aopGetUsesAcc (left, offset))
8058                 {
8059                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8060                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8061                 }
8062               else
8063                 {
8064                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8065                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
8066                 }
8067               aopPut (result, "a", offset);
8068             }
8069             _endLazyDPSEvaluation();
8070         }
8071     }
8072
8073 release:
8074   freeAsmop (result, NULL, ic, TRUE);
8075   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8076   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8077 }
8078
8079 /*-----------------------------------------------------------------*/
8080 /* genXor - code for xclusive or                                   */
8081 /*-----------------------------------------------------------------*/
8082 static void
8083 genXor (iCode * ic, iCode * ifx)
8084 {
8085   operand *left, *right, *result;
8086   int size, offset = 0;
8087   unsigned long lit = 0L;
8088   int bytelit = 0;
8089   bool pushResult;
8090
8091   D (emitcode (";", "genXor"));
8092
8093   AOP_OP_3_NOFATAL (ic, pushResult);
8094   AOP_SET_LOCALS (ic);
8095
8096   if (pushResult)
8097   {
8098       genFarFarLogicOp(ic, "xrl");
8099       return;
8100   }
8101
8102 #ifdef DEBUG_TYPE
8103   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
8104             AOP_TYPE (result),
8105             AOP_TYPE (left), AOP_TYPE (right));
8106   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
8107             AOP_SIZE (result),
8108             AOP_SIZE (left), AOP_SIZE (right));
8109 #endif
8110
8111   /* if left is a literal & right is not ||
8112      if left needs acc & right does not */
8113   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
8114 #ifdef LOGIC_OPS_BROKEN
8115       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
8116 #endif
8117      )
8118     {
8119       operand *tmp = right;
8120       right = left;
8121       left = tmp;
8122     }
8123
8124   /* if result = right then exchange them */
8125   if (sameRegs (AOP (result), AOP (right)))
8126     {
8127       operand *tmp = right;
8128       right = left;
8129       left = tmp;
8130     }
8131
8132   /* if right is bit then exchange them */
8133   if (AOP_TYPE (right) == AOP_CRY &&
8134       AOP_TYPE (left) != AOP_CRY)
8135     {
8136       operand *tmp = right;
8137       right = left;
8138       left = tmp;
8139     }
8140
8141   if (AOP_TYPE (right) == AOP_LIT)
8142     lit = ulFromVal (AOP (right)->aopu.aop_lit);
8143
8144   size = AOP_SIZE (result);
8145
8146   // if(bit ^ yy)
8147   // xx = bit ^ yy;
8148   if (AOP_TYPE (left) == AOP_CRY)
8149     {
8150       if (AOP_TYPE (right) == AOP_LIT)
8151         {
8152           // c = bit & literal;
8153           if (lit >> 1)
8154             {
8155               // lit>>1  != 0 => result = 1
8156               if (AOP_TYPE (result) == AOP_CRY)
8157                 {
8158                   if (size)
8159                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8160                   else if (ifx)
8161                     continueIfTrue (ifx);
8162                   goto release;
8163                 }
8164               emitcode ("setb", "c");
8165             }
8166           else
8167             {
8168               // lit == (0 or 1)
8169               if (lit == 0)
8170                 {
8171                   // lit == 0, result = left
8172                   if (size && sameRegs (AOP (result), AOP (left)))
8173                     goto release;
8174                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8175                 }
8176               else
8177                 {
8178                   // lit == 1, result = not(left)
8179                   if (size && sameRegs (AOP (result), AOP (left)))
8180                     {
8181                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8182                       goto release;
8183                     }
8184                   else
8185                     {
8186                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8187                       emitcode ("cpl", "c");
8188                     }
8189                 }
8190             }
8191         }
8192       else
8193         {
8194           // right != literal
8195           symbol *tlbl = newiTempLabel (NULL);
8196           if (AOP_TYPE (right) == AOP_CRY)
8197             {
8198               // c = bit ^ bit;
8199               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8200             }
8201           else
8202             {
8203               int sizer = AOP_SIZE (right);
8204               // c = bit ^ val
8205               // if val>>1 != 0, result = 1
8206               emitcode ("setb", "c");
8207               while (sizer)
8208                 {
8209                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8210                   if (sizer == 1)
8211                     // test the msb of the lsb
8212                     emitcode ("anl", "a,#!constbyte",0xfe);
8213                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8214                   sizer--;
8215                 }
8216               // val = (0,1)
8217               emitcode ("rrc", "a");
8218             }
8219           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8220           emitcode ("cpl", "c");
8221           emitLabel (tlbl);
8222         }
8223       // bit = c
8224       // val = c
8225       if (size)
8226         outBitC (result);
8227       // if(bit ^ ...)
8228       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8229         genIfxJump (ifx, "c", ic->next);
8230       goto release;
8231     }
8232
8233   /* if left is same as result */
8234   if (sameRegs (AOP (result), AOP (left)))
8235     {
8236       for (; size--; offset++)
8237         {
8238           if (AOP_TYPE (right) == AOP_LIT)
8239             {
8240               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8241               if (bytelit == 0)
8242                 {
8243                   /* dummy read of volatile operand */
8244                   if (isOperandVolatile (left, FALSE))
8245                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8246                   else
8247                     continue;
8248                 }
8249               else if (IS_AOP_PREG (left))
8250                 {
8251                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8252                   emitcode ("xrl", "a,%s",
8253                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8254                   aopPut (result, "a", offset);
8255                 }
8256               else
8257                 {
8258                   emitcode ("xrl", "%s,%s",
8259                             aopGet (left, offset, FALSE, TRUE, NULL),
8260                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8261                 }
8262             }
8263           else
8264             {
8265               if (AOP_TYPE (left) == AOP_ACC)
8266                 {
8267                   if (offset)
8268                     emitcode("mov", "a,b");
8269                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8270                 }
8271               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8272                 {
8273                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8274                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8275                   emitcode ("xrl", "a,b");
8276                   aopPut (result, "a", offset);
8277                 }
8278               else if (aopGetUsesAcc (left, offset))
8279                 {
8280                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8281                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8282                   aopPut (result, "a", offset);
8283                 }
8284               else
8285                 {
8286                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8287                   if (IS_AOP_PREG (left))
8288                     {
8289                       emitcode ("xrl", "a,%s",
8290                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8291                       aopPut (result, "a", offset);
8292                     }
8293                   else
8294                     emitcode ("xrl", "%s,a",
8295                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8296                 }
8297             }
8298         }
8299     }
8300   else
8301     {
8302       // left & result in different registers
8303       if (AOP_TYPE (result) == AOP_CRY)
8304         {
8305           // result = bit
8306           // if(size), result in bit
8307           // if(!size && ifx), conditional oper: if(left ^ right)
8308           symbol *tlbl = newiTempLabel (NULL);
8309           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8310
8311           if (size)
8312             emitcode ("setb", "c");
8313           while (sizer--)
8314             {
8315               if ((AOP_TYPE (right) == AOP_LIT) &&
8316                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8317                 {
8318                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8319                 }
8320               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8321                   && AOP_TYPE(left)==AOP_ACC)
8322                 {
8323                   if (offset)
8324                     emitcode("mov", "a,b");
8325                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8326                 }
8327               else if (AOP_TYPE(left)==AOP_ACC)
8328                 {
8329                   if (!offset)
8330                     {
8331                       bool pushedB = pushB ();
8332                       emitcode("mov", "b,a");
8333                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8334                       emitcode("xrl", "a,b");
8335                       popB (pushedB);
8336                     }
8337                   else
8338                     {
8339                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8340                       emitcode("xrl", "a,b");
8341                     }
8342                 }
8343               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8344                 {
8345                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8346                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8347                   emitcode ("xrl", "a,b");
8348                 }
8349               else if (aopGetUsesAcc (left, offset))
8350                 {
8351                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8352                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8353                 }
8354               else
8355                 {
8356                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8357                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8358                 }
8359
8360               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8361               offset++;
8362             }
8363           if (size)
8364             {
8365               CLRC;
8366               emitLabel (tlbl);
8367               outBitC (result);
8368             }
8369           else if (ifx)
8370             jmpTrueOrFalse (ifx, tlbl);
8371         }
8372       else
8373         {
8374           for (; (size--); offset++)
8375             {
8376               // normal case
8377               // result = left ^ right
8378               if (AOP_TYPE (right) == AOP_LIT)
8379                 {
8380                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8381                   if (bytelit == 0)
8382                     {
8383                       aopPut (result,
8384                               aopGet (left, offset, FALSE, FALSE, NULL),
8385                               offset);
8386                       continue;
8387                     }
8388                   D (emitcode (";", "better literal XOR."));
8389                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8390                   emitcode ("xrl", "a, %s",
8391                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8392                 }
8393               else
8394                 {
8395                   // faster than result <- left, anl result,right
8396                   // and better if result is SFR
8397                   if (AOP_TYPE (left) == AOP_ACC)
8398                     {
8399                       emitcode ("xrl", "a,%s",
8400                                 aopGet (right, offset,
8401                                         FALSE, FALSE, DP2_RESULT_REG));
8402                     }
8403                   else
8404                     {
8405                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8406                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8407                         {
8408                           emitcode("mov", "b,a");
8409                           rOp = "b";
8410                         }
8411
8412                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8413                       emitcode ("xrl", "a,%s", rOp);
8414                     }
8415                 }
8416               aopPut (result, "a", offset);
8417             }
8418         }
8419     }
8420
8421 release:
8422   freeAsmop (result, NULL, ic, TRUE);
8423   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8424   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8425 }
8426
8427 /*-----------------------------------------------------------------*/
8428 /* genInline - write the inline code out                           */
8429 /*-----------------------------------------------------------------*/
8430 static void
8431 genInline (iCode * ic)
8432 {
8433   char *buffer, *bp, *bp1;
8434   bool inComment = FALSE;
8435
8436   D (emitcode (";", "genInline"));
8437
8438   _G.inLine += (!options.asmpeep);
8439
8440   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
8441
8442   /* emit each line as a code */
8443   while (*bp)
8444     {
8445       switch (*bp)
8446         {
8447         case ';':
8448           inComment = TRUE;
8449           ++bp;
8450           break;
8451
8452         case '\n':
8453           inComment = FALSE;
8454           *bp++ = '\0';
8455           emitcode (bp1, "");
8456           bp1 = bp;
8457           break;
8458
8459         default:
8460           /* Add \n for labels, not dirs such as c:\mydir */
8461           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8462             {
8463               ++bp;
8464               *bp = '\0';
8465               ++bp;
8466               emitcode (bp1, "");
8467               bp1 = bp;
8468             }
8469           else
8470             ++bp;
8471           break;
8472         }
8473     }
8474   if (bp1 != bp)
8475     emitcode (bp1, "");
8476
8477   Safe_free (buffer);
8478
8479   _G.inLine -= (!options.asmpeep);
8480 }
8481
8482 /*-----------------------------------------------------------------*/
8483 /* genRRC - rotate right with carry                                */
8484 /*-----------------------------------------------------------------*/
8485 static void
8486 genRRC (iCode * ic)
8487 {
8488   operand *left, *result;
8489   int     size, offset;
8490   char    *l;
8491
8492   D (emitcode (";", "genRRC"));
8493
8494   /* rotate right with carry */
8495   left = IC_LEFT (ic);
8496   result = IC_RESULT (ic);
8497   aopOp (left, ic, FALSE, FALSE);
8498   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8499
8500   /* move it to the result */
8501   size = AOP_SIZE (result);
8502   offset = size - 1;
8503   CLRC;
8504
8505   _startLazyDPSEvaluation ();
8506   while (size--)
8507     {
8508       l = aopGet (left, offset, FALSE, FALSE, NULL);
8509       MOVA (l);
8510       emitcode ("rrc", "a");
8511       if (AOP_SIZE (result) > 1)
8512         aopPut (result, "a", offset--);
8513     }
8514   _endLazyDPSEvaluation ();
8515
8516   /* now we need to put the carry into the
8517      highest order byte of the result */
8518   if (AOP_SIZE (result) > 1)
8519     {
8520       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8521       MOVA (l);
8522     }
8523   emitcode ("mov", "acc.7,c");
8524   aopPut (result, "a", AOP_SIZE (result) - 1);
8525   freeAsmop (result, NULL, ic, TRUE);
8526   freeAsmop (left, NULL, ic, TRUE);
8527 }
8528
8529 /*-----------------------------------------------------------------*/
8530 /* genRLC - generate code for rotate left with carry               */
8531 /*-----------------------------------------------------------------*/
8532 static void
8533 genRLC (iCode * ic)
8534 {
8535   operand *left, *result;
8536   int size, offset;
8537   char *l;
8538
8539   D (emitcode (";", "genRLC"));
8540
8541   /* rotate right with carry */
8542   left = IC_LEFT (ic);
8543   result = IC_RESULT (ic);
8544   aopOp (left, ic, FALSE, FALSE);
8545   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8546
8547   /* move it to the result */
8548   size = AOP_SIZE (result);
8549   offset = 0;
8550   if (size--)
8551     {
8552       l = aopGet (left, offset, FALSE, FALSE, NULL);
8553       MOVA (l);
8554       emitcode ("add", "a,acc");
8555       if (AOP_SIZE (result) > 1)
8556         {
8557           aopPut (result, "a", offset++);
8558         }
8559
8560       _startLazyDPSEvaluation ();
8561       while (size--)
8562         {
8563           l = aopGet (left, offset, FALSE, FALSE, NULL);
8564           MOVA (l);
8565           emitcode ("rlc", "a");
8566           if (AOP_SIZE (result) > 1)
8567             aopPut (result, "a", offset++);
8568         }
8569       _endLazyDPSEvaluation ();
8570     }
8571   /* now we need to put the carry into the
8572      highest order byte of the result */
8573   if (AOP_SIZE (result) > 1)
8574     {
8575       l = aopGet (result, 0, FALSE, FALSE, NULL);
8576       MOVA (l);
8577     }
8578   emitcode ("mov", "acc.0,c");
8579   aopPut (result, "a", 0);
8580   freeAsmop (result, NULL, ic, TRUE);
8581   freeAsmop (left, NULL, ic, TRUE);
8582 }
8583
8584 /*-----------------------------------------------------------------*/
8585 /* genGetHbit - generates code get highest order bit               */
8586 /*-----------------------------------------------------------------*/
8587 static void
8588 genGetHbit (iCode * ic)
8589 {
8590   operand *left, *result;
8591
8592   D (emitcode (";", "genGetHbit"));
8593
8594   left = IC_LEFT (ic);
8595   result = IC_RESULT (ic);
8596   aopOp (left, ic, FALSE, FALSE);
8597   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8598
8599   /* get the highest order byte into a */
8600   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8601   if (AOP_TYPE (result) == AOP_CRY)
8602     {
8603       emitcode ("rlc", "a");
8604       outBitC (result);
8605     }
8606   else
8607     {
8608       emitcode ("rl", "a");
8609       emitcode ("anl", "a,#0x01");
8610       outAcc (result);
8611     }
8612
8613
8614   freeAsmop (result, NULL, ic, TRUE);
8615   freeAsmop (left, NULL, ic, TRUE);
8616 }
8617
8618 /*-----------------------------------------------------------------*/
8619 /* genSwap - generates code to swap nibbles or bytes               */
8620 /*-----------------------------------------------------------------*/
8621 static void
8622 genSwap (iCode * ic)
8623 {
8624   operand *left, *result;
8625
8626   D(emitcode (";", "genSwap"));
8627
8628   left = IC_LEFT (ic);
8629   result = IC_RESULT (ic);
8630   aopOp (left, ic, FALSE, FALSE);
8631   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8632
8633   _startLazyDPSEvaluation ();
8634   switch (AOP_SIZE (left))
8635     {
8636     case 1: /* swap nibbles in byte */
8637       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8638       emitcode ("swap", "a");
8639       aopPut (result, "a", 0);
8640       break;
8641     case 2: /* swap bytes in word */
8642       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8643         {
8644           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8645           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8646           aopPut (result, "a", 1);
8647         }
8648       else if (operandsEqu (left, result))
8649         {
8650           char * reg = "a";
8651           bool pushedB = FALSE, leftInB = FALSE;
8652
8653           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8654           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8655             {
8656               pushedB = pushB ();
8657               emitcode ("mov", "b,a");
8658               reg = "b";
8659               leftInB = TRUE;
8660             }
8661           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8662           aopPut (result, reg, 1);
8663
8664           if (leftInB)
8665             popB (pushedB);
8666         }
8667       else
8668         {
8669           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8670           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8671         }
8672       break;
8673     default:
8674       wassertl(FALSE, "unsupported SWAP operand size");
8675     }
8676   _endLazyDPSEvaluation ();
8677
8678   freeAsmop (result, NULL, ic, TRUE);
8679   freeAsmop (left, NULL, ic, TRUE);
8680 }
8681
8682 /*-----------------------------------------------------------------*/
8683 /* AccRol - rotate left accumulator by known count                 */
8684 /*-----------------------------------------------------------------*/
8685 static void
8686 AccRol (int shCount)
8687 {
8688   shCount &= 0x0007;            // shCount : 0..7
8689
8690   switch (shCount)
8691     {
8692     case 0:
8693       break;
8694     case 1:
8695       emitcode ("rl", "a");
8696       break;
8697     case 2:
8698       emitcode ("rl", "a");
8699       emitcode ("rl", "a");
8700       break;
8701     case 3:
8702       emitcode ("swap", "a");
8703       emitcode ("rr", "a");
8704       break;
8705     case 4:
8706       emitcode ("swap", "a");
8707       break;
8708     case 5:
8709       emitcode ("swap", "a");
8710       emitcode ("rl", "a");
8711       break;
8712     case 6:
8713       emitcode ("rr", "a");
8714       emitcode ("rr", "a");
8715       break;
8716     case 7:
8717       emitcode ("rr", "a");
8718       break;
8719     }
8720 }
8721
8722 /*-----------------------------------------------------------------*/
8723 /* AccLsh - left shift accumulator by known count                  */
8724 /*-----------------------------------------------------------------*/
8725 static void
8726 AccLsh (int shCount)
8727 {
8728   if (shCount != 0)
8729     {
8730       if (shCount == 1)
8731         emitcode ("add", "a,acc");
8732       else if (shCount == 2)
8733         {
8734           emitcode ("add", "a,acc");
8735           emitcode ("add", "a,acc");
8736         }
8737       else
8738         {
8739           /* rotate left accumulator */
8740           AccRol (shCount);
8741           /* and kill the lower order bits */
8742           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8743         }
8744     }
8745 }
8746
8747 /*-----------------------------------------------------------------*/
8748 /* AccRsh - right shift accumulator by known count                 */
8749 /*-----------------------------------------------------------------*/
8750 static void
8751 AccRsh (int shCount)
8752 {
8753   if (shCount != 0)
8754     {
8755       if (shCount == 1)
8756         {
8757           CLRC;
8758           emitcode ("rrc", "a");
8759         }
8760       else
8761         {
8762           /* rotate right accumulator */
8763           AccRol (8 - shCount);
8764           /* and kill the higher order bits */
8765           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8766         }
8767     }
8768 }
8769
8770 #ifdef BETTER_LITERAL_SHIFT
8771 /*-----------------------------------------------------------------*/
8772 /* AccSRsh - signed right shift accumulator by known count                 */
8773 /*-----------------------------------------------------------------*/
8774 static void
8775 AccSRsh (int shCount)
8776 {
8777   symbol *tlbl;
8778   if (shCount != 0)
8779     {
8780       if (shCount == 1)
8781         {
8782           emitcode ("mov", "c,acc.7");
8783           emitcode ("rrc", "a");
8784         }
8785       else if (shCount == 2)
8786         {
8787           emitcode ("mov", "c,acc.7");
8788           emitcode ("rrc", "a");
8789           emitcode ("mov", "c,acc.7");
8790           emitcode ("rrc", "a");
8791         }
8792       else
8793         {
8794           tlbl = newiTempLabel (NULL);
8795           /* rotate right accumulator */
8796           AccRol (8 - shCount);
8797           /* and kill the higher order bits */
8798           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8799           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8800           emitcode ("orl", "a,#!constbyte",
8801                     (unsigned char) ~SRMask[shCount]);
8802           emitLabel (tlbl);
8803         }
8804     }
8805 }
8806 #endif
8807
8808 #ifdef BETTER_LITERAL_SHIFT
8809 /*-----------------------------------------------------------------*/
8810 /* shiftR1Left2Result - shift right one byte from left to result   */
8811 /*-----------------------------------------------------------------*/
8812 static void
8813 shiftR1Left2Result (operand * left, int offl,
8814                     operand * result, int offr,
8815                     int shCount, int sign)
8816 {
8817   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8818   /* shift right accumulator */
8819   if (sign)
8820     AccSRsh (shCount);
8821   else
8822     AccRsh (shCount);
8823   aopPut (result, "a", offr);
8824 }
8825 #endif
8826
8827 #ifdef BETTER_LITERAL_SHIFT
8828 /*-----------------------------------------------------------------*/
8829 /* shiftL1Left2Result - shift left one byte from left to result    */
8830 /*-----------------------------------------------------------------*/
8831 static void
8832 shiftL1Left2Result (operand * left, int offl,
8833                     operand * result, int offr, int shCount)
8834 {
8835   char *l;
8836   l = aopGet (left, offl, FALSE, FALSE, NULL);
8837   MOVA (l);
8838   /* shift left accumulator */
8839   AccLsh (shCount);
8840   aopPut (result, "a", offr);
8841 }
8842 #endif
8843
8844 #ifdef BETTER_LITERAL_SHIFT
8845 /*-----------------------------------------------------------------*/
8846 /* movLeft2Result - move byte from left to result                  */
8847 /*-----------------------------------------------------------------*/
8848 static void
8849 movLeft2Result (operand * left, int offl,
8850                 operand * result, int offr, int sign)
8851 {
8852   char *l;
8853   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8854   {
8855       l = aopGet (left, offl, FALSE, FALSE, NULL);
8856
8857       if (*l == '@' && (IS_AOP_PREG (result)))
8858         {
8859           emitcode ("mov", "a,%s", l);
8860           aopPut (result, "a", offr);
8861         }
8862       else
8863         {
8864           if (!sign)
8865             {
8866               aopPut (result, l, offr);
8867             }
8868           else
8869             {
8870               /* MSB sign in acc.7 ! */
8871               if (getDataSize (left) == offl + 1)
8872                 {
8873                   MOVA (l);
8874                   aopPut (result, "a", offr);
8875                 }
8876             }
8877         }
8878     }
8879 }
8880 #endif
8881
8882 #ifdef BETTER_LITERAL_SHIFT
8883 /*-----------------------------------------------------------------*/
8884 /* AccAXRrl1 - right rotate a:x by 1                               */
8885 /*-----------------------------------------------------------------*/
8886 static void
8887 AccAXRrl1 (char *x)
8888 {
8889   emitcode ("mov", "c,acc.0");
8890   emitcode ("xch", "a,%s", x);
8891   emitcode ("rrc", "a");
8892   emitcode ("xch", "a,%s", x);
8893   emitcode ("rrc", "a");
8894 }
8895 #endif
8896
8897 #ifdef BETTER_LITERAL_SHIFT
8898 //REMOVE ME!!!
8899 /*-----------------------------------------------------------------*/
8900 /* AccAXLrl1 - left rotate a:x by 1                                */
8901 /*-----------------------------------------------------------------*/
8902 static void
8903 AccAXLrl1 (char *x)
8904 {
8905   emitcode ("mov", "c,acc.7");
8906   emitcode ("xch", "a,%s", x);
8907   emitcode ("rlc", "a");
8908   emitcode ("xch", "a,%s", x);
8909   emitcode ("rlc", "a");
8910 }
8911 #endif
8912
8913 #ifdef BETTER_LITERAL_SHIFT
8914 /*-----------------------------------------------------------------*/
8915 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8916 /*-----------------------------------------------------------------*/
8917 static void
8918 AccAXRsh1 (char *x)
8919 {
8920   emitcode ("rrc", "a");
8921   emitcode ("xch", "a,%s", x);
8922   emitcode ("rrc", "a");
8923   emitcode ("xch", "a,%s", x);
8924 }
8925 #endif
8926
8927 #ifdef BETTER_LITERAL_SHIFT
8928 /*-----------------------------------------------------------------*/
8929 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8930 /*-----------------------------------------------------------------*/
8931 static void
8932 AccAXLsh1 (char *x)
8933 {
8934   emitcode ("xch", "a,%s", x);
8935   emitcode ("add", "a,acc");
8936   emitcode ("xch", "a,%s", x);
8937   emitcode ("rlc", "a");
8938 }
8939 #endif
8940
8941 #ifdef BETTER_LITERAL_SHIFT
8942 /*-----------------------------------------------------------------*/
8943 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8944 /*-----------------------------------------------------------------*/
8945 static void
8946 AccAXLsh (char *x, int shCount)
8947 {
8948   switch (shCount)
8949     {
8950     case 0:
8951       break;
8952     case 1:
8953       AccAXLsh1 (x);
8954       break;
8955     case 2:
8956       AccAXLsh1 (x);
8957       AccAXLsh1 (x);
8958       break;
8959     case 3:
8960     case 4:
8961     case 5:                             // AAAAABBB:CCCCCDDD
8962
8963       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8964
8965       emitcode ("anl", "a,#!constbyte",
8966                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8967
8968       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8969
8970       AccRol (shCount);                 // DDDCCCCC:BBB00000
8971
8972       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8973
8974       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8975
8976       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8977
8978       emitcode ("anl", "a,#!constbyte",
8979                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8980
8981       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8982
8983       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8984
8985       break;
8986     case 6:                             // AAAAAABB:CCCCCCDD
8987       emitcode ("anl", "a,#!constbyte",
8988                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8989 #if 1
8990       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8991       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8992       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8993 #else
8994       emitcode ("mov", "c,acc.0");      // c = B
8995       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8996       emitcode("rrc","a");
8997       emitcode("xch","a,%s", x);
8998       emitcode("rrc","a");
8999       emitcode("mov","c,acc.0"); //<< get correct bit
9000       emitcode("xch","a,%s", x);
9001
9002       emitcode("rrc","a");
9003       emitcode("xch","a,%s", x);
9004       emitcode("rrc","a");
9005       emitcode("xch","a,%s", x);
9006 #endif
9007       break;
9008     case 7:                             // a:x <<= 7
9009
9010       emitcode ("anl", "a,#!constbyte",
9011                 SRMask[shCount]);       // 0000000B:CCCCCCCD
9012
9013       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
9014
9015       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
9016
9017       break;
9018     default:
9019       break;
9020     }
9021 }
9022 #endif
9023
9024 #ifdef BETTER_LITERAL_SHIFT
9025 //REMOVE ME!!!
9026 /*-----------------------------------------------------------------*/
9027 /* AccAXRsh - right shift a:x known count (0..7)                   */
9028 /*-----------------------------------------------------------------*/
9029 static void
9030 AccAXRsh (char *x, int shCount)
9031 {
9032   switch (shCount)
9033     {
9034     case 0:
9035       break;
9036     case 1:
9037       CLRC;
9038       AccAXRsh1 (x);                    // 0->a:x
9039
9040       break;
9041     case 2:
9042       CLRC;
9043       AccAXRsh1 (x);                    // 0->a:x
9044
9045       CLRC;
9046       AccAXRsh1 (x);                    // 0->a:x
9047
9048       break;
9049     case 3:
9050     case 4:
9051     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9052
9053       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
9054
9055       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9056
9057       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9058
9059       emitcode ("anl", "a,#!constbyte",
9060                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9061
9062       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9063
9064       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9065
9066       emitcode ("anl", "a,#!constbyte",
9067                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9068
9069       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9070
9071       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9072
9073       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
9074
9075       break;
9076     case 6:                             // AABBBBBB:CCDDDDDD
9077
9078       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
9079       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9080
9081       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9082
9083       emitcode ("anl", "a,#!constbyte",
9084                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9085
9086       break;
9087     case 7:                             // ABBBBBBB:CDDDDDDD
9088
9089       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9090
9091       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9092
9093       emitcode ("anl", "a,#!constbyte",
9094                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9095
9096       break;
9097     default:
9098       break;
9099     }
9100 }
9101 #endif
9102
9103 #ifdef BETTER_LITERAL_SHIFT
9104 /*-----------------------------------------------------------------*/
9105 /* AccAXRshS - right shift signed a:x known count (0..7)           */
9106 /*-----------------------------------------------------------------*/
9107 static void
9108 AccAXRshS (char *x, int shCount)
9109 {
9110   symbol *tlbl;
9111   switch (shCount)
9112     {
9113     case 0:
9114       break;
9115     case 1:
9116       emitcode ("mov", "c,acc.7");
9117       AccAXRsh1 (x);                    // s->a:x
9118
9119       break;
9120     case 2:
9121       emitcode ("mov", "c,acc.7");
9122       AccAXRsh1 (x);                    // s->a:x
9123
9124       emitcode ("mov", "c,acc.7");
9125       AccAXRsh1 (x);                    // s->a:x
9126
9127       break;
9128     case 3:
9129     case 4:
9130     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9131
9132       tlbl = newiTempLabel (NULL);
9133       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9134
9135       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9136
9137       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9138
9139       emitcode ("anl", "a,#!constbyte",
9140                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9141
9142       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9143
9144       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9145
9146       emitcode ("anl", "a,#!constbyte",
9147                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9148
9149       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9150
9151       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9152
9153       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9154
9155       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9156       emitcode ("orl", "a,#!constbyte",
9157                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9158
9159       emitLabel (tlbl);
9160       break;                            // SSSSAAAA:BBBCCCCC
9161
9162     case 6:                             // AABBBBBB:CCDDDDDD
9163
9164       tlbl = newiTempLabel (NULL);
9165
9166       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9167       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9168
9169       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9170
9171       emitcode ("anl", "a,#!constbyte",
9172                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9173
9174       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9175       emitcode ("orl", "a,#!constbyte",
9176                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9177
9178       emitLabel (tlbl);
9179       break;
9180     case 7:                             // ABBBBBBB:CDDDDDDD
9181
9182       tlbl = newiTempLabel (NULL);
9183
9184       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9185
9186       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9187
9188       emitcode ("anl", "a,#!constbyte",
9189                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9190
9191       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9192       emitcode ("orl", "a,#!constbyte",
9193                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9194
9195       emitLabel (tlbl);
9196       break;
9197     default:
9198       break;
9199     }
9200 }
9201 #endif
9202
9203 #ifdef BETTER_LITERAL_SHIFT
9204 static void
9205 _loadLeftIntoAx(char    **lsb,
9206                 operand *left,
9207                 operand *result,
9208                 int     offl,
9209                 int     offr)
9210 {
9211   // Get the initial value from left into a pair of registers.
9212   // MSB must be in A, LSB can be any register.
9213   //
9214   // If the result is held in registers, it is an optimization
9215   // if the LSB can be held in the register which will hold the,
9216   // result LSB since this saves us from having to copy it into
9217   // the result following AccAXLsh.
9218   //
9219   // If the result is addressed indirectly, this is not a gain.
9220   if (AOP_NEEDSACC(result))
9221   {
9222        char *leftByte;
9223
9224        _startLazyDPSEvaluation();
9225       if (AOP_TYPE(left) == AOP_DPTR2)
9226        {
9227            // Get MSB in A.
9228            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9229            // get LSB in DP2_RESULT_REG.
9230            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9231            assert(!strcmp(leftByte, DP2_RESULT_REG));
9232        }
9233        else
9234        {
9235            // get LSB into DP2_RESULT_REG
9236            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9237            if (strcmp(leftByte, DP2_RESULT_REG))
9238            {
9239                TR_AP("#7");
9240                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9241            }
9242            // And MSB in A.
9243            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9244            assert(strcmp(leftByte, DP2_RESULT_REG));
9245            MOVA (leftByte);
9246        }
9247        _endLazyDPSEvaluation();
9248        *lsb = DP2_RESULT_REG;
9249   }
9250   else
9251   {
9252       if (sameRegs (AOP (result), AOP (left)) &&
9253         ((offl + MSB16) == offr))
9254       {
9255           /* don't crash result[offr] */
9256           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9257           emitcode ("xch", "a,%s",
9258                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9259       }
9260       else
9261       {
9262           movLeft2Result (left, offl, result, offr, 0);
9263           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9264       }
9265       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9266       assert(strcmp(*lsb,"a"));
9267   }
9268 }
9269
9270 static void
9271 _storeAxResults(char    *lsb,
9272                 operand *result,
9273                 int     offr)
9274 {
9275   _startLazyDPSEvaluation();
9276   if (AOP_NEEDSACC(result))
9277   {
9278       /* We have to explicitly update the result LSB.
9279        */
9280       emitcode ("xch","a,%s", lsb);
9281       aopPut (result, "a", offr);
9282       emitcode ("mov","a,%s", lsb);
9283   }
9284   if (getDataSize (result) > 1)
9285   {
9286       aopPut (result, "a", offr + MSB16);
9287   }
9288   _endLazyDPSEvaluation();
9289 }
9290
9291 /*-----------------------------------------------------------------*/
9292 /* shiftL2Left2Result - shift left two bytes from left to result   */
9293 /*-----------------------------------------------------------------*/
9294 static void
9295 shiftL2Left2Result (operand * left, int offl,
9296                     operand * result, int offr, int shCount)
9297 {
9298   char *lsb;
9299
9300   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9301
9302   AccAXLsh (lsb, shCount);
9303
9304   _storeAxResults(lsb, result, offr);
9305 }
9306 #endif
9307
9308 #ifdef BETTER_LITERAL_SHIFT
9309 /*-----------------------------------------------------------------*/
9310 /* shiftR2Left2Result - shift right two bytes from left to result  */
9311 /*-----------------------------------------------------------------*/
9312 static void
9313 shiftR2Left2Result (operand * left, int offl,
9314                     operand * result, int offr,
9315                     int shCount, int sign)
9316 {
9317   char *lsb;
9318
9319   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9320
9321   /* a:x >> shCount (x = lsb(result)) */
9322   if (sign)
9323   {
9324      AccAXRshS(lsb, shCount);
9325   }
9326   else
9327   {
9328     AccAXRsh(lsb, shCount);
9329   }
9330
9331   _storeAxResults(lsb, result, offr);
9332 }
9333 #endif
9334
9335 /*-----------------------------------------------------------------*/
9336 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9337 /*-----------------------------------------------------------------*/
9338 static void
9339 shiftLLeftOrResult (operand * left, int offl,
9340                     operand * result, int offr, int shCount)
9341 {
9342   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9343   /* shift left accumulator */
9344   AccLsh (shCount);
9345   /* or with result */
9346   emitcode ("orl", "a,%s",
9347             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9348   /* back to result */
9349   aopPut (result, "a", offr);
9350 }
9351
9352 #if 0
9353 //REMOVE ME!!!
9354 /*-----------------------------------------------------------------*/
9355 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9356 /*-----------------------------------------------------------------*/
9357 static void
9358 shiftRLeftOrResult (operand * left, int offl,
9359                     operand * result, int offr, int shCount)
9360 {
9361   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9362   /* shift right accumulator */
9363   AccRsh (shCount);
9364   /* or with result */
9365   emitcode ("orl", "a,%s",
9366             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9367   /* back to result */
9368   aopPut (result, "a", offr);
9369 }
9370 #endif
9371
9372 #ifdef BETTER_LITERAL_SHIFT
9373 /*-----------------------------------------------------------------*/
9374 /* genlshOne - left shift a one byte quantity by known count       */
9375 /*-----------------------------------------------------------------*/
9376 static void
9377 genlshOne (operand * result, operand * left, int shCount)
9378 {
9379   D (emitcode (";", "genlshOne"));
9380
9381   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9382 }
9383 #endif
9384
9385 #ifdef BETTER_LITERAL_SHIFT
9386 /*-----------------------------------------------------------------*/
9387 /* genlshTwo - left shift two bytes by known amount != 0           */
9388 /*-----------------------------------------------------------------*/
9389 static void
9390 genlshTwo (operand * result, operand * left, int shCount)
9391 {
9392   int size;
9393
9394   D (emitcode (";", "genlshTwo"));
9395
9396   size = getDataSize (result);
9397
9398   /* if shCount >= 8 */
9399   if (shCount >= 8)
9400     {
9401       shCount -= 8;
9402
9403       _startLazyDPSEvaluation();
9404
9405       if (size > 1)
9406         {
9407           if (shCount)
9408             {
9409               _endLazyDPSEvaluation();
9410               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9411               aopPut (result, zero, LSB);
9412             }
9413           else
9414             {
9415               movLeft2Result (left, LSB, result, MSB16, 0);
9416               aopPut (result, zero, LSB);
9417               _endLazyDPSEvaluation();
9418             }
9419         }
9420       else
9421         {
9422           aopPut (result, zero, LSB);
9423           _endLazyDPSEvaluation();
9424         }
9425   }
9426
9427   /*  1 <= shCount <= 7 */
9428   else
9429     {
9430       if (size == 1)
9431         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9432       else
9433         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9434     }
9435 }
9436 #endif
9437
9438 #if 0
9439 //REMOVE ME!!!
9440 /*-----------------------------------------------------------------*/
9441 /* shiftLLong - shift left one long from left to result            */
9442 /* offl = LSB or MSB16                                             */
9443 /*-----------------------------------------------------------------*/
9444 static void
9445 shiftLLong (operand * left, operand * result, int offr)
9446 {
9447   char *l;
9448   int size = AOP_SIZE (result);
9449
9450   if (size >= LSB + offr)
9451     {
9452       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9453       MOVA (l);
9454       emitcode ("add", "a,acc");
9455       if (sameRegs (AOP (left), AOP (result)) &&
9456           size >= MSB16 + offr && offr != LSB)
9457         emitcode ("xch", "a,%s",
9458                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9459       else
9460         aopPut (result, "a", LSB + offr);
9461     }
9462
9463   if (size >= MSB16 + offr)
9464     {
9465       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9466         {
9467           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9468           MOVA (l);
9469         }
9470       emitcode ("rlc", "a");
9471       if (sameRegs (AOP (left), AOP (result)) &&
9472           size >= MSB24 + offr && offr != LSB)
9473         emitcode ("xch", "a,%s",
9474                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9475       else
9476         aopPut (result, "a", MSB16 + offr);
9477     }
9478
9479   if (size >= MSB24 + offr)
9480     {
9481       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9482         {
9483           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9484           MOVA (l);
9485         }
9486       emitcode ("rlc", "a");
9487       if (sameRegs (AOP (left), AOP (result)) &&
9488           size >= MSB32 + offr && offr != LSB)
9489         emitcode ("xch", "a,%s",
9490                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9491       else
9492         aopPut (result, "a", MSB24 + offr);
9493     }
9494
9495   if (size > MSB32 + offr)
9496     {
9497       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9498         {
9499           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9500           MOVA (l);
9501         }
9502       emitcode ("rlc", "a");
9503       aopPut (result, "a", MSB32 + offr);
9504     }
9505   if (offr != LSB)
9506     aopPut (result, zero, LSB);
9507 }
9508 #endif
9509
9510 #if 0
9511 //REMOVE ME!!!
9512 /*-----------------------------------------------------------------*/
9513 /* genlshFour - shift four byte by a known amount != 0             */
9514 /*-----------------------------------------------------------------*/
9515 static void
9516 genlshFour (operand * result, operand * left, int shCount)
9517 {
9518   int size;
9519
9520   D (emitcode (";", "genlshFour"));
9521
9522   size = AOP_SIZE (result);
9523
9524   /* if shifting more that 3 bytes */
9525   if (shCount >= 24)
9526     {
9527       shCount -= 24;
9528       if (shCount)
9529         /* lowest order of left goes to the highest
9530            order of the destination */
9531         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9532       else
9533         movLeft2Result (left, LSB, result, MSB32, 0);
9534       aopPut (result, zero, LSB);
9535       aopPut (result, zero, MSB16);
9536       aopPut (result, zero, MSB24);
9537       return;
9538     }
9539
9540   /* more than two bytes */
9541   else if (shCount >= 16)
9542     {
9543       /* lower order two bytes goes to higher order two bytes */
9544       shCount -= 16;
9545       /* if some more remaining */
9546       if (shCount)
9547         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9548       else
9549         {
9550           movLeft2Result (left, MSB16, result, MSB32, 0);
9551           movLeft2Result (left, LSB, result, MSB24, 0);
9552         }
9553       aopPut (result, zero, MSB16);
9554       aopPut (result, zero, LSB);
9555       return;
9556     }
9557
9558   /* if more than 1 byte */
9559   else if (shCount >= 8)
9560     {
9561       /* lower order three bytes goes to higher order  three bytes */
9562       shCount -= 8;
9563       if (size == 2)
9564         {
9565           if (shCount)
9566             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9567           else
9568             movLeft2Result (left, LSB, result, MSB16, 0);
9569         }
9570       else
9571         {                       /* size = 4 */
9572           if (shCount == 0)
9573             {
9574               movLeft2Result (left, MSB24, result, MSB32, 0);
9575               movLeft2Result (left, MSB16, result, MSB24, 0);
9576               movLeft2Result (left, LSB, result, MSB16, 0);
9577               aopPut (result, zero, LSB);
9578             }
9579           else if (shCount == 1)
9580             shiftLLong (left, result, MSB16);
9581           else
9582             {
9583               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9584               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9585               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9586               aopPut (result, zero, LSB);
9587             }
9588         }
9589     }
9590
9591   /* 1 <= shCount <= 7 */
9592   else if (shCount <= 2)
9593     {
9594       shiftLLong (left, result, LSB);
9595       if (shCount == 2)
9596         shiftLLong (result, result, LSB);
9597     }
9598   /* 3 <= shCount <= 7, optimize */
9599   else
9600     {
9601       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9602       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9603       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9604     }
9605 }
9606 #endif
9607
9608 #ifdef BETTER_LITERAL_SHIFT
9609 /*-----------------------------------------------------------------*/
9610 /* genLeftShiftLiteral - left shifting by known count              */
9611 /*-----------------------------------------------------------------*/
9612 static bool
9613 genLeftShiftLiteral (operand * left,
9614                      operand * right,
9615                      operand * result,
9616                      iCode * ic)
9617 {
9618   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9619   int size;
9620
9621   size = getSize (operandType (result));
9622
9623   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9624
9625   /* We only handle certain easy cases so far. */
9626   if ((shCount != 0)
9627    && (shCount < (size * 8))
9628    && (size != 1)
9629    && (size != 2))
9630   {
9631       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9632       return FALSE;
9633   }
9634
9635   freeAsmop (right, NULL, ic, TRUE);
9636
9637   aopOp(left, ic, FALSE, FALSE);
9638   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9639
9640 #if 0 // debug spew
9641   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9642   {
9643         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9644         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9645         {
9646            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9647         }
9648   }
9649   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9650   {
9651         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9652         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9653         {
9654            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9655         }
9656   }
9657 #endif
9658
9659 #if VIEW_SIZE
9660   emitcode ("; shift left ", "result %d, left %d", size,
9661             AOP_SIZE (left));
9662 #endif
9663
9664   /* I suppose that the left size >= result size */
9665   if (shCount == 0)
9666     {
9667       _startLazyDPSEvaluation();
9668       while (size--)
9669         {
9670           movLeft2Result (left, size, result, size, 0);
9671         }
9672       _endLazyDPSEvaluation();
9673     }
9674   else if (shCount >= (size * 8))
9675     {
9676       _startLazyDPSEvaluation();
9677       while (size--)
9678         {
9679           aopPut (result, zero, size);
9680         }
9681       _endLazyDPSEvaluation();
9682     }
9683   else
9684     {
9685       switch (size)
9686         {
9687         case 1:
9688           genlshOne (result, left, shCount);
9689           break;
9690
9691         case 2:
9692           genlshTwo (result, left, shCount);
9693           break;
9694 #if 0
9695         case 4:
9696           genlshFour (result, left, shCount);
9697           break;
9698 #endif
9699         default:
9700           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9701                   "*** ack! mystery literal shift!\n");
9702           break;
9703         }
9704     }
9705   freeAsmop (result, NULL, ic, TRUE);
9706   freeAsmop (left, NULL, ic, TRUE);
9707   return TRUE;
9708 }
9709 #endif
9710
9711 /*-----------------------------------------------------------------*/
9712 /* genLeftShift - generates code for left shifting                 */
9713 /*-----------------------------------------------------------------*/
9714 static void
9715 genLeftShift (iCode * ic)
9716 {
9717   operand *left, *right, *result;
9718   int size, offset;
9719   char *l;
9720   symbol *tlbl, *tlbl1;
9721   bool pushedB;
9722
9723   D (emitcode (";", "genLeftShift"));
9724
9725   right = IC_RIGHT (ic);
9726   left = IC_LEFT (ic);
9727   result = IC_RESULT (ic);
9728
9729   aopOp (right, ic, FALSE, FALSE);
9730
9731
9732 #ifdef BETTER_LITERAL_SHIFT
9733   /* if the shift count is known then do it
9734      as efficiently as possible */
9735   if (AOP_TYPE (right) == AOP_LIT)
9736     {
9737       if (genLeftShiftLiteral (left, right, result, ic))
9738       {
9739         return;
9740       }
9741     }
9742 #endif
9743
9744   /* shift count is unknown then we have to form
9745      a loop get the loop count in B : Note: we take
9746      only the lower order byte since shifting
9747      more that 32 bits make no sense anyway, ( the
9748      largest size of an object can be only 32 bits ) */
9749
9750   pushedB = pushB ();
9751   if (AOP_TYPE (right) == AOP_LIT)
9752   {
9753       /* Really should be handled by genLeftShiftLiteral,
9754        * but since I'm too lazy to fix that today, at least we can make
9755        * some small improvement.
9756        */
9757        emitcode("mov", "b,#!constbyte",
9758                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
9759   }
9760   else
9761   {
9762       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9763       emitcode ("inc", "b");
9764   }
9765   freeAsmop (right, NULL, ic, TRUE);
9766   aopOp (left, ic, FALSE, FALSE);
9767   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9768
9769   /* now move the left to the result if they are not the same */
9770   if (!sameRegs (AOP (left), AOP (result)) &&
9771       AOP_SIZE (result) > 1)
9772     {
9773
9774       size = AOP_SIZE (result);
9775       offset = 0;
9776       _startLazyDPSEvaluation ();
9777       while (size--)
9778         {
9779           l = aopGet (left, offset, FALSE, TRUE, NULL);
9780           if (*l == '@' && (IS_AOP_PREG (result)))
9781             {
9782
9783               emitcode ("mov", "a,%s", l);
9784               aopPut (result, "a", offset);
9785             }
9786           else
9787             aopPut (result, l, offset);
9788           offset++;
9789         }
9790       _endLazyDPSEvaluation ();
9791     }
9792
9793   tlbl = newiTempLabel (NULL);
9794   size = AOP_SIZE (result);
9795   offset = 0;
9796   tlbl1 = newiTempLabel (NULL);
9797
9798   /* if it is only one byte then */
9799   if (size == 1)
9800     {
9801       symbol *tlbl1 = newiTempLabel (NULL);
9802
9803       l = aopGet (left, 0, FALSE, FALSE, NULL);
9804       MOVA (l);
9805       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9806       emitLabel (tlbl);
9807       emitcode ("add", "a,acc");
9808       emitLabel (tlbl1);
9809       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9810       popB (pushedB);
9811       aopPut (result, "a", 0);
9812       goto release;
9813     }
9814
9815   reAdjustPreg (AOP (result));
9816
9817   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9818   emitLabel (tlbl);
9819   l = aopGet (result, offset, FALSE, FALSE, NULL);
9820   MOVA (l);
9821   emitcode ("add", "a,acc");
9822   aopPut (result, "a", offset++);
9823   _startLazyDPSEvaluation ();
9824   while (--size)
9825     {
9826       l = aopGet (result, offset, FALSE, FALSE, NULL);
9827       MOVA (l);
9828       emitcode ("rlc", "a");
9829       aopPut (result, "a", offset++);
9830     }
9831   _endLazyDPSEvaluation ();
9832   reAdjustPreg (AOP (result));
9833
9834   emitLabel (tlbl1);
9835   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9836   popB (pushedB);
9837 release:
9838   freeAsmop (result, NULL, ic, TRUE);
9839   freeAsmop (left, NULL, ic, TRUE);
9840 }
9841
9842 #ifdef BETTER_LITERAL_SHIFT
9843 /*-----------------------------------------------------------------*/
9844 /* genrshOne - right shift a one byte quantity by known count      */
9845 /*-----------------------------------------------------------------*/
9846 static void
9847 genrshOne (operand * result, operand * left,
9848            int shCount, int sign)
9849 {
9850   D (emitcode (";", "genrshOne"));
9851
9852   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9853 }
9854 #endif
9855
9856 #ifdef BETTER_LITERAL_SHIFT
9857 /*-----------------------------------------------------------------*/
9858 /* genrshTwo - right shift two bytes by known amount != 0          */
9859 /*-----------------------------------------------------------------*/
9860 static void
9861 genrshTwo (operand * result, operand * left,
9862            int shCount, int sign)
9863 {
9864   D (emitcode (";", "genrshTwo"));
9865
9866   /* if shCount >= 8 */
9867   if (shCount >= 8)
9868     {
9869       shCount -= 8;
9870       _startLazyDPSEvaluation();
9871       if (shCount)
9872         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9873       else
9874         movLeft2Result (left, MSB16, result, LSB, sign);
9875       addSign (result, MSB16, sign);
9876       _endLazyDPSEvaluation();
9877     }
9878
9879   /*  1 <= shCount <= 7 */
9880   else
9881     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9882 }
9883 #endif
9884
9885 /*-----------------------------------------------------------------*/
9886 /* shiftRLong - shift right one long from left to result           */
9887 /* offl = LSB or MSB16                                             */
9888 /*-----------------------------------------------------------------*/
9889 static void
9890 shiftRLong (operand * left, int offl,
9891             operand * result, int sign)
9892 {
9893   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9894
9895   if (overlapping && offl>1)
9896     {
9897       // we are in big trouble, but this shouldn't happen
9898       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9899     }
9900
9901   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9902
9903   if (offl==MSB16)
9904     {
9905       // shift is > 8
9906       if (sign)
9907         {
9908           emitcode ("rlc", "a");
9909           emitcode ("subb", "a,acc");
9910           emitcode ("xch", "a,%s",
9911                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9912         }
9913       else
9914         {
9915           aopPut (result, zero, MSB32);
9916         }
9917     }
9918
9919   if (!sign)
9920     {
9921       emitcode ("clr", "c");
9922     }
9923   else
9924     {
9925       emitcode ("mov", "c,acc.7");
9926     }
9927
9928   emitcode ("rrc", "a");
9929
9930   if (overlapping && offl==MSB16)
9931     {
9932       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9933     }
9934   else
9935     {
9936       aopPut (result, "a", MSB32 - offl);
9937       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9938     }
9939
9940   emitcode ("rrc", "a");
9941
9942   if (overlapping && offl==MSB16)
9943     {
9944       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9945     }
9946   else
9947     {
9948       aopPut (result, "a", MSB24 - offl);
9949       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9950     }
9951
9952   emitcode ("rrc", "a");
9953   if (offl != LSB)
9954     {
9955       aopPut (result, "a", MSB16 - offl);
9956     }
9957   else
9958     {
9959       if (overlapping && offl==MSB16)
9960         {
9961           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9962         }
9963       else
9964         {
9965           aopPut (result, "a", MSB16 - offl);
9966           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9967         }
9968       emitcode ("rrc", "a");
9969       aopPut (result, "a", LSB);
9970     }
9971 }
9972
9973 /*-----------------------------------------------------------------*/
9974 /* genrshFour - shift four byte by a known amount != 0             */
9975 /*-----------------------------------------------------------------*/
9976 static void
9977 genrshFour (operand * result, operand * left,
9978             int shCount, int sign)
9979 {
9980   D (emitcode (";", "genrshFour"));
9981
9982   /* if shifting more that 3 bytes */
9983   if (shCount >= 24)
9984     {
9985       shCount -= 24;
9986       _startLazyDPSEvaluation();
9987       if (shCount)
9988         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9989       else
9990         movLeft2Result (left, MSB32, result, LSB, sign);
9991       addSign (result, MSB16, sign);
9992       _endLazyDPSEvaluation();
9993     }
9994   else if (shCount >= 16)
9995     {
9996       shCount -= 16;
9997       _startLazyDPSEvaluation();
9998       if (shCount)
9999         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
10000       else
10001         {
10002           movLeft2Result (left, MSB24, result, LSB, 0);
10003           movLeft2Result (left, MSB32, result, MSB16, sign);
10004         }
10005       addSign (result, MSB24, sign);
10006       _endLazyDPSEvaluation();
10007     }
10008   else if (shCount >= 8)
10009     {
10010       shCount -= 8;
10011       _startLazyDPSEvaluation();
10012       if (shCount == 1)
10013         {
10014           shiftRLong (left, MSB16, result, sign);
10015         }
10016       else if (shCount == 0)
10017         {
10018           movLeft2Result (left, MSB16, result, LSB, 0);
10019           movLeft2Result (left, MSB24, result, MSB16, 0);
10020           movLeft2Result (left, MSB32, result, MSB24, sign);
10021           addSign (result, MSB32, sign);
10022         }
10023       else
10024         {
10025           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
10026           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
10027           /* the last shift is signed */
10028           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
10029           addSign (result, MSB32, sign);
10030         }
10031         _endLazyDPSEvaluation();
10032     }
10033   else
10034     {
10035       /* 1 <= shCount <= 7 */
10036       if (shCount <= 2)
10037         {
10038           shiftRLong (left, LSB, result, sign);
10039           if (shCount == 2)
10040             shiftRLong (result, LSB, result, sign);
10041         }
10042       else
10043         {
10044           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
10045           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
10046           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
10047         }
10048     }
10049 }
10050
10051 #ifdef BETTER_LITERAL_SHIFT
10052 /*-----------------------------------------------------------------*/
10053 /* genRightShiftLiteral - right shifting by known count            */
10054 /*-----------------------------------------------------------------*/
10055 static bool
10056 genRightShiftLiteral (operand * left,
10057                       operand * right,
10058                       operand * result,
10059                       iCode * ic,
10060                       int sign)
10061 {
10062   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10063   int size;
10064
10065   size = getSize (operandType (result));
10066
10067   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
10068
10069   /* We only handle certain easy cases so far. */
10070   if ((shCount != 0)
10071    && (shCount < (size * 8))
10072    && (size != 1)
10073    && (size != 2)
10074    && (size != 4))
10075   {
10076       D(emitcode (";", "genRightShiftLiteral wimping out"););
10077       return FALSE;
10078   }
10079
10080   freeAsmop (right, NULL, ic, TRUE);
10081
10082   aopOp (left, ic, FALSE, FALSE);
10083   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10084
10085 #if VIEW_SIZE
10086   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
10087             AOP_SIZE (left));
10088 #endif
10089
10090   /* test the LEFT size !!! */
10091
10092   /* I suppose that the left size >= result size */
10093   if (shCount == 0)
10094     {
10095       size = getDataSize (result);
10096       _startLazyDPSEvaluation();
10097       while (size--)
10098         movLeft2Result (left, size, result, size, 0);
10099       _endLazyDPSEvaluation();
10100     }
10101   else if (shCount >= (size * 8))
10102     {
10103       if (sign)
10104         {
10105           /* get sign in acc.7 */
10106           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
10107         }
10108       addSign (result, LSB, sign);
10109     }
10110   else
10111     {
10112       switch (size)
10113         {
10114         case 1:
10115           genrshOne (result, left, shCount, sign);
10116           break;
10117
10118         case 2:
10119           genrshTwo (result, left, shCount, sign);
10120           break;
10121 #if 1
10122         case 4:
10123           genrshFour (result, left, shCount, sign);
10124           break;
10125 #endif
10126         default:
10127           break;
10128         }
10129     }
10130   freeAsmop (result, NULL, ic, TRUE);
10131   freeAsmop (left, NULL, ic, TRUE);
10132
10133   return TRUE;
10134 }
10135 #endif
10136
10137 /*-----------------------------------------------------------------*/
10138 /* genSignedRightShift - right shift of signed number              */
10139 /*-----------------------------------------------------------------*/
10140 static void
10141 genSignedRightShift (iCode * ic)
10142 {
10143   operand *right, *left, *result;
10144   int size, offset;
10145   char *l;
10146   symbol *tlbl, *tlbl1;
10147   bool pushedB;
10148
10149   D (emitcode (";", "genSignedRightShift"));
10150
10151   /* we do it the hard way put the shift count in b
10152      and loop thru preserving the sign */
10153
10154   right = IC_RIGHT (ic);
10155   left = IC_LEFT (ic);
10156   result = IC_RESULT (ic);
10157
10158   aopOp (right, ic, FALSE, FALSE);
10159
10160 #ifdef BETTER_LITERAL_SHIFT
10161   if (AOP_TYPE (right) == AOP_LIT)
10162     {
10163       if (genRightShiftLiteral (left, right, result, ic, 1))
10164       {
10165         return;
10166       }
10167     }
10168 #endif
10169   /* shift count is unknown then we have to form
10170      a loop get the loop count in B : Note: we take
10171      only the lower order byte since shifting
10172      more that 32 bits make no sense anyway, ( the
10173      largest size of an object can be only 32 bits ) */
10174
10175   pushedB = pushB ();
10176   if (AOP_TYPE (right) == AOP_LIT)
10177   {
10178       /* Really should be handled by genRightShiftLiteral,
10179        * but since I'm too lazy to fix that today, at least we can make
10180        * some small improvement.
10181        */
10182        emitcode("mov", "b,#!constbyte",
10183                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10184   }
10185   else
10186   {
10187         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10188         emitcode ("inc", "b");
10189   }
10190   freeAsmop (right, NULL, ic, TRUE);
10191   aopOp (left, ic, FALSE, FALSE);
10192   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10193
10194   /* now move the left to the result if they are not the
10195      same */
10196   if (!sameRegs (AOP (left), AOP (result)) &&
10197       AOP_SIZE (result) > 1)
10198     {
10199
10200       size = AOP_SIZE (result);
10201       offset = 0;
10202       _startLazyDPSEvaluation ();
10203       while (size--)
10204         {
10205           l = aopGet (left, offset, FALSE, TRUE, NULL);
10206           if (*l == '@' && IS_AOP_PREG (result))
10207             {
10208
10209               emitcode ("mov", "a,%s", l);
10210               aopPut (result, "a", offset);
10211             }
10212           else
10213             aopPut (result, l, offset);
10214           offset++;
10215         }
10216       _endLazyDPSEvaluation ();
10217     }
10218
10219   /* mov the highest order bit to OVR */
10220   tlbl = newiTempLabel (NULL);
10221   tlbl1 = newiTempLabel (NULL);
10222
10223   size = AOP_SIZE (result);
10224   offset = size - 1;
10225   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10226   emitcode ("rlc", "a");
10227   emitcode ("mov", "ov,c");
10228   /* if it is only one byte then */
10229   if (size == 1)
10230     {
10231       l = aopGet (left, 0, FALSE, FALSE, NULL);
10232       MOVA (l);
10233       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10234       emitLabel (tlbl);
10235       emitcode ("mov", "c,ov");
10236       emitcode ("rrc", "a");
10237       emitLabel (tlbl1);
10238       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10239       popB (pushedB);
10240       aopPut (result, "a", 0);
10241       goto release;
10242     }
10243
10244   reAdjustPreg (AOP (result));
10245   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10246   emitLabel (tlbl);
10247   emitcode ("mov", "c,ov");
10248   _startLazyDPSEvaluation ();
10249   while (size--)
10250     {
10251       l = aopGet (result, offset, FALSE, FALSE, NULL);
10252       MOVA (l);
10253       emitcode ("rrc", "a");
10254       aopPut (result, "a", offset--);
10255     }
10256   _endLazyDPSEvaluation ();
10257   reAdjustPreg (AOP (result));
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 /* genRightShift - generate code for right shifting                */
10269 /*-----------------------------------------------------------------*/
10270 static void
10271 genRightShift (iCode * ic)
10272 {
10273   operand *right, *left, *result;
10274   sym_link *letype;
10275   int size, offset;
10276   char *l;
10277   symbol *tlbl, *tlbl1;
10278   bool pushedB;
10279
10280   D (emitcode (";", "genRightShift"));
10281
10282   /* if signed then we do it the hard way preserve the
10283      sign bit moving it inwards */
10284   letype = getSpec (operandType (IC_LEFT (ic)));
10285
10286   if (!SPEC_USIGN (letype))
10287     {
10288       genSignedRightShift (ic);
10289       return;
10290     }
10291
10292   /* signed & unsigned types are treated the same : i.e. the
10293      signed is NOT propagated inwards : quoting from the
10294      ANSI - standard : "for E1 >> E2, is equivalent to division
10295      by 2**E2 if unsigned or if it has a non-negative value,
10296      otherwise the result is implementation defined ", MY definition
10297      is that the sign does not get propagated */
10298
10299   right = IC_RIGHT (ic);
10300   left = IC_LEFT (ic);
10301   result = IC_RESULT (ic);
10302
10303   aopOp (right, ic, FALSE, FALSE);
10304
10305 #ifdef BETTER_LITERAL_SHIFT
10306   /* if the shift count is known then do it
10307      as efficiently as possible */
10308   if (AOP_TYPE (right) == AOP_LIT)
10309     {
10310       if (genRightShiftLiteral (left, right, result, ic, 0))
10311       {
10312         return;
10313       }
10314     }
10315 #endif
10316
10317   /* shift count is unknown then we have to form
10318      a loop get the loop count in B : Note: we take
10319      only the lower order byte since shifting
10320      more that 32 bits make no sense anyway, ( the
10321      largest size of an object can be only 32 bits ) */
10322
10323   pushedB = pushB ();
10324   if (AOP_TYPE (right) == AOP_LIT)
10325   {
10326       /* Really should be handled by genRightShiftLiteral,
10327        * but since I'm too lazy to fix that today, at least we can make
10328        * some small improvement.
10329        */
10330        emitcode("mov", "b,#!constbyte",
10331                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10332   }
10333   else
10334   {
10335       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10336       emitcode ("inc", "b");
10337   }
10338   freeAsmop (right, NULL, ic, TRUE);
10339   aopOp (left, ic, FALSE, FALSE);
10340   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10341
10342   /* now move the left to the result if they are not the
10343      same */
10344   if (!sameRegs (AOP (left), AOP (result)) &&
10345       AOP_SIZE (result) > 1)
10346     {
10347       size = AOP_SIZE (result);
10348       offset = 0;
10349       _startLazyDPSEvaluation ();
10350       while (size--)
10351         {
10352           l = aopGet (left, offset, FALSE, TRUE, NULL);
10353           if (*l == '@' && IS_AOP_PREG (result))
10354             {
10355
10356               emitcode ("mov", "a,%s", l);
10357               aopPut (result, "a", offset);
10358             }
10359           else
10360             aopPut (result, l, offset);
10361           offset++;
10362         }
10363       _endLazyDPSEvaluation ();
10364     }
10365
10366   tlbl = newiTempLabel (NULL);
10367   tlbl1 = newiTempLabel (NULL);
10368   size = AOP_SIZE (result);
10369   offset = size - 1;
10370
10371   /* if it is only one byte then */
10372   if (size == 1)
10373     {
10374       l = aopGet (left, 0, FALSE, FALSE, NULL);
10375       MOVA (l);
10376       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10377       emitLabel (tlbl);
10378       CLRC;
10379       emitcode ("rrc", "a");
10380       emitLabel (tlbl1);
10381       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10382       popB (pushedB);
10383       aopPut (result, "a", 0);
10384       goto release;
10385     }
10386
10387   reAdjustPreg (AOP (result));
10388   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10389   emitLabel (tlbl);
10390   CLRC;
10391   _startLazyDPSEvaluation ();
10392   while (size--)
10393     {
10394       l = aopGet (result, offset, FALSE, FALSE, NULL);
10395       MOVA (l);
10396       emitcode ("rrc", "a");
10397       aopPut (result, "a", offset--);
10398     }
10399   _endLazyDPSEvaluation ();
10400   reAdjustPreg (AOP (result));
10401
10402   emitLabel (tlbl1);
10403   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10404   popB (pushedB);
10405
10406 release:
10407   freeAsmop (result, NULL, ic, TRUE);
10408   freeAsmop (left, NULL, ic, TRUE);
10409 }
10410
10411 /*-----------------------------------------------------------------*/
10412 /* emitPtrByteGet - emits code to get a byte into A through a      */
10413 /*                  pointer register (R0, R1, or DPTR). The        */
10414 /*                  original value of A can be preserved in B.     */
10415 /*-----------------------------------------------------------------*/
10416 static void
10417 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10418 {
10419   switch (p_type)
10420     {
10421     case IPOINTER:
10422     case POINTER:
10423       if (preserveAinB)
10424         emitcode ("mov", "b,a");
10425       emitcode ("mov", "a,@%s", rname);
10426       break;
10427
10428     case PPOINTER:
10429       if (preserveAinB)
10430         emitcode ("mov", "b,a");
10431       emitcode ("movx", "a,@%s", rname);
10432       break;
10433
10434     case FPOINTER:
10435       if (preserveAinB)
10436         emitcode ("mov", "b,a");
10437       emitcode ("movx", "a,@dptr");
10438       break;
10439
10440     case CPOINTER:
10441       if (preserveAinB)
10442         emitcode ("mov", "b,a");
10443       emitcode ("clr", "a");
10444       emitcode ("movc", "a,@a+dptr");
10445       break;
10446
10447     case GPOINTER:
10448       if (preserveAinB)
10449         {
10450           emitcode ("push", "b");
10451           emitcode ("push", "acc");
10452         }
10453       emitcode ("lcall", "__gptrget");
10454       if (preserveAinB)
10455         emitcode ("pop", "b");
10456       break;
10457     }
10458 }
10459
10460 /*-----------------------------------------------------------------*/
10461 /* emitPtrByteSet - emits code to set a byte from src through a    */
10462 /*                  pointer register (R0, R1, or DPTR).            */
10463 /*-----------------------------------------------------------------*/
10464 static void
10465 emitPtrByteSet (char *rname, int p_type, char *src)
10466 {
10467   switch (p_type)
10468     {
10469     case IPOINTER:
10470     case POINTER:
10471       if (*src=='@')
10472         {
10473           MOVA (src);
10474           emitcode ("mov", "@%s,a", rname);
10475         }
10476       else
10477         emitcode ("mov", "@%s,%s", rname, src);
10478       break;
10479
10480     case PPOINTER:
10481       MOVA (src);
10482       emitcode ("movx", "@%s,a", rname);
10483       break;
10484
10485     case FPOINTER:
10486       MOVA (src);
10487       emitcode ("movx", "@dptr,a");
10488       break;
10489
10490     case GPOINTER:
10491       MOVA (src);
10492       emitcode ("lcall", "__gptrput");
10493       break;
10494     }
10495 }
10496
10497 /*-----------------------------------------------------------------*/
10498 /* genUnpackBits - generates code for unpacking bits               */
10499 /*-----------------------------------------------------------------*/
10500 static void
10501 genUnpackBits (operand * result, char *rname, int ptype)
10502 {
10503   int offset = 0;       /* result byte offset */
10504   int rsize;            /* result size */
10505   int rlen = 0;         /* remaining bitfield length */
10506   sym_link *etype;      /* bitfield type information */
10507   int blen;             /* bitfield length */
10508   int bstr;             /* bitfield starting bit within byte */
10509
10510   D(emitcode (";", "genUnpackBits"));
10511
10512   etype = getSpec (operandType (result));
10513   rsize = getSize (operandType (result));
10514   blen = SPEC_BLEN (etype);
10515   bstr = SPEC_BSTR (etype);
10516
10517   /* If the bitfield length is less than a byte */
10518   if (blen < 8)
10519     {
10520       emitPtrByteGet (rname, ptype, FALSE);
10521       AccRol (8 - bstr);
10522       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10523       if (!SPEC_USIGN (etype))
10524         {
10525           /* signed bitfield */
10526           symbol *tlbl = newiTempLabel (NULL);
10527
10528           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10529           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10530           emitLabel (tlbl);
10531         }
10532       aopPut (result, "a", offset++);
10533       goto finish;
10534     }
10535
10536   /* Bit field did not fit in a byte. Copy all
10537      but the partial byte at the end.  */
10538   for (rlen=blen;rlen>=8;rlen-=8)
10539     {
10540       emitPtrByteGet (rname, ptype, FALSE);
10541       aopPut (result, "a", offset++);
10542       if (rlen>8)
10543         emitcode ("inc", "%s", rname);
10544     }
10545
10546   /* Handle the partial byte at the end */
10547   if (rlen)
10548     {
10549       emitPtrByteGet (rname, ptype, FALSE);
10550       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10551       if (!SPEC_USIGN (etype))
10552         {
10553           /* signed bitfield */
10554           symbol *tlbl = newiTempLabel (NULL);
10555
10556           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10557           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10558           emitLabel (tlbl);
10559         }
10560       aopPut (result, "a", offset++);
10561     }
10562
10563 finish:
10564   if (offset < rsize)
10565     {
10566       char *source;
10567
10568       if (SPEC_USIGN (etype))
10569         source = zero;
10570       else
10571         {
10572           /* signed bitfield: sign extension with 0x00 or 0xff */
10573           emitcode ("rlc", "a");
10574           emitcode ("subb", "a,acc");
10575
10576           source = "a";
10577         }
10578       rsize -= offset;
10579       while (rsize--)
10580         aopPut (result, source, offset++);
10581     }
10582 }
10583
10584
10585 /*-----------------------------------------------------------------*/
10586 /* genDataPointerGet - generates code when ptr offset is known     */
10587 /*-----------------------------------------------------------------*/
10588 static void
10589 genDataPointerGet (operand * left,
10590                    operand * result,
10591                    iCode * ic)
10592 {
10593   char *l;
10594   char buffer[256];
10595   int size, offset = 0;
10596   aopOp (result, ic, TRUE, FALSE);
10597
10598   /* get the string representation of the name */
10599   l = aopGet (left, 0, FALSE, TRUE, NULL);
10600   size = AOP_SIZE (result);
10601   _startLazyDPSEvaluation ();
10602   while (size--)
10603     {
10604       if (offset)
10605         {
10606           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
10607         }
10608       else
10609         {
10610           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
10611         }
10612       aopPut (result, buffer, offset++);
10613     }
10614   _endLazyDPSEvaluation ();
10615
10616   freeAsmop (result, NULL, ic, TRUE);
10617   freeAsmop (left, NULL, ic, TRUE);
10618 }
10619
10620 /*-----------------------------------------------------------------*/
10621 /* genNearPointerGet - emitcode for near pointer fetch             */
10622 /*-----------------------------------------------------------------*/
10623 static void
10624 genNearPointerGet (operand * left,
10625                    operand * result,
10626                    iCode * ic,
10627                    iCode *pi)
10628 {
10629   asmop *aop = NULL;
10630   regs *preg;
10631   char *rname;
10632   sym_link *rtype, *retype, *letype;
10633   sym_link *ltype = operandType (left);
10634   char buffer[80];
10635
10636   rtype = operandType (result);
10637   retype = getSpec (rtype);
10638   letype = getSpec (ltype);
10639
10640   aopOp (left, ic, FALSE, FALSE);
10641
10642   /* if left is rematerialisable and
10643      result is not bitfield variable type and
10644      the left is pointer to data space i.e
10645      lower 128 bytes of space */
10646   if (AOP_TYPE (left) == AOP_IMMD &&
10647       !IS_BITFIELD (retype) &&
10648       !IS_BITFIELD (letype) &&
10649       DCL_TYPE (ltype) == POINTER)
10650     {
10651       genDataPointerGet (left, result, ic);
10652       return;
10653     }
10654
10655   /* if the value is already in a pointer register
10656      then don't need anything more */
10657   if (!AOP_INPREG (AOP (left)))
10658     {
10659       /* otherwise get a free pointer register */
10660       aop = newAsmop (0);
10661       preg = getFreePtr (ic, &aop, FALSE);
10662       emitcode ("mov", "%s,%s",
10663                 preg->name,
10664                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10665       rname = preg->name;
10666     }
10667   else
10668     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10669
10670   freeAsmop (left, NULL, ic, TRUE);
10671   aopOp (result, ic, FALSE, FALSE);
10672
10673   /* if bitfield then unpack the bits */
10674   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10675     genUnpackBits (result, rname, POINTER);
10676   else
10677     {
10678       /* we have can just get the values */
10679       int size = AOP_SIZE (result);
10680       int offset = 0;
10681
10682       while (size--)
10683         {
10684           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10685             {
10686
10687               emitcode ("mov", "a,@%s", rname);
10688               aopPut (result, "a", offset);
10689             }
10690           else
10691             {
10692               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10693               aopPut (result, buffer, offset);
10694             }
10695           offset++;
10696           if (size || pi)
10697             emitcode ("inc", "%s", rname);
10698         }
10699     }
10700
10701   /* now some housekeeping stuff */
10702   if (aop)      /* we had to allocate for this iCode */
10703     {
10704       if (pi) { /* post increment present */
10705         aopPut (left, rname, 0);
10706       }
10707       freeAsmop (NULL, aop, ic, TRUE);
10708     }
10709   else
10710     {
10711       /* we did not allocate which means left
10712          already in a pointer register, then
10713          if size > 0 && this could be used again
10714          we have to point it back to where it
10715          belongs */
10716       if (AOP_SIZE (result) > 1 &&
10717           !OP_SYMBOL (left)->remat &&
10718           (OP_SYMBOL (left)->liveTo > ic->seq ||
10719            ic->depth) &&
10720           !pi)
10721         {
10722           int size = AOP_SIZE (result) - 1;
10723           while (size--)
10724             emitcode ("dec", "%s", rname);
10725         }
10726     }
10727
10728   /* done */
10729   freeAsmop (result, NULL, ic, TRUE);
10730   if (pi) pi->generated = 1;
10731 }
10732
10733 /*-----------------------------------------------------------------*/
10734 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10735 /*-----------------------------------------------------------------*/
10736 static void
10737 genPagedPointerGet (operand * left,
10738                     operand * result,
10739                     iCode * ic,
10740                     iCode * pi)
10741 {
10742   asmop *aop = NULL;
10743   regs *preg;
10744   char *rname;
10745   sym_link *rtype, *retype, *letype;
10746
10747   rtype = operandType (result);
10748   retype = getSpec (rtype);
10749   letype = getSpec (operandType (left));
10750   aopOp (left, ic, FALSE, FALSE);
10751
10752   /* if the value is already in a pointer register
10753      then don't need anything more */
10754   if (!AOP_INPREG (AOP (left)))
10755     {
10756       /* otherwise get a free pointer register */
10757       aop = newAsmop (0);
10758       preg = getFreePtr (ic, &aop, FALSE);
10759       emitcode ("mov", "%s,%s",
10760                 preg->name,
10761                 aopGet (left, 0, FALSE, TRUE, NULL));
10762       rname = preg->name;
10763     }
10764   else
10765     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10766
10767   freeAsmop (left, NULL, ic, TRUE);
10768   aopOp (result, ic, FALSE, FALSE);
10769
10770   /* if bitfield then unpack the bits */
10771   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10772     genUnpackBits (result, rname, PPOINTER);
10773   else
10774     {
10775       /* we have can just get the values */
10776       int size = AOP_SIZE (result);
10777       int offset = 0;
10778
10779       while (size--)
10780         {
10781
10782           emitcode ("movx", "a,@%s", rname);
10783           aopPut (result, "a", offset);
10784
10785           offset++;
10786
10787           if (size || pi)
10788             emitcode ("inc", "%s", rname);
10789         }
10790     }
10791
10792   /* now some housekeeping stuff */
10793   if (aop)      /* we had to allocate for this iCode */
10794     {
10795       if (pi)
10796         aopPut (left, rname, 0);
10797       freeAsmop (NULL, aop, ic, TRUE);
10798     }
10799   else
10800     {
10801       /* we did not allocate which means left
10802          already in a pointer register, then
10803          if size > 0 && this could be used again
10804          we have to point it back to where it
10805          belongs */
10806       if (AOP_SIZE (result) > 1 &&
10807           !OP_SYMBOL (left)->remat &&
10808           (OP_SYMBOL (left)->liveTo > ic->seq ||
10809            ic->depth) &&
10810           !pi)
10811         {
10812           int size = AOP_SIZE (result) - 1;
10813           while (size--)
10814             emitcode ("dec", "%s", rname);
10815         }
10816     }
10817
10818   /* done */
10819   freeAsmop (result, NULL, ic, TRUE);
10820   if (pi) pi->generated = 1;
10821 }
10822
10823 /*-----------------------------------------------------------------*/
10824 /* genFarPointerGet - get value from far space                     */
10825 /*-----------------------------------------------------------------*/
10826 static void
10827 genFarPointerGet (operand * left,
10828                   operand * result, iCode * ic, iCode *pi)
10829 {
10830   int size, offset, dopi=1;
10831   sym_link *retype = getSpec (operandType (result));
10832   sym_link *letype = getSpec (operandType (left));
10833   D (emitcode (";", "genFarPointerGet"););
10834
10835   aopOp (left, ic, FALSE, FALSE);
10836
10837   /* if the operand is already in dptr
10838      then we do nothing else we move the value to dptr */
10839   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10840     {
10841       /* if this is rematerializable */
10842       if (AOP_TYPE (left) == AOP_IMMD)
10843         {
10844           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10845         }
10846       else
10847         {
10848           /* we need to get it byte by byte */
10849           _startLazyDPSEvaluation ();
10850           if (AOP_TYPE (left) != AOP_DPTR)
10851             {
10852               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10853               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10854               if (options.model == MODEL_FLAT24)
10855                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10856             }
10857           else
10858             {
10859               /* We need to generate a load to DPTR indirect through DPTR. */
10860               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10861               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10862               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10863               if (options.model == MODEL_FLAT24)
10864                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10865               emitcode ("pop", "dph");
10866               emitcode ("pop", "dpl");
10867               dopi =0;
10868             }
10869           _endLazyDPSEvaluation ();
10870         }
10871     }
10872   /* so dptr now contains the address */
10873   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10874
10875   /* if bit then unpack */
10876   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10877       if (AOP_INDPTRn(left)) {
10878           genSetDPTR(AOP(left)->aopu.dptr);
10879       }
10880       genUnpackBits (result, "dptr", FPOINTER);
10881       if (AOP_INDPTRn(left)) {
10882           genSetDPTR(0);
10883       }
10884   } else
10885     {
10886       size = AOP_SIZE (result);
10887       offset = 0;
10888
10889       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10890           while (size--) {
10891               genSetDPTR(AOP(left)->aopu.dptr);
10892               emitcode ("movx", "a,@dptr");
10893               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10894                   emitcode ("inc", "dptr");
10895               genSetDPTR (0);
10896               aopPut (result, "a", offset++);
10897           }
10898       } else {
10899           _startLazyDPSEvaluation ();
10900           while (size--) {
10901               if (AOP_INDPTRn(left)) {
10902                   genSetDPTR(AOP(left)->aopu.dptr);
10903               } else {
10904                   genSetDPTR (0);
10905               }
10906               _flushLazyDPS ();
10907
10908               emitcode ("movx", "a,@dptr");
10909               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10910                   emitcode ("inc", "dptr");
10911
10912               aopPut (result, "a", offset++);
10913           }
10914           _endLazyDPSEvaluation ();
10915       }
10916     }
10917   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10918       if (!AOP_INDPTRn(left)) {
10919           _startLazyDPSEvaluation ();
10920           aopPut (left, "dpl", 0);
10921           aopPut (left, "dph", 1);
10922           if (options.model == MODEL_FLAT24)
10923               aopPut (left, "dpx", 2);
10924           _endLazyDPSEvaluation ();
10925       }
10926     pi->generated = 1;
10927   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10928              AOP_SIZE(result) > 1 &&
10929              IS_SYMOP(left) &&
10930              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10931
10932       size = AOP_SIZE (result) - 1;
10933       if (AOP_INDPTRn(left)) {
10934           genSetDPTR(AOP(left)->aopu.dptr);
10935       }
10936       while (size--) emitcode ("lcall","__decdptr");
10937       if (AOP_INDPTRn(left)) {
10938           genSetDPTR(0);
10939       }
10940   }
10941
10942   freeAsmop (result, NULL, ic, TRUE);
10943   freeAsmop (left, NULL, ic, TRUE);
10944 }
10945
10946 /*-----------------------------------------------------------------*/
10947 /* genCodePointerGet - get value from code space                   */
10948 /*-----------------------------------------------------------------*/
10949 static void
10950 genCodePointerGet (operand * left,
10951                     operand * result, iCode * ic, iCode *pi)
10952 {
10953   int size, offset, dopi=1;
10954   sym_link *retype = getSpec (operandType (result));
10955
10956   aopOp (left, ic, FALSE, FALSE);
10957
10958   /* if the operand is already in dptr
10959      then we do nothing else we move the value to dptr */
10960   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10961     {
10962       /* if this is rematerializable */
10963       if (AOP_TYPE (left) == AOP_IMMD)
10964         {
10965           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10966         }
10967       else
10968         {                       /* we need to get it byte by byte */
10969           _startLazyDPSEvaluation ();
10970           if (AOP_TYPE (left) != AOP_DPTR)
10971             {
10972               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10973               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10974               if (options.model == MODEL_FLAT24)
10975                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10976             }
10977           else
10978             {
10979               /* We need to generate a load to DPTR indirect through DPTR. */
10980               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10981               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10982               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10983               if (options.model == MODEL_FLAT24)
10984                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10985               emitcode ("pop", "dph");
10986               emitcode ("pop", "dpl");
10987               dopi=0;
10988             }
10989           _endLazyDPSEvaluation ();
10990         }
10991     }
10992   /* so dptr now contains the address */
10993   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10994
10995   /* if bit then unpack */
10996   if (IS_BITFIELD (retype)) {
10997       if (AOP_INDPTRn(left)) {
10998           genSetDPTR(AOP(left)->aopu.dptr);
10999       }
11000       genUnpackBits (result, "dptr", CPOINTER);
11001       if (AOP_INDPTRn(left)) {
11002           genSetDPTR(0);
11003       }
11004   } else
11005     {
11006       size = AOP_SIZE (result);
11007       offset = 0;
11008       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
11009           while (size--) {
11010               genSetDPTR(AOP(left)->aopu.dptr);
11011               emitcode ("clr", "a");
11012               emitcode ("movc", "a,@a+dptr");
11013               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
11014                   emitcode ("inc", "dptr");
11015               genSetDPTR (0);
11016               aopPut (result, "a", offset++);
11017           }
11018       } else {
11019           _startLazyDPSEvaluation ();
11020           while (size--)
11021               {
11022                   if (AOP_INDPTRn(left)) {
11023                       genSetDPTR(AOP(left)->aopu.dptr);
11024                   } else {
11025                       genSetDPTR (0);
11026                   }
11027                   _flushLazyDPS ();
11028
11029                   emitcode ("clr", "a");
11030                   emitcode ("movc", "a,@a+dptr");
11031                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
11032                       emitcode ("inc", "dptr");
11033                   aopPut (result, "a", offset++);
11034               }
11035           _endLazyDPSEvaluation ();
11036       }
11037     }
11038   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
11039       if (!AOP_INDPTRn(left)) {
11040           _startLazyDPSEvaluation ();
11041
11042           aopPut (left, "dpl", 0);
11043           aopPut (left, "dph", 1);
11044           if (options.model == MODEL_FLAT24)
11045               aopPut (left, "dpx", 2);
11046
11047           _endLazyDPSEvaluation ();
11048       }
11049       pi->generated = 1;
11050   } else if (IS_SYMOP(left) &&
11051              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
11052              AOP_SIZE(result) > 1 &&
11053              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11054
11055       size = AOP_SIZE (result) - 1;
11056       if (AOP_INDPTRn(left)) {
11057           genSetDPTR(AOP(left)->aopu.dptr);
11058       }
11059       while (size--) emitcode ("lcall","__decdptr");
11060       if (AOP_INDPTRn(left)) {
11061           genSetDPTR(0);
11062       }
11063   }
11064
11065   freeAsmop (result, NULL, ic, TRUE);
11066   freeAsmop (left, NULL, ic, TRUE);
11067 }
11068
11069 /*-----------------------------------------------------------------*/
11070 /* genGenPointerGet - get value from generic pointer space         */
11071 /*-----------------------------------------------------------------*/
11072 static void
11073 genGenPointerGet (operand * left,
11074                   operand * result, iCode * ic, iCode * pi)
11075 {
11076   int size, offset;
11077   bool pushedB;
11078   sym_link *retype = getSpec (operandType (result));
11079   sym_link *letype = getSpec (operandType (left));
11080
11081   D (emitcode (";", "genGenPointerGet"));
11082
11083   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
11084
11085   pushedB = pushB ();
11086   /* if the operand is already in dptr
11087      then we do nothing else we move the value to dptr */
11088   if (AOP_TYPE (left) != AOP_STR)
11089     {
11090       /* if this is rematerializable */
11091       if (AOP_TYPE (left) == AOP_IMMD)
11092         {
11093           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
11094           if (AOP(left)->aopu.aop_immd.from_cast_remat)
11095             {
11096               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
11097             }
11098           else
11099             {
11100               emitcode ("mov", "b,#%d", pointerCode (retype));
11101             }
11102         }
11103       else
11104         {                       /* we need to get it byte by byte */
11105           _startLazyDPSEvaluation ();
11106           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
11107           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
11108           if (options.model == MODEL_FLAT24) {
11109               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
11110               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
11111           } else {
11112               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
11113           }
11114           _endLazyDPSEvaluation ();
11115         }
11116     }
11117
11118   /* so dptr-b now contains the address */
11119   aopOp (result, ic, FALSE, TRUE);
11120
11121   /* if bit then unpack */
11122   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11123     {
11124       genUnpackBits (result, "dptr", GPOINTER);
11125     }
11126   else
11127     {
11128       size = AOP_SIZE (result);
11129       offset = 0;
11130
11131       while (size--)
11132         {
11133           if (size)
11134             {
11135                 // Get two bytes at a time, results in _AP & A.
11136                 // dptr will be incremented ONCE by __gptrgetWord.
11137                 //
11138                 // Note: any change here must be coordinated
11139                 // with the implementation of __gptrgetWord
11140                 // in device/lib/_gptrget.c
11141                 emitcode ("lcall", "__gptrgetWord");
11142                 aopPut (result, "a", offset++);
11143                 aopPut (result, DP2_RESULT_REG, offset++);
11144                 size--;
11145             }
11146           else
11147             {
11148                 // Only one byte to get.
11149                 emitcode ("lcall", "__gptrget");
11150                 aopPut (result, "a", offset++);
11151             }
11152
11153           if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11154             {
11155                 emitcode ("inc", "dptr");
11156             }
11157         }
11158     }
11159
11160   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11161     _startLazyDPSEvaluation ();
11162
11163     aopPut (left, "dpl", 0);
11164     aopPut (left, "dph", 1);
11165     if (options.model == MODEL_FLAT24) {
11166         aopPut (left, "dpx", 2);
11167         aopPut (left, "b", 3);
11168     } else  aopPut (left, "b", 2);
11169
11170     _endLazyDPSEvaluation ();
11171
11172     pi->generated = 1;
11173   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11174              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11175
11176       size = AOP_SIZE (result) - 1;
11177       while (size--) emitcode ("lcall","__decdptr");
11178   }
11179   popB (pushedB);
11180
11181   freeAsmop (result, NULL, ic, TRUE);
11182   freeAsmop (left, NULL, ic, TRUE);
11183 }
11184
11185 /*-----------------------------------------------------------------*/
11186 /* genPointerGet - generate code for pointer get                   */
11187 /*-----------------------------------------------------------------*/
11188 static void
11189 genPointerGet (iCode * ic, iCode *pi)
11190 {
11191   operand *left, *result;
11192   sym_link *type, *etype;
11193   int p_type;
11194
11195   D (emitcode (";", "genPointerGet"));
11196
11197   left = IC_LEFT (ic);
11198   result = IC_RESULT (ic);
11199
11200   /* depending on the type of pointer we need to
11201      move it to the correct pointer register */
11202   type = operandType (left);
11203   etype = getSpec (type);
11204   /* if left is of type of pointer then it is simple */
11205   if (IS_PTR (type) && !IS_FUNC (type->next))
11206     {
11207       p_type = DCL_TYPE (type);
11208     }
11209   else
11210     {
11211       /* we have to go by the storage class */
11212       p_type = PTR_TYPE (SPEC_OCLS (etype));
11213     }
11214
11215   /* special case when cast remat */
11216   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11217       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11218     {
11219       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11220       type = operandType (left);
11221       p_type = DCL_TYPE (type);
11222     }
11223   /* now that we have the pointer type we assign
11224      the pointer values */
11225   switch (p_type)
11226     {
11227
11228     case POINTER:
11229     case IPOINTER:
11230       genNearPointerGet (left, result, ic, pi);
11231       break;
11232
11233     case PPOINTER:
11234       genPagedPointerGet (left, result, ic, pi);
11235       break;
11236
11237     case FPOINTER:
11238       genFarPointerGet (left, result, ic, pi);
11239       break;
11240
11241     case CPOINTER:
11242       genCodePointerGet (left, result, ic, pi);
11243       break;
11244
11245     case GPOINTER:
11246       genGenPointerGet (left, result, ic, pi);
11247       break;
11248     }
11249 }
11250
11251
11252 /*-----------------------------------------------------------------*/
11253 /* genPackBits - generates code for packed bit storage             */
11254 /*-----------------------------------------------------------------*/
11255 static void
11256 genPackBits (sym_link * etype,
11257              operand * right,
11258              char *rname, int p_type)
11259 {
11260   int offset = 0;       /* source byte offset */
11261   int rlen = 0;         /* remaining bitfield length */
11262   int blen;             /* bitfield length */
11263   int bstr;             /* bitfield starting bit within byte */
11264   int litval;           /* source literal value (if AOP_LIT) */
11265   unsigned char mask;   /* bitmask within current byte */
11266
11267   D(emitcode (";", "genPackBits"));
11268
11269   blen = SPEC_BLEN (etype);
11270   bstr = SPEC_BSTR (etype);
11271
11272   /* If the bitfield length is less than a byte */
11273   if (blen < 8)
11274     {
11275       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11276               (unsigned char) (0xFF >> (8 - bstr)));
11277
11278       if (AOP_TYPE (right) == AOP_LIT)
11279         {
11280           /* Case with a bitfield length <8 and literal source
11281           */
11282           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11283           litval <<= bstr;
11284           litval &= (~mask) & 0xff;
11285           emitPtrByteGet (rname, p_type, FALSE);
11286           if ((mask|litval)!=0xff)
11287             emitcode ("anl","a,#!constbyte", mask);
11288           if (litval)
11289             emitcode ("orl","a,#!constbyte", litval);
11290         }
11291       else
11292         {
11293           if ((blen==1) && (p_type!=GPOINTER))
11294             {
11295               /* Case with a bitfield length == 1 and no generic pointer
11296               */
11297               if (AOP_TYPE (right) == AOP_CRY)
11298                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11299               else
11300                 {
11301                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11302                   emitcode ("rrc","a");
11303                 }
11304               emitPtrByteGet (rname, p_type, FALSE);
11305               emitcode ("mov","acc.%d,c",bstr);
11306             }
11307           else
11308             {
11309               bool pushedB;
11310               /* Case with a bitfield length < 8 and arbitrary source
11311               */
11312               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11313               /* shift and mask source value */
11314               AccLsh (bstr);
11315               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11316
11317               pushedB = pushB ();
11318               /* transfer A to B and get next byte */
11319               emitPtrByteGet (rname, p_type, TRUE);
11320
11321               emitcode ("anl", "a,#!constbyte", mask);
11322               emitcode ("orl", "a,b");
11323               if (p_type == GPOINTER)
11324                 emitcode ("pop", "b");
11325
11326               popB (pushedB);
11327            }
11328         }
11329
11330       emitPtrByteSet (rname, p_type, "a");
11331       return;
11332     }
11333
11334   /* Bit length is greater than 7 bits. In this case, copy  */
11335   /* all except the partial byte at the end                 */
11336   for (rlen=blen;rlen>=8;rlen-=8)
11337     {
11338       emitPtrByteSet (rname, p_type,
11339                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11340       if (rlen>8)
11341         emitcode ("inc", "%s", rname);
11342     }
11343
11344   /* If there was a partial byte at the end */
11345   if (rlen)
11346     {
11347       mask = (((unsigned char) -1 << rlen) & 0xff);
11348
11349       if (AOP_TYPE (right) == AOP_LIT)
11350         {
11351           /* Case with partial byte and literal source
11352           */
11353           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11354           litval >>= (blen-rlen);
11355           litval &= (~mask) & 0xff;
11356           emitPtrByteGet (rname, p_type, FALSE);
11357           if ((mask|litval)!=0xff)
11358             emitcode ("anl","a,#!constbyte", mask);
11359           if (litval)
11360             emitcode ("orl","a,#!constbyte", litval);
11361         }
11362       else
11363         {
11364           bool pushedB;
11365           /* Case with partial byte and arbitrary source
11366           */
11367           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11368           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11369
11370           pushedB = pushB ();
11371           /* transfer A to B and get next byte */
11372           emitPtrByteGet (rname, p_type, TRUE);
11373
11374           emitcode ("anl", "a,#!constbyte", mask);
11375           emitcode ("orl", "a,b");
11376           if (p_type == GPOINTER)
11377             emitcode ("pop", "b");
11378
11379           popB (pushedB);
11380         }
11381       emitPtrByteSet (rname, p_type, "a");
11382     }
11383 }
11384
11385
11386 /*-----------------------------------------------------------------*/
11387 /* genDataPointerSet - remat pointer to data space                 */
11388 /*-----------------------------------------------------------------*/
11389 static void
11390 genDataPointerSet (operand * right,
11391                    operand * result,
11392                    iCode * ic)
11393 {
11394   int size, offset = 0;
11395   char *l, buffer[256];
11396
11397   D (emitcode (";", "genDataPointerSet"));
11398
11399   aopOp (right, ic, FALSE, FALSE);
11400
11401   l = aopGet (result, 0, FALSE, TRUE, NULL);
11402   size = AOP_SIZE (right);
11403   while (size--)
11404     {
11405       if (offset)
11406         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11407       else
11408         SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11409       emitcode ("mov", "%s,%s", buffer,
11410                 aopGet (right, offset++, FALSE, FALSE, NULL));
11411     }
11412
11413   freeAsmop (right, NULL, ic, TRUE);
11414   freeAsmop (result, NULL, ic, TRUE);
11415 }
11416
11417 /*-----------------------------------------------------------------*/
11418 /* genNearPointerSet - emitcode for near pointer put               */
11419 /*-----------------------------------------------------------------*/
11420 static void
11421 genNearPointerSet (operand * right,
11422                    operand * result,
11423                    iCode * ic,
11424                    iCode * pi)
11425 {
11426   asmop *aop = NULL;
11427   char *rname, *l;
11428   sym_link *retype, *letype;
11429   sym_link *ptype = operandType (result);
11430
11431   D (emitcode (";", "genNearPointerSet"));
11432
11433   retype = getSpec (operandType (right));
11434   letype = getSpec (ptype);
11435
11436   aopOp (result, ic, FALSE, FALSE);
11437
11438   /* if the result is rematerializable &
11439      in data space & not a bit variable */
11440   if (AOP_TYPE (result) == AOP_IMMD &&
11441       DCL_TYPE (ptype) == POINTER &&
11442       !IS_BITVAR (retype) &&
11443       !IS_BITVAR (letype))
11444     {
11445       genDataPointerSet (right, result, ic);
11446       return;
11447     }
11448
11449   /* if the value is already in a pointer register
11450      then don't need anything more */
11451   if (!AOP_INPREG (AOP (result)))
11452     {
11453       /* otherwise get a free pointer register */
11454       regs *preg;
11455
11456       aop = newAsmop (0);
11457       preg = getFreePtr (ic, &aop, FALSE);
11458       emitcode ("mov", "%s,%s",
11459                 preg->name,
11460                 aopGet (result, 0, FALSE, TRUE, NULL));
11461       rname = preg->name;
11462     }
11463   else
11464     {
11465       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11466     }
11467
11468   aopOp (right, ic, FALSE, FALSE);
11469
11470   /* if bitfield then unpack the bits */
11471   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11472     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11473   else
11474     {
11475       /* we can just get the values */
11476       int size = AOP_SIZE (right);
11477       int offset = 0;
11478
11479       while (size--)
11480         {
11481           l = aopGet (right, offset, FALSE, TRUE, NULL);
11482           if ((*l == '@') || (strcmp (l, "acc") == 0))
11483             {
11484               MOVA (l);
11485               emitcode ("mov", "@%s,a", rname);
11486             }
11487           else
11488             emitcode ("mov", "@%s,%s", rname, l);
11489           if (size || pi)
11490             emitcode ("inc", "%s", rname);
11491           offset++;
11492         }
11493     }
11494
11495   /* now some housekeeping stuff */
11496   if (aop)      /* we had to allocate for this iCode */
11497     {
11498       if (pi)
11499         aopPut (result, rname, 0);
11500       freeAsmop (NULL, aop, ic, TRUE);
11501     }
11502   else
11503     {
11504       /* we did not allocate which means left
11505          already in a pointer register, then
11506          if size > 0 && this could be used again
11507          we have to point it back to where it
11508          belongs */
11509       if (AOP_SIZE (right) > 1 &&
11510           !OP_SYMBOL (result)->remat &&
11511           (OP_SYMBOL (result)->liveTo > ic->seq ||
11512            ic->depth) &&
11513           !pi)
11514         {
11515           int size = AOP_SIZE (right) - 1;
11516           while (size--)
11517             emitcode ("dec", "%s", rname);
11518         }
11519     }
11520
11521   /* done */
11522   if (pi)
11523     pi->generated = 1;
11524   freeAsmop (right, NULL, ic, TRUE);
11525   freeAsmop (result, NULL, ic, TRUE);
11526 }
11527
11528 /*-----------------------------------------------------------------*/
11529 /* genPagedPointerSet - emitcode for Paged pointer put             */
11530 /*-----------------------------------------------------------------*/
11531 static void
11532 genPagedPointerSet (operand * right,
11533                     operand * result,
11534                     iCode * ic,
11535                     iCode * pi)
11536 {
11537   asmop *aop = NULL;
11538   char *rname, *l;
11539   sym_link *retype, *letype;
11540
11541   D (emitcode (";", "genPagedPointerSet"));
11542
11543   retype = getSpec (operandType (right));
11544   letype = getSpec (operandType (result));
11545
11546   aopOp (result, ic, FALSE, FALSE);
11547
11548   /* if the value is already in a pointer register
11549      then don't need anything more */
11550   if (!AOP_INPREG (AOP (result)))
11551     {
11552       /* otherwise get a free pointer register */
11553       regs *preg;
11554
11555       aop = newAsmop (0);
11556       preg = getFreePtr (ic, &aop, FALSE);
11557       emitcode ("mov", "%s,%s",
11558                 preg->name,
11559                 aopGet (result, 0, FALSE, TRUE, NULL));
11560       rname = preg->name;
11561     }
11562   else
11563     {
11564       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11565     }
11566
11567   aopOp (right, ic, FALSE, FALSE);
11568
11569   /* if bitfield then unpack the bits */
11570   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11571     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11572   else
11573     {
11574       /* we can just get the values */
11575       int size = AOP_SIZE (right);
11576       int offset = 0;
11577
11578       while (size--)
11579         {
11580           l = aopGet (right, offset, FALSE, TRUE, NULL);
11581           MOVA (l);
11582           emitcode ("movx", "@%s,a", rname);
11583           if (size || pi)
11584             emitcode ("inc", "%s", rname);
11585           offset++;
11586         }
11587     }
11588
11589   /* now some housekeeping stuff */
11590   if (aop)
11591     {
11592       if (pi)
11593         aopPut (result, rname, 0);
11594       /* we had to allocate for this iCode */
11595       freeAsmop (NULL, aop, ic, TRUE);
11596     }
11597   else
11598     {
11599       /* we did not allocate which means left
11600          already in a pointer register, then
11601          if size > 0 && this could be used again
11602          we have to point it back to where it
11603          belongs */
11604       if (AOP_SIZE (right) > 1 &&
11605           !OP_SYMBOL (result)->remat &&
11606           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
11607           !pi)
11608         {
11609           int size = AOP_SIZE (right) - 1;
11610           while (size--)
11611             emitcode ("dec", "%s", rname);
11612         }
11613     }
11614
11615   /* done */
11616   if (pi)
11617     pi->generated = 1;
11618   freeAsmop (right, NULL, ic, TRUE);
11619   freeAsmop (result, NULL, ic, TRUE);
11620 }
11621
11622 /*-----------------------------------------------------------------*/
11623 /* genFarPointerSet - set value from far space                     */
11624 /*-----------------------------------------------------------------*/
11625 static void
11626 genFarPointerSet (operand * right,
11627                   operand * result, iCode * ic, iCode *pi)
11628 {
11629   int size, offset, dopi=1;
11630   sym_link *retype = getSpec (operandType (right));
11631   sym_link *letype = getSpec (operandType (result));
11632
11633   aopOp (result, ic, FALSE, FALSE);
11634
11635   /* if the operand is already in dptr
11636      then we do nothing else we move the value to dptr */
11637   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11638     {
11639       /* if this is remateriazable */
11640       if (AOP_TYPE (result) == AOP_IMMD)
11641         emitcode ("mov", "dptr,%s",
11642                   aopGet (result, 0, TRUE, FALSE, NULL));
11643       else
11644         {
11645           /* we need to get it byte by byte */
11646           _startLazyDPSEvaluation ();
11647           if (AOP_TYPE (result) != AOP_DPTR)
11648             {
11649               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11650               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11651               if (options.model == MODEL_FLAT24)
11652                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11653             }
11654           else
11655             {
11656               /* We need to generate a load to DPTR indirect through DPTR. */
11657               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11658
11659               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11660               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11661               if (options.model == MODEL_FLAT24)
11662                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11663               emitcode ("pop", "dph");
11664               emitcode ("pop", "dpl");
11665               dopi=0;
11666             }
11667           _endLazyDPSEvaluation ();
11668         }
11669     }
11670   /* so dptr now contains the address */
11671   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11672
11673   /* if bit then unpack */
11674   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11675   {
11676       if (AOP_INDPTRn(result)) {
11677           genSetDPTR(AOP(result)->aopu.dptr);
11678       }
11679       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11680       if (AOP_INDPTRn(result)) {
11681           genSetDPTR(0);
11682       }
11683   } else {
11684       size = AOP_SIZE (right);
11685       offset = 0;
11686       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11687           while (size--) {
11688               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11689
11690               genSetDPTR(AOP(result)->aopu.dptr);
11691               emitcode ("movx", "@dptr,a");
11692               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11693                   emitcode ("inc", "dptr");
11694               genSetDPTR (0);
11695           }
11696       } else {
11697           _startLazyDPSEvaluation ();
11698           while (size--) {
11699               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11700
11701               if (AOP_INDPTRn(result)) {
11702                   genSetDPTR(AOP(result)->aopu.dptr);
11703               } else {
11704                   genSetDPTR (0);
11705               }
11706               _flushLazyDPS ();
11707
11708               emitcode ("movx", "@dptr,a");
11709               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11710                   emitcode ("inc", "dptr");
11711           }
11712           _endLazyDPSEvaluation ();
11713       }
11714   }
11715
11716   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11717       if (!AOP_INDPTRn(result)) {
11718           _startLazyDPSEvaluation ();
11719
11720           aopPut (result,"dpl",0);
11721           aopPut (result,"dph",1);
11722           if (options.model == MODEL_FLAT24)
11723               aopPut (result,"dpx",2);
11724
11725           _endLazyDPSEvaluation ();
11726       }
11727       pi->generated=1;
11728   } else if (IS_SYMOP (result) &&
11729              (OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11730              AOP_SIZE(right) > 1 &&
11731              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11732
11733       size = AOP_SIZE (right) - 1;
11734       if (AOP_INDPTRn(result)) {
11735           genSetDPTR(AOP(result)->aopu.dptr);
11736       }
11737       while (size--) emitcode ("lcall","__decdptr");
11738       if (AOP_INDPTRn(result)) {
11739           genSetDPTR(0);
11740       }
11741   }
11742   freeAsmop (result, NULL, ic, TRUE);
11743   freeAsmop (right, NULL, ic, TRUE);
11744 }
11745
11746 /*-----------------------------------------------------------------*/
11747 /* genGenPointerSet - set value from generic pointer space         */
11748 /*-----------------------------------------------------------------*/
11749 static void
11750 genGenPointerSet (operand * right,
11751                   operand * result, iCode * ic, iCode * pi)
11752 {
11753   int size, offset;
11754   bool pushedB;
11755   sym_link *retype = getSpec (operandType (right));
11756   sym_link *letype = getSpec (operandType (result));
11757
11758   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11759
11760   pushedB = pushB ();
11761   /* if the operand is already in dptr
11762      then we do nothing else we move the value to dptr */
11763   if (AOP_TYPE (result) != AOP_STR)
11764     {
11765       _startLazyDPSEvaluation ();
11766       /* if this is remateriazable */
11767       if (AOP_TYPE (result) == AOP_IMMD)
11768         {
11769           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11770           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11771           {
11772               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11773           }
11774           else
11775           {
11776               emitcode ("mov",
11777                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11778           }
11779         }
11780       else
11781         {                       /* we need to get it byte by byte */
11782           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11783           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11784           if (options.model == MODEL_FLAT24) {
11785             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11786             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11787           } else {
11788             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11789           }
11790         }
11791       _endLazyDPSEvaluation ();
11792     }
11793   /* so dptr + b now contains the address */
11794   aopOp (right, ic, FALSE, TRUE);
11795
11796   /* if bit then unpack */
11797   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11798     {
11799       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11800     }
11801   else
11802     {
11803       size = AOP_SIZE (right);
11804       offset = 0;
11805
11806       _startLazyDPSEvaluation ();
11807       while (size--)
11808         {
11809           if (size)
11810             {
11811               // Set two bytes at a time, passed in _AP & A.
11812               // dptr will be incremented ONCE by __gptrputWord.
11813               //
11814               // Note: any change here must be coordinated
11815               // with the implementation of __gptrputWord
11816               // in device/lib/_gptrput.c
11817               emitcode("mov", "_ap, %s",
11818                        aopGet (right, offset++, FALSE, FALSE, NULL));
11819               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11820
11821               genSetDPTR (0);
11822               _flushLazyDPS ();
11823               emitcode ("lcall", "__gptrputWord");
11824               size--;
11825             }
11826           else
11827             {
11828               // Only one byte to put.
11829               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11830
11831               genSetDPTR (0);
11832               _flushLazyDPS ();
11833               emitcode ("lcall", "__gptrput");
11834             }
11835
11836           if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11837             {
11838               emitcode ("inc", "dptr");
11839             }
11840         }
11841       _endLazyDPSEvaluation ();
11842     }
11843
11844   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11845       _startLazyDPSEvaluation ();
11846
11847       aopPut (result, "dpl",0);
11848       aopPut (result, "dph",1);
11849       if (options.model == MODEL_FLAT24) {
11850           aopPut (result, "dpx",2);
11851           aopPut (result, "b",3);
11852       } else {
11853           aopPut (result, "b",2);
11854       }
11855       _endLazyDPSEvaluation ();
11856
11857       pi->generated=1;
11858   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11859              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11860
11861       size = AOP_SIZE (right) - 1;
11862       while (size--) emitcode ("lcall","__decdptr");
11863   }
11864   popB (pushedB);
11865
11866   freeAsmop (result, NULL, ic, TRUE);
11867   freeAsmop (right, NULL, ic, TRUE);
11868 }
11869
11870 /*-----------------------------------------------------------------*/
11871 /* genPointerSet - stores the value into a pointer location        */
11872 /*-----------------------------------------------------------------*/
11873 static void
11874 genPointerSet (iCode * ic, iCode *pi)
11875 {
11876   operand *right, *result;
11877   sym_link *type, *etype;
11878   int p_type;
11879
11880   D (emitcode (";", "genPointerSet"));
11881
11882   right = IC_RIGHT (ic);
11883   result = IC_RESULT (ic);
11884
11885   /* depending on the type of pointer we need to
11886      move it to the correct pointer register */
11887   type = operandType (result);
11888   etype = getSpec (type);
11889   /* if left is of type of pointer then it is simple */
11890   if (IS_PTR (type) && !IS_FUNC (type->next))
11891     {
11892       p_type = DCL_TYPE (type);
11893     }
11894   else
11895     {
11896       /* we have to go by the storage class */
11897       p_type = PTR_TYPE (SPEC_OCLS (etype));
11898     }
11899
11900   /* special case when cast remat */
11901   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11902       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11903           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11904           type = operandType (result);
11905           p_type = DCL_TYPE (type);
11906   }
11907
11908   /* now that we have the pointer type we assign
11909      the pointer values */
11910   switch (p_type)
11911     {
11912
11913     case POINTER:
11914     case IPOINTER:
11915       genNearPointerSet (right, result, ic, pi);
11916       break;
11917
11918     case PPOINTER:
11919       genPagedPointerSet (right, result, ic, pi);
11920       break;
11921
11922     case FPOINTER:
11923       genFarPointerSet (right, result, ic, pi);
11924       break;
11925
11926     case GPOINTER:
11927       genGenPointerSet (right, result, ic, pi);
11928       break;
11929
11930     default:
11931       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11932               "genPointerSet: illegal pointer type");
11933     }
11934 }
11935
11936 /*-----------------------------------------------------------------*/
11937 /* genIfx - generate code for Ifx statement                        */
11938 /*-----------------------------------------------------------------*/
11939 static void
11940 genIfx (iCode * ic, iCode * popIc)
11941 {
11942   operand *cond = IC_COND (ic);
11943   int isbit = 0;
11944   char *dup = NULL;
11945
11946   D (emitcode (";", "genIfx"));
11947
11948   aopOp (cond, ic, FALSE, FALSE);
11949
11950   /* get the value into acc */
11951   if (AOP_TYPE (cond) != AOP_CRY)
11952     {
11953       toBoolean (cond);
11954     }
11955   else
11956     {
11957       isbit = 1;
11958       if (AOP(cond)->aopu.aop_dir)
11959         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11960     }
11961
11962   /* the result is now in the accumulator or a directly addressable bit */
11963   freeAsmop (cond, NULL, ic, TRUE);
11964
11965   /* if the condition is a bit variable */
11966   if (isbit && dup)
11967     genIfxJump (ic, dup, popIc);
11968   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11969     genIfxJump (ic, SPIL_LOC (cond)->rname, popIc);
11970   else if (isbit && !IS_ITEMP (cond))
11971     genIfxJump (ic, OP_SYMBOL (cond)->rname, popIc);
11972   else
11973     genIfxJump (ic, "a", popIc);
11974
11975   ic->generated = 1;
11976 }
11977
11978 /*-----------------------------------------------------------------*/
11979 /* genAddrOf - generates code for address of                       */
11980 /*-----------------------------------------------------------------*/
11981 static void
11982 genAddrOf (iCode * ic)
11983 {
11984   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11985   int size, offset;
11986   bool pushedA = FALSE;
11987
11988   D (emitcode (";", "genAddrOf"));
11989
11990   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11991
11992   /* if the operand is on the stack then we
11993      need to get the stack offset of this
11994      variable */
11995   if (sym->onStack)
11996     {
11997       /* if 10 bit stack */
11998       if (options.stack10bit) {
11999           char buff[10];
12000           int  offset;
12001
12002           tsprintf(buff, sizeof(buff),
12003                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
12004           /* if it has an offset then we need to compute it */
12005 /*        emitcode ("subb", "a,#!constbyte", */
12006 /*                  -((sym->stack < 0) ? */
12007 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
12008 /*                    ((short) sym->stack)) & 0xff); */
12009 /*        emitcode ("mov","b,a"); */
12010 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
12011 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
12012 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
12013           if (sym->stack) {
12014               emitcode ("mov", "a,_bpx");
12015               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
12016                                              ((char) (sym->stack - _G.nRegsSaved)) :
12017                                              ((char) sym->stack )) & 0xff);
12018               emitcode ("mov", "b,a");
12019               emitcode ("mov", "a,_bpx+1");
12020
12021               offset = (((sym->stack < 0) ?
12022                          ((short) (sym->stack - _G.nRegsSaved)) :
12023                          ((short) sym->stack )) >> 8) & 0xff;
12024
12025               emitcode ("addc","a,#!constbyte", offset);
12026
12027               if (aopPutUsesAcc (IC_RESULT (ic), "b", 0))
12028                 {
12029                   emitcode ("push", "acc");
12030                   pushedA = TRUE;
12031                 }
12032               aopPut (IC_RESULT (ic), "b", 0);
12033               if (pushedA)
12034                   emitcode ("pop", "acc");
12035               aopPut (IC_RESULT (ic), "a", 1);
12036               aopPut (IC_RESULT (ic), buff, 2);
12037           } else {
12038               /* we can just move _bp */
12039               aopPut (IC_RESULT (ic), "_bpx", 0);
12040               aopPut (IC_RESULT (ic), "_bpx+1", 1);
12041               aopPut (IC_RESULT (ic), buff, 2);
12042           }
12043       } else {
12044           /* if it has an offset then we need to compute it */
12045           if (sym->stack)
12046             {
12047               emitcode ("mov", "a,_bp");
12048               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
12049               aopPut (IC_RESULT (ic), "a", 0);
12050             }
12051           else
12052             {
12053               /* we can just move _bp */
12054               aopPut (IC_RESULT (ic), "_bp", 0);
12055             }
12056           /* fill the result with zero */
12057           size = AOP_SIZE (IC_RESULT (ic)) - 1;
12058
12059
12060           if (options.stack10bit && size < (FPTRSIZE - 1)) {
12061               fprintf (stderr,
12062                        "*** warning: pointer to stack var truncated.\n");
12063           }
12064
12065           offset = 1;
12066           while (size--)
12067             {
12068               aopPut (IC_RESULT (ic), zero, offset++);
12069             }
12070       }
12071       goto release;
12072     }
12073
12074   /* object not on stack then we need the name */
12075   size = getDataSize (IC_RESULT (ic));
12076   offset = 0;
12077
12078   while (size--)
12079     {
12080       char s[SDCC_NAME_MAX];
12081       if (offset)
12082         {
12083           switch (offset) {
12084           case 1:
12085               tsprintf(s, sizeof(s), "#!his",sym->rname);
12086               break;
12087           case 2:
12088               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
12089               break;
12090           case 3:
12091               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
12092               break;
12093           default: /* should not need this (just in case) */
12094               SNPRINTF (s, sizeof(s), "#(%s >> %d)", sym->rname, offset * 8);
12095           }
12096         }
12097       else
12098         {
12099           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
12100         }
12101       aopPut (IC_RESULT (ic), s, offset++);
12102     }
12103   if (opIsGptr (IC_RESULT (ic)))
12104     {
12105       char buffer[10];
12106       SNPRINTF (buffer, sizeof(buffer), "#0x%02x",
12107                 pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
12108       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
12109     }
12110
12111 release:
12112   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12113 }
12114
12115 #if 0 // obsolete, and buggy for != xdata
12116 /*-----------------------------------------------------------------*/
12117 /* genArrayInit - generates code for address of                    */
12118 /*-----------------------------------------------------------------*/
12119 static void
12120 genArrayInit (iCode * ic)
12121 {
12122     literalList *iLoop;
12123     int         ix, count;
12124     int         elementSize = 0, eIndex;
12125     unsigned    val, lastVal;
12126     sym_link    *type;
12127     operand     *left=IC_LEFT(ic);
12128
12129     D (emitcode (";", "genArrayInit"));
12130
12131     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
12132
12133     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
12134     {
12135         // Load immediate value into DPTR.
12136         emitcode("mov", "dptr, %s",
12137              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
12138     }
12139     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
12140     {
12141 #if 0
12142       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12143               "Unexpected operand to genArrayInit.\n");
12144       exit(1);
12145 #else
12146       // a regression because of SDCCcse.c:1.52
12147       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12148       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12149       if (options.model == MODEL_FLAT24)
12150         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12151 #endif
12152     }
12153
12154     type = operandType(IC_LEFT(ic));
12155
12156     if (type && type->next)
12157     {
12158         elementSize = getSize(type->next);
12159     }
12160     else
12161     {
12162         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12163                                 "can't determine element size in genArrayInit.\n");
12164         exit(1);
12165     }
12166
12167     iLoop = IC_ARRAYILIST(ic);
12168     lastVal = 0xffff;
12169
12170     while (iLoop)
12171     {
12172         bool firstpass = TRUE;
12173
12174         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12175                  iLoop->count, (int)iLoop->literalValue, elementSize);
12176
12177         ix = iLoop->count;
12178
12179         while (ix)
12180         {
12181             symbol *tlbl = NULL;
12182
12183             count = ix > 256 ? 256 : ix;
12184
12185             if (count > 1)
12186             {
12187                 tlbl = newiTempLabel (NULL);
12188                 if (firstpass || (count & 0xff))
12189                 {
12190                     emitcode("mov", "b, #!constbyte", count & 0xff);
12191                 }
12192
12193                 emitLabel (tlbl);
12194             }
12195
12196             firstpass = FALSE;
12197
12198             for (eIndex = 0; eIndex < elementSize; eIndex++)
12199             {
12200                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12201                 if (val != lastVal)
12202                 {
12203                     emitcode("mov", "a, #!constbyte", val);
12204                     lastVal = val;
12205                 }
12206
12207                 emitcode("movx", "@dptr, a");
12208                 emitcode("inc", "dptr");
12209             }
12210
12211             if (count > 1)
12212             {
12213                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12214             }
12215
12216             ix -= count;
12217         }
12218
12219         iLoop = iLoop->next;
12220     }
12221
12222     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12223 }
12224 #endif
12225
12226 /*-----------------------------------------------------------------*/
12227 /* genFarFarAssign - assignment when both are in far space         */
12228 /*-----------------------------------------------------------------*/
12229 static void
12230 genFarFarAssign (operand * result, operand * right, iCode * ic)
12231 {
12232   int size = AOP_SIZE (right);
12233   int offset = 0;
12234   symbol *rSym = NULL;
12235
12236   if (size == 1)
12237   {
12238       /* quick & easy case. */
12239       D (emitcode(";","genFarFarAssign (1 byte case)"));
12240       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12241       freeAsmop (right, NULL, ic, FALSE);
12242       /* now assign DPTR to result */
12243       _G.accInUse++;
12244       aopOp(result, ic, FALSE, FALSE);
12245       _G.accInUse--;
12246       aopPut (result, "a", 0);
12247       freeAsmop(result, NULL, ic, FALSE);
12248       return;
12249   }
12250
12251   /* See if we've got an underlying symbol to abuse. */
12252   if (IS_SYMOP(result) && OP_SYMBOL(result))
12253   {
12254       if (IS_TRUE_SYMOP(result))
12255       {
12256           rSym = OP_SYMBOL(result);
12257       }
12258       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12259       {
12260           rSym = OP_SYMBOL(result)->usl.spillLoc;
12261       }
12262   }
12263
12264   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12265   {
12266       /* We can use the '390 auto-toggle feature to good effect here. */
12267
12268       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12269       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12270       emitcode ("mov", "dptr,#%s", rSym->rname);
12271       /* DP2 = result, DP1 = right, DP1 is current. */
12272       while (size)
12273       {
12274           emitcode("movx", "a,@dptr");
12275           emitcode("movx", "@dptr,a");
12276           if (--size)
12277           {
12278                emitcode("inc", "dptr");
12279                emitcode("inc", "dptr");
12280           }
12281       }
12282       emitcode("mov", "dps,#0");
12283       freeAsmop (right, NULL, ic, FALSE);
12284 #if 0
12285 some alternative code for processors without auto-toggle
12286 no time to test now, so later well put in...kpb
12287         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12288         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12289         emitcode ("mov", "dptr,#%s", rSym->rname);
12290         /* DP2 = result, DP1 = right, DP1 is current. */
12291         while (size)
12292         {
12293           --size;
12294           emitcode("movx", "a,@dptr");
12295           if (size)
12296             emitcode("inc", "dptr");
12297           emitcode("inc", "dps");
12298           emitcode("movx", "@dptr,a");
12299           if (size)
12300             emitcode("inc", "dptr");
12301           emitcode("inc", "dps");
12302         }
12303         emitcode("mov", "dps,#0");
12304         freeAsmop (right, NULL, ic, FALSE);
12305 #endif
12306   }
12307   else
12308   {
12309       D (emitcode (";", "genFarFarAssign"));
12310       aopOp (result, ic, TRUE, TRUE);
12311
12312       _startLazyDPSEvaluation ();
12313
12314       while (size--)
12315         {
12316           aopPut (result,
12317                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12318           offset++;
12319         }
12320       _endLazyDPSEvaluation ();
12321       freeAsmop (result, NULL, ic, FALSE);
12322       freeAsmop (right, NULL, ic, FALSE);
12323   }
12324 }
12325
12326 /*-----------------------------------------------------------------*/
12327 /* genAssign - generate code for assignment                        */
12328 /*-----------------------------------------------------------------*/
12329 static void
12330 genAssign (iCode * ic)
12331 {
12332   operand *result, *right;
12333   int size, offset;
12334   unsigned long lit = 0L;
12335
12336   D (emitcode (";", "genAssign"));
12337
12338   result = IC_RESULT (ic);
12339   right = IC_RIGHT (ic);
12340
12341   /* if they are the same */
12342   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12343     return;
12344
12345   aopOp (right, ic, FALSE, FALSE);
12346
12347   emitcode (";", "genAssign: resultIsFar = %s",
12348             isOperandInFarSpace (result) ?
12349             "TRUE" : "FALSE");
12350
12351   /* special case both in far space */
12352   if ((AOP_TYPE (right) == AOP_DPTR ||
12353        AOP_TYPE (right) == AOP_DPTR2) &&
12354   /* IS_TRUE_SYMOP(result)       && */
12355       isOperandInFarSpace (result))
12356     {
12357       genFarFarAssign (result, right, ic);
12358       return;
12359     }
12360
12361   aopOp (result, ic, TRUE, FALSE);
12362
12363   /* if they are the same registers */
12364   if (sameRegs (AOP (right), AOP (result)))
12365     goto release;
12366
12367   /* if the result is a bit */
12368   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12369     {
12370       /* if the right size is a literal then
12371          we know what the value is */
12372       if (AOP_TYPE (right) == AOP_LIT)
12373         {
12374           if (((int) operandLitValue (right)))
12375             aopPut (result, one, 0);
12376           else
12377             aopPut (result, zero, 0);
12378           goto release;
12379         }
12380
12381       /* the right is also a bit variable */
12382       if (AOP_TYPE (right) == AOP_CRY)
12383         {
12384           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12385           aopPut (result, "c", 0);
12386           goto release;
12387         }
12388
12389       /* we need to or */
12390       toBoolean (right);
12391       aopPut (result, "a", 0);
12392       goto release;
12393     }
12394
12395   /* bit variables done */
12396   /* general case */
12397   size = getDataSize (result);
12398   offset = 0;
12399   if (AOP_TYPE (right) == AOP_LIT)
12400     lit = ulFromVal (AOP (right)->aopu.aop_lit);
12401
12402   if ((size > 1) &&
12403       (AOP_TYPE (result) != AOP_REG) &&
12404       (AOP_TYPE (right) == AOP_LIT) &&
12405       !IS_FLOAT (operandType (right)))
12406     {
12407       _startLazyDPSEvaluation ();
12408       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12409         {
12410           aopPut (result,
12411                   aopGet (right, offset, FALSE, FALSE, NULL),
12412                   offset);
12413           offset++;
12414           size--;
12415         }
12416       /* And now fill the rest with zeros. */
12417       if (size)
12418         {
12419           emitcode ("clr", "a");
12420         }
12421       while (size--)
12422         {
12423           aopPut (result, "a", offset++);
12424         }
12425       _endLazyDPSEvaluation ();
12426     }
12427   else
12428     {
12429       _startLazyDPSEvaluation ();
12430       while (size--)
12431         {
12432           aopPut (result,
12433                   aopGet (right, offset, FALSE, FALSE, NULL),
12434                   offset);
12435           offset++;
12436         }
12437       _endLazyDPSEvaluation ();
12438     }
12439   adjustArithmeticResult (ic);
12440
12441 release:
12442   freeAsmop (result, NULL, ic, TRUE);
12443   freeAsmop (right, NULL, ic, TRUE);
12444 }
12445
12446 /*-----------------------------------------------------------------*/
12447 /* genJumpTab - generates code for jump table                      */
12448 /*-----------------------------------------------------------------*/
12449 static void
12450 genJumpTab (iCode * ic)
12451 {
12452   symbol *jtab;
12453   char *l;
12454
12455   D (emitcode (";", "genJumpTab"));
12456
12457   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12458   /* get the condition into accumulator */
12459   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12460   MOVA (l);
12461   /* multiply by four! */
12462   emitcode ("add", "a,acc");
12463   emitcode ("add", "a,acc");
12464   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12465
12466   jtab = newiTempLabel (NULL);
12467   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12468   emitcode ("jmp", "@a+dptr");
12469   emitLabel (jtab);
12470   /* now generate the jump labels */
12471   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12472        jtab = setNextItem (IC_JTLABELS (ic)))
12473     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12474
12475 }
12476
12477 /*-----------------------------------------------------------------*/
12478 /* genCast - gen code for casting                                  */
12479 /*-----------------------------------------------------------------*/
12480 static void
12481 genCast (iCode * ic)
12482 {
12483   operand *result = IC_RESULT (ic);
12484   sym_link *ctype = operandType (IC_LEFT (ic));
12485   sym_link *rtype = operandType (IC_RIGHT (ic));
12486   operand *right = IC_RIGHT (ic);
12487   int size, offset;
12488
12489   D (emitcode (";", "genCast"));
12490
12491   /* if they are equivalent then do nothing */
12492   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12493     return;
12494
12495   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12496   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12497
12498   /* if the result is a bit (and not a bitfield) */
12499   if (IS_BIT (OP_SYMBOL (result)->type))
12500     {
12501       /* if the right size is a literal then
12502          we know what the value is */
12503       if (AOP_TYPE (right) == AOP_LIT)
12504         {
12505           if (((int) operandLitValue (right)))
12506             aopPut (result, one, 0);
12507           else
12508             aopPut (result, zero, 0);
12509
12510           goto release;
12511         }
12512
12513       /* the right is also a bit variable */
12514       if (AOP_TYPE (right) == AOP_CRY)
12515         {
12516           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12517           aopPut (result, "c", 0);
12518           goto release;
12519         }
12520
12521       /* we need to or */
12522       toBoolean (right);
12523       aopPut (result, "a", 0);
12524       goto release;
12525     }
12526
12527   /* if they are the same size : or less */
12528   if (AOP_SIZE (result) <= AOP_SIZE (right))
12529     {
12530
12531       /* if they are in the same place */
12532       if (sameRegs (AOP (right), AOP (result)))
12533         goto release;
12534
12535       /* if they in different places then copy */
12536       size = AOP_SIZE (result);
12537       offset = 0;
12538       _startLazyDPSEvaluation ();
12539       while (size--)
12540         {
12541           aopPut (result,
12542                   aopGet (right, offset, FALSE, FALSE, NULL),
12543                   offset);
12544           offset++;
12545         }
12546       _endLazyDPSEvaluation ();
12547       goto release;
12548     }
12549
12550   /* if the result is of type pointer */
12551   if (IS_PTR (ctype))
12552     {
12553
12554       int p_type;
12555       sym_link *type = operandType (right);
12556
12557       /* pointer to generic pointer */
12558       if (IS_GENPTR (ctype))
12559         {
12560           if (IS_PTR (type))
12561             {
12562               p_type = DCL_TYPE (type);
12563             }
12564           else
12565             {
12566 #if OLD_CAST_BEHAVIOR
12567               /* KV: we are converting a non-pointer type to
12568                * a generic pointer. This (ifdef'd out) code
12569                * says that the resulting generic pointer
12570                * should have the same class as the storage
12571                * location of the non-pointer variable.
12572                *
12573                * For example, converting an int (which happens
12574                * to be stored in DATA space) to a pointer results
12575                * in a DATA generic pointer; if the original int
12576                * in XDATA space, so will be the resulting pointer.
12577                *
12578                * I don't like that behavior, and thus this change:
12579                * all such conversions will be forced to XDATA and
12580                * throw a warning. If you want some non-XDATA
12581                * type, or you want to suppress the warning, you
12582                * must go through an intermediate cast, like so:
12583                *
12584                * char _generic *gp = (char _xdata *)(intVar);
12585                */
12586               sym_link *etype = getSpec (type);
12587
12588               /* we have to go by the storage class */
12589               if (SPEC_OCLS (etype) != generic)
12590                 {
12591                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12592                 }
12593               else
12594 #endif
12595                 {
12596                   /* Converting unknown class (i.e. register variable)
12597                    * to generic pointer. This is not good, but
12598                    * we'll make a guess (and throw a warning).
12599                    */
12600                   p_type = FPOINTER;
12601                   werror (W_INT_TO_GEN_PTR_CAST);
12602                 }
12603             }
12604
12605           /* the first two bytes are known */
12606           size = GPTRSIZE - 1;
12607           offset = 0;
12608           _startLazyDPSEvaluation ();
12609           while (size--)
12610             {
12611               aopPut (result,
12612                       aopGet (right, offset, FALSE, FALSE, NULL),
12613                       offset);
12614               offset++;
12615             }
12616           _endLazyDPSEvaluation ();
12617
12618           /* the last byte depending on type */
12619             {
12620                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12621                 char gpValStr[10];
12622
12623                 if (gpVal == -1)
12624                 {
12625                     // pointerTypeToGPByte will have bitched.
12626                     exit(1);
12627                 }
12628
12629                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12630                 aopPut (result, gpValStr, GPTRSIZE - 1);
12631             }
12632           goto release;
12633         }
12634
12635       /* just copy the pointers */
12636       size = AOP_SIZE (result);
12637       offset = 0;
12638       _startLazyDPSEvaluation ();
12639       while (size--)
12640         {
12641           aopPut (result,
12642                   aopGet (right, offset, FALSE, FALSE, NULL),
12643                   offset);
12644           offset++;
12645         }
12646       _endLazyDPSEvaluation ();
12647       goto release;
12648     }
12649
12650   /* so we now know that the size of destination is greater
12651      than the size of the source */
12652   /* we move to result for the size of source */
12653   size = AOP_SIZE (right);
12654   offset = 0;
12655   _startLazyDPSEvaluation ();
12656   while (size--)
12657     {
12658       aopPut (result,
12659               aopGet (right, offset, FALSE, FALSE, NULL),
12660               offset);
12661       offset++;
12662     }
12663   _endLazyDPSEvaluation ();
12664
12665   /* now depending on the sign of the source && destination */
12666   size = AOP_SIZE (result) - AOP_SIZE (right);
12667   /* if unsigned or not an integral type */
12668   /* also, if the source is a bit, we don't need to sign extend, because
12669    * it can't possibly have set the sign bit.
12670    */
12671   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12672     {
12673       while (size--)
12674         {
12675           aopPut (result, zero, offset++);
12676         }
12677     }
12678   else
12679     {
12680       /* we need to extend the sign :{ */
12681       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12682                         FALSE, FALSE, NULL));
12683       emitcode ("rlc", "a");
12684       emitcode ("subb", "a,acc");
12685       while (size--)
12686         aopPut (result, "a", offset++);
12687     }
12688
12689   /* we are done hurray !!!! */
12690
12691 release:
12692   freeAsmop (right, NULL, ic, TRUE);
12693   freeAsmop (result, NULL, ic, TRUE);
12694
12695 }
12696
12697 /*-----------------------------------------------------------------*/
12698 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12699 /*-----------------------------------------------------------------*/
12700 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12701 {
12702     operand *from , *to , *count;
12703     symbol *lbl;
12704     bitVect *rsave;
12705     int i;
12706
12707     /* we know it has to be 3 parameters */
12708     assert (nparms == 3);
12709
12710     rsave = newBitVect(16);
12711     /* save DPTR if it needs to be saved */
12712     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12713             if (bitVectBitValue(ic->rMask,i))
12714                     rsave = bitVectSetBit(rsave,i);
12715     }
12716     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12717                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12718     savermask(rsave);
12719
12720     to = parms[0];
12721     from = parms[1];
12722     count = parms[2];
12723
12724     aopOp (from, ic->next, FALSE, FALSE);
12725
12726     /* get from into DPTR1 */
12727     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12728     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12729     if (options.model == MODEL_FLAT24) {
12730         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12731     }
12732
12733     freeAsmop (from, NULL, ic, FALSE);
12734     aopOp (to, ic, FALSE, FALSE);
12735     /* get "to" into DPTR */
12736     /* if the operand is already in dptr
12737        then we do nothing else we move the value to dptr */
12738     if (AOP_TYPE (to) != AOP_STR) {
12739         /* if already in DPTR then we need to push */
12740         if (AOP_TYPE(to) == AOP_DPTR) {
12741             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12742             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12743             if (options.model == MODEL_FLAT24)
12744                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12745             emitcode ("pop", "dph");
12746             emitcode ("pop", "dpl");
12747         } else {
12748             _startLazyDPSEvaluation ();
12749             /* if this is remateriazable */
12750             if (AOP_TYPE (to) == AOP_IMMD) {
12751                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12752             } else {                    /* we need to get it byte by byte */
12753                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12754                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12755                 if (options.model == MODEL_FLAT24) {
12756                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12757                 }
12758             }
12759             _endLazyDPSEvaluation ();
12760         }
12761     }
12762     freeAsmop (to, NULL, ic, FALSE);
12763     _G.dptrInUse = _G.dptr1InUse = 1;
12764     aopOp (count, ic->next->next, FALSE,FALSE);
12765     lbl =newiTempLabel(NULL);
12766
12767     /* now for the actual copy */
12768     if (AOP_TYPE(count) == AOP_LIT &&
12769         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12770         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12771         if (fromc) {
12772             emitcode ("lcall","__bi_memcpyc2x_s");
12773         } else {
12774             emitcode ("lcall","__bi_memcpyx2x_s");
12775         }
12776         freeAsmop (count, NULL, ic, FALSE);
12777     } else {
12778         symbol *lbl1 = newiTempLabel(NULL);
12779
12780         emitcode (";"," Auto increment but no djnz");
12781         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12782         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12783         freeAsmop (count, NULL, ic, FALSE);
12784         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12785         emitLabel (lbl);
12786         if (fromc) {
12787             emitcode ("clr","a");
12788             emitcode ("movc", "a,@a+dptr");
12789         } else
12790             emitcode ("movx", "a,@dptr");
12791         emitcode ("movx", "@dptr,a");
12792         emitcode ("inc", "dptr");
12793         emitcode ("inc", "dptr");
12794         emitcode ("mov","a,b");
12795         emitcode ("orl","a,_ap");
12796         emitcode ("jz","!tlabel",lbl1->key+100);
12797         emitcode ("mov","a,_ap");
12798         emitcode ("add","a,#!constbyte",0xFF);
12799         emitcode ("mov","_ap,a");
12800         emitcode ("mov","a,b");
12801         emitcode ("addc","a,#!constbyte",0xFF);
12802         emitcode ("mov","b,a");
12803         emitcode ("sjmp","!tlabel",lbl->key+100);
12804         emitLabel (lbl1);
12805     }
12806     emitcode ("mov", "dps,#0");
12807     _G.dptrInUse = _G.dptr1InUse = 0;
12808     unsavermask(rsave);
12809
12810 }
12811
12812 /*-----------------------------------------------------------------*/
12813 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12814 /*-----------------------------------------------------------------*/
12815 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12816 {
12817     operand *from , *to , *count;
12818     symbol *lbl,*lbl2;
12819     bitVect *rsave;
12820     int i;
12821
12822     /* we know it has to be 3 parameters */
12823     assert (nparms == 3);
12824
12825     rsave = newBitVect(16);
12826     /* save DPTR if it needs to be saved */
12827     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12828             if (bitVectBitValue(ic->rMask,i))
12829                     rsave = bitVectSetBit(rsave,i);
12830     }
12831     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12832                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12833     savermask(rsave);
12834
12835     to = parms[0];
12836     from = parms[1];
12837     count = parms[2];
12838
12839     aopOp (from, ic->next, FALSE, FALSE);
12840
12841     /* get from into DPTR1 */
12842     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12843     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12844     if (options.model == MODEL_FLAT24) {
12845         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12846     }
12847
12848     freeAsmop (from, NULL, ic, FALSE);
12849     aopOp (to, ic, FALSE, FALSE);
12850     /* get "to" into DPTR */
12851     /* if the operand is already in dptr
12852        then we do nothing else we move the value to dptr */
12853     if (AOP_TYPE (to) != AOP_STR) {
12854         /* if already in DPTR then we need to push */
12855         if (AOP_TYPE(to) == AOP_DPTR) {
12856             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12857             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12858             if (options.model == MODEL_FLAT24)
12859                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12860             emitcode ("pop", "dph");
12861             emitcode ("pop", "dpl");
12862         } else {
12863             _startLazyDPSEvaluation ();
12864             /* if this is remateriazable */
12865             if (AOP_TYPE (to) == AOP_IMMD) {
12866                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12867             } else {                    /* we need to get it byte by byte */
12868                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12869                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12870                 if (options.model == MODEL_FLAT24) {
12871                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12872                 }
12873             }
12874             _endLazyDPSEvaluation ();
12875         }
12876     }
12877     freeAsmop (to, NULL, ic, FALSE);
12878     _G.dptrInUse = _G.dptr1InUse = 1;
12879     aopOp (count, ic->next->next, FALSE,FALSE);
12880     lbl =newiTempLabel(NULL);
12881     lbl2 =newiTempLabel(NULL);
12882
12883     /* now for the actual compare */
12884     if (AOP_TYPE(count) == AOP_LIT &&
12885         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12886         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12887         if (fromc)
12888             emitcode("lcall","__bi_memcmpc2x_s");
12889         else
12890             emitcode("lcall","__bi_memcmpx2x_s");
12891         freeAsmop (count, NULL, ic, FALSE);
12892         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12893         aopPut(IC_RESULT(ic),"a",0);
12894         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12895     } else {
12896         symbol *lbl1 = newiTempLabel(NULL);
12897
12898         emitcode("push","ar0");
12899         emitcode (";"," Auto increment but no djnz");
12900         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12901         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12902         freeAsmop (count, NULL, ic, FALSE);
12903         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12904         emitLabel (lbl);
12905         if (fromc) {
12906             emitcode ("clr","a");
12907             emitcode ("movc", "a,@a+dptr");
12908         } else
12909             emitcode ("movx", "a,@dptr");
12910         emitcode ("mov","r0,a");
12911         emitcode ("movx", "a,@dptr");
12912         emitcode ("clr","c");
12913         emitcode ("subb","a,r0");
12914         emitcode ("jnz","!tlabel",lbl2->key+100);
12915         emitcode ("inc", "dptr");
12916         emitcode ("inc", "dptr");
12917         emitcode ("mov","a,b");
12918         emitcode ("orl","a,_ap");
12919         emitcode ("jz","!tlabel",lbl1->key+100);
12920         emitcode ("mov","a,_ap");
12921         emitcode ("add","a,#!constbyte",0xFF);
12922         emitcode ("mov","_ap,a");
12923         emitcode ("mov","a,b");
12924         emitcode ("addc","a,#!constbyte",0xFF);
12925         emitcode ("mov","b,a");
12926         emitcode ("sjmp","!tlabel",lbl->key+100);
12927         emitLabel (lbl1);
12928         emitcode ("clr","a");
12929         emitLabel (lbl2);
12930         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12931         aopPut(IC_RESULT(ic),"a",0);
12932         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12933         emitcode("pop","ar0");
12934         emitcode ("mov", "dps,#0");
12935     }
12936     _G.dptrInUse = _G.dptr1InUse = 0;
12937     unsavermask(rsave);
12938
12939 }
12940
12941 /*-----------------------------------------------------------------*/
12942 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12943 /* port, first parameter output area second parameter pointer to   */
12944 /* port third parameter count                                      */
12945 /*-----------------------------------------------------------------*/
12946 static void genInp( iCode *ic, int nparms, operand **parms)
12947 {
12948     operand *from , *to , *count;
12949     symbol *lbl;
12950     bitVect *rsave;
12951     int i;
12952
12953     /* we know it has to be 3 parameters */
12954     assert (nparms == 3);
12955
12956     rsave = newBitVect(16);
12957     /* save DPTR if it needs to be saved */
12958     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12959             if (bitVectBitValue(ic->rMask,i))
12960                     rsave = bitVectSetBit(rsave,i);
12961     }
12962     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12963                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12964     savermask(rsave);
12965
12966     to = parms[0];
12967     from = parms[1];
12968     count = parms[2];
12969
12970     aopOp (from, ic->next, FALSE, FALSE);
12971
12972     /* get from into DPTR1 */
12973     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12974     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12975     if (options.model == MODEL_FLAT24) {
12976         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12977     }
12978
12979     freeAsmop (from, NULL, ic, FALSE);
12980     aopOp (to, ic, FALSE, FALSE);
12981     /* get "to" into DPTR */
12982     /* if the operand is already in dptr
12983        then we do nothing else we move the value to dptr */
12984     if (AOP_TYPE (to) != AOP_STR) {
12985         /* if already in DPTR then we need to push */
12986         if (AOP_TYPE(to) == AOP_DPTR) {
12987             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12988             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12989             if (options.model == MODEL_FLAT24)
12990                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12991             emitcode ("pop", "dph");
12992             emitcode ("pop", "dpl");
12993         } else {
12994             _startLazyDPSEvaluation ();
12995             /* if this is remateriazable */
12996             if (AOP_TYPE (to) == AOP_IMMD) {
12997                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12998             } else {                    /* we need to get it byte by byte */
12999                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13000                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13001                 if (options.model == MODEL_FLAT24) {
13002                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13003                 }
13004             }
13005             _endLazyDPSEvaluation ();
13006         }
13007     }
13008     freeAsmop (to, NULL, ic, FALSE);
13009
13010     _G.dptrInUse = _G.dptr1InUse = 1;
13011     aopOp (count, ic->next->next, FALSE,FALSE);
13012     lbl =newiTempLabel(NULL);
13013
13014     /* now for the actual copy */
13015     if (AOP_TYPE(count) == AOP_LIT &&
13016         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13017         emitcode (";","OH  JOY auto increment with djnz (very fast)");
13018         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
13019         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13020         freeAsmop (count, NULL, ic, FALSE);
13021         emitLabel (lbl);
13022         emitcode ("movx", "a,@dptr");   /* read data from port */
13023         emitcode ("dec","dps");         /* switch to DPTR */
13024         emitcode ("movx", "@dptr,a");   /* save into location */
13025         emitcode ("inc", "dptr");       /* point to next area */
13026         emitcode ("inc","dps");         /* switch to DPTR2 */
13027         emitcode ("djnz","b,!tlabel",lbl->key+100);
13028     } else {
13029         symbol *lbl1 = newiTempLabel(NULL);
13030
13031         emitcode (";"," Auto increment but no djnz");
13032         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13033         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13034         freeAsmop (count, NULL, ic, FALSE);
13035         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
13036         emitLabel (lbl);
13037         emitcode ("movx", "a,@dptr");
13038         emitcode ("dec","dps");         /* switch to DPTR */
13039         emitcode ("movx", "@dptr,a");
13040         emitcode ("inc", "dptr");
13041         emitcode ("inc","dps");         /* switch to DPTR2 */
13042 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
13043 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
13044         emitcode ("mov","a,b");
13045         emitcode ("orl","a,_ap");
13046         emitcode ("jz","!tlabel",lbl1->key+100);
13047         emitcode ("mov","a,_ap");
13048         emitcode ("add","a,#!constbyte",0xFF);
13049         emitcode ("mov","_ap,a");
13050         emitcode ("mov","a,b");
13051         emitcode ("addc","a,#!constbyte",0xFF);
13052         emitcode ("mov","b,a");
13053         emitcode ("sjmp","!tlabel",lbl->key+100);
13054         emitLabel (lbl1);
13055     }
13056     emitcode ("mov", "dps,#0");
13057     _G.dptrInUse = _G.dptr1InUse = 0;
13058     unsavermask(rsave);
13059
13060 }
13061
13062 /*-----------------------------------------------------------------*/
13063 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
13064 /* port, first parameter output area second parameter pointer to   */
13065 /* port third parameter count                                      */
13066 /*-----------------------------------------------------------------*/
13067 static void genOutp( iCode *ic, int nparms, operand **parms)
13068 {
13069     operand *from , *to , *count;
13070     symbol *lbl;
13071     bitVect *rsave;
13072     int i;
13073
13074     /* we know it has to be 3 parameters */
13075     assert (nparms == 3);
13076
13077     rsave = newBitVect(16);
13078     /* save DPTR if it needs to be saved */
13079     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13080             if (bitVectBitValue(ic->rMask,i))
13081                     rsave = bitVectSetBit(rsave,i);
13082     }
13083     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13084                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13085     savermask(rsave);
13086
13087     to = parms[0];
13088     from = parms[1];
13089     count = parms[2];
13090
13091     aopOp (from, ic->next, FALSE, FALSE);
13092
13093     /* get from into DPTR1 */
13094     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
13095     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
13096     if (options.model == MODEL_FLAT24) {
13097         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
13098     }
13099
13100     freeAsmop (from, NULL, ic, FALSE);
13101     aopOp (to, ic, FALSE, FALSE);
13102     /* get "to" into DPTR */
13103     /* if the operand is already in dptr
13104        then we do nothing else we move the value to dptr */
13105     if (AOP_TYPE (to) != AOP_STR) {
13106         /* if already in DPTR then we need to push */
13107         if (AOP_TYPE(to) == AOP_DPTR) {
13108             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13109             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13110             if (options.model == MODEL_FLAT24)
13111                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13112             emitcode ("pop", "dph");
13113             emitcode ("pop", "dpl");
13114         } else {
13115             _startLazyDPSEvaluation ();
13116             /* if this is remateriazable */
13117             if (AOP_TYPE (to) == AOP_IMMD) {
13118                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13119             } else {                    /* we need to get it byte by byte */
13120                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13121                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13122                 if (options.model == MODEL_FLAT24) {
13123                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13124                 }
13125             }
13126             _endLazyDPSEvaluation ();
13127         }
13128     }
13129     freeAsmop (to, NULL, ic, FALSE);
13130
13131     _G.dptrInUse = _G.dptr1InUse = 1;
13132     aopOp (count, ic->next->next, FALSE,FALSE);
13133     lbl =newiTempLabel(NULL);
13134
13135     /* now for the actual copy */
13136     if (AOP_TYPE(count) == AOP_LIT &&
13137         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13138         emitcode (";","OH  JOY auto increment with djnz (very fast)");
13139         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13140         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13141         emitLabel (lbl);
13142         emitcode ("movx", "a,@dptr");   /* read data from port */
13143         emitcode ("inc","dps");         /* switch to DPTR2 */
13144         emitcode ("movx", "@dptr,a");   /* save into location */
13145         emitcode ("inc", "dptr");       /* point to next area */
13146         emitcode ("dec","dps");         /* switch to DPTR */
13147         emitcode ("djnz","b,!tlabel",lbl->key+100);
13148         freeAsmop (count, NULL, ic, FALSE);
13149     } else {
13150         symbol *lbl1 = newiTempLabel(NULL);
13151
13152         emitcode (";"," Auto increment but no djnz");
13153         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13154         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13155         freeAsmop (count, NULL, ic, FALSE);
13156         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13157         emitLabel (lbl);
13158         emitcode ("movx", "a,@dptr");
13159         emitcode ("inc", "dptr");
13160         emitcode ("inc","dps");         /* switch to DPTR2 */
13161         emitcode ("movx", "@dptr,a");
13162         emitcode ("dec","dps");         /* switch to DPTR */
13163         emitcode ("mov","a,b");
13164         emitcode ("orl","a,_ap");
13165         emitcode ("jz","!tlabel",lbl1->key+100);
13166         emitcode ("mov","a,_ap");
13167         emitcode ("add","a,#!constbyte",0xFF);
13168         emitcode ("mov","_ap,a");
13169         emitcode ("mov","a,b");
13170         emitcode ("addc","a,#!constbyte",0xFF);
13171         emitcode ("mov","b,a");
13172         emitcode ("sjmp","!tlabel",lbl->key+100);
13173         emitLabel (lbl1);
13174     }
13175     emitcode ("mov", "dps,#0");
13176     _G.dptrInUse = _G.dptr1InUse = 0;
13177     unsavermask(rsave);
13178
13179 }
13180
13181 /*-----------------------------------------------------------------*/
13182 /* genSwapW - swap lower & high order bytes                        */
13183 /*-----------------------------------------------------------------*/
13184 static void genSwapW(iCode *ic, int nparms, operand **parms)
13185 {
13186     operand *dest;
13187     operand *src;
13188     assert (nparms==1);
13189
13190     src = parms[0];
13191     dest=IC_RESULT(ic);
13192
13193     assert(getSize(operandType(src))==2);
13194
13195     aopOp (src, ic, FALSE, FALSE);
13196     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13197     _G.accInUse++;
13198     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13199     _G.accInUse--;
13200     freeAsmop (src, NULL, ic, FALSE);
13201
13202     aopOp (dest,ic, FALSE, FALSE);
13203     aopPut(dest,"b",0);
13204     aopPut(dest,"a",1);
13205     freeAsmop (dest, NULL, ic, FALSE);
13206 }
13207
13208 /*-----------------------------------------------------------------*/
13209 /* genMemsetX - gencode for memSetX data                           */
13210 /*-----------------------------------------------------------------*/
13211 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13212 {
13213     operand *to , *val , *count;
13214     symbol *lbl;
13215     char *l;
13216     int i;
13217     bitVect *rsave;
13218
13219     /* we know it has to be 3 parameters */
13220     assert (nparms == 3);
13221
13222     to = parms[0];
13223     val = parms[1];
13224     count = parms[2];
13225
13226     /* save DPTR if it needs to be saved */
13227     rsave = newBitVect(16);
13228     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13229             if (bitVectBitValue(ic->rMask,i))
13230                     rsave = bitVectSetBit(rsave,i);
13231     }
13232     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13233                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13234     savermask(rsave);
13235
13236     aopOp (to, ic, FALSE, FALSE);
13237     /* get "to" into DPTR */
13238     /* if the operand is already in dptr
13239        then we do nothing else we move the value to dptr */
13240     if (AOP_TYPE (to) != AOP_STR) {
13241         /* if already in DPTR then we need to push */
13242         if (AOP_TYPE(to) == AOP_DPTR) {
13243             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13244             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13245             if (options.model == MODEL_FLAT24)
13246                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13247             emitcode ("pop", "dph");
13248             emitcode ("pop", "dpl");
13249         } else {
13250             _startLazyDPSEvaluation ();
13251             /* if this is remateriazable */
13252             if (AOP_TYPE (to) == AOP_IMMD) {
13253                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13254             } else {                    /* we need to get it byte by byte */
13255                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13256                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13257                 if (options.model == MODEL_FLAT24) {
13258                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13259                 }
13260             }
13261             _endLazyDPSEvaluation ();
13262         }
13263     }
13264     freeAsmop (to, NULL, ic, FALSE);
13265
13266     aopOp (val, ic->next->next, FALSE,FALSE);
13267     aopOp (count, ic->next->next, FALSE,FALSE);
13268     lbl =newiTempLabel(NULL);
13269     /* now for the actual copy */
13270     if (AOP_TYPE(count) == AOP_LIT &&
13271         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13272         l = aopGet(val, 0, FALSE, FALSE, NULL);
13273         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13274         MOVA(l);
13275         emitLabel (lbl);
13276         emitcode ("movx", "@dptr,a");
13277         emitcode ("inc", "dptr");
13278         emitcode ("djnz","b,!tlabel",lbl->key+100);
13279     } else {
13280         symbol *lbl1 = newiTempLabel(NULL);
13281
13282         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13283         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13284         emitLabel (lbl);
13285         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13286         emitcode ("movx", "@dptr,a");
13287         emitcode ("inc", "dptr");
13288         emitcode ("mov","a,b");
13289         emitcode ("orl","a,_ap");
13290         emitcode ("jz","!tlabel",lbl1->key+100);
13291         emitcode ("mov","a,_ap");
13292         emitcode ("add","a,#!constbyte",0xFF);
13293         emitcode ("mov","_ap,a");
13294         emitcode ("mov","a,b");
13295         emitcode ("addc","a,#!constbyte",0xFF);
13296         emitcode ("mov","b,a");
13297         emitcode ("sjmp","!tlabel",lbl->key+100);
13298         emitLabel (lbl1);
13299     }
13300     freeAsmop (count, NULL, ic, FALSE);
13301     unsavermask(rsave);
13302 }
13303
13304 /*-----------------------------------------------------------------*/
13305 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13306 /*-----------------------------------------------------------------*/
13307 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13308 {
13309         bitVect *rsave ;
13310         operand *pnum, *result;
13311         int i;
13312
13313         assert (nparms==1);
13314         /* save registers that need to be saved */
13315         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13316                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13317
13318         pnum = parms[0];
13319         aopOp (pnum, ic, FALSE, FALSE);
13320         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13321         freeAsmop (pnum, NULL, ic, FALSE);
13322         emitcode ("lcall","NatLib_LoadPrimitive");
13323         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13324         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13325             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13326                 for (i = (size-1) ; i >= 0 ; i-- ) {
13327                         emitcode ("push","a%s",javaRet[i]);
13328                 }
13329                 for (i=0; i < size ; i++ ) {
13330                         emitcode ("pop","a%s",
13331                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13332                 }
13333         } else {
13334                 for (i = 0 ; i < size ; i++ ) {
13335                         aopPut(result,javaRet[i],i);
13336                 }
13337         }
13338         freeAsmop (result, NULL, ic, FALSE);
13339         unsavermask(rsave);
13340 }
13341
13342 /*-----------------------------------------------------------------*/
13343 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13344 /*-----------------------------------------------------------------*/
13345 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13346 {
13347         bitVect *rsave ;
13348         operand *pnum, *result;
13349         int size = 3;
13350         int i;
13351
13352         assert (nparms==1);
13353         /* save registers that need to be saved */
13354         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13355                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13356
13357         pnum = parms[0];
13358         aopOp (pnum, ic, FALSE, FALSE);
13359         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13360         freeAsmop (pnum, NULL, ic, FALSE);
13361         emitcode ("lcall","NatLib_LoadPointer");
13362         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13363         if (AOP_TYPE(result)!=AOP_STR) {
13364                 for (i = 0 ; i < size ; i++ ) {
13365                         aopPut(result,fReturn[i],i);
13366                 }
13367         }
13368         freeAsmop (result, NULL, ic, FALSE);
13369         unsavermask(rsave);
13370 }
13371
13372 /*-----------------------------------------------------------------*/
13373 /* genNatLibInstallStateBlock -                                    */
13374 /*-----------------------------------------------------------------*/
13375 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13376                                        operand **parms, const char *name)
13377 {
13378         bitVect *rsave ;
13379         operand *psb, *handle;
13380         assert (nparms==2);
13381
13382         /* save registers that need to be saved */
13383         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13384                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13385         psb = parms[0];
13386         handle = parms[1];
13387
13388         /* put pointer to state block into DPTR1 */
13389         aopOp (psb, ic, FALSE, FALSE);
13390         if (AOP_TYPE (psb) == AOP_IMMD) {
13391                 emitcode ("mov","dps,#1");
13392                 emitcode ("mov", "dptr,%s",
13393                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13394                 emitcode ("mov","dps,#0");
13395         } else {
13396                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13397                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13398                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13399         }
13400         freeAsmop (psb, NULL, ic, FALSE);
13401
13402         /* put libraryID into DPTR */
13403         emitcode ("mov","dptr,#LibraryID");
13404
13405         /* put handle into r3:r2 */
13406         aopOp (handle, ic, FALSE, FALSE);
13407         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13408                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13409                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13410                 emitcode ("pop","ar3");
13411                 emitcode ("pop","ar2");
13412         } else {
13413                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13414                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13415         }
13416         freeAsmop (psb, NULL, ic, FALSE);
13417
13418         /* make the call */
13419         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13420
13421         /* put return value into place*/
13422         _G.accInUse++;
13423         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13424         _G.accInUse--;
13425         aopPut(IC_RESULT(ic),"a",0);
13426         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13427         unsavermask(rsave);
13428 }
13429
13430 /*-----------------------------------------------------------------*/
13431 /* genNatLibRemoveStateBlock -                                     */
13432 /*-----------------------------------------------------------------*/
13433 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13434 {
13435         bitVect *rsave ;
13436
13437         assert(nparms==0);
13438
13439         /* save registers that need to be saved */
13440         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13441                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13442
13443         /* put libraryID into DPTR */
13444         emitcode ("mov","dptr,#LibraryID");
13445         /* make the call */
13446         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13447         unsavermask(rsave);
13448 }
13449
13450 /*-----------------------------------------------------------------*/
13451 /* genNatLibGetStateBlock -                                        */
13452 /*-----------------------------------------------------------------*/
13453 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13454                                    operand **parms,const char *name)
13455 {
13456         bitVect *rsave ;
13457         symbol *lbl = newiTempLabel(NULL);
13458
13459         assert(nparms==0);
13460         /* save registers that need to be saved */
13461         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13462                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13463
13464         /* put libraryID into DPTR */
13465         emitcode ("mov","dptr,#LibraryID");
13466         /* make the call */
13467         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13468         emitcode ("jnz","!tlabel",lbl->key+100);
13469
13470         /* put return value into place */
13471         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13472         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13473                 emitcode ("push","ar3");
13474                 emitcode ("push","ar2");
13475                 emitcode ("pop","%s",
13476                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13477                 emitcode ("pop","%s",
13478                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13479         } else {
13480                 aopPut(IC_RESULT(ic),"r2",0);
13481                 aopPut(IC_RESULT(ic),"r3",1);
13482         }
13483         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13484         emitLabel (lbl);
13485         unsavermask(rsave);
13486 }
13487
13488 /*-----------------------------------------------------------------*/
13489 /* genMMMalloc -                                                   */
13490 /*-----------------------------------------------------------------*/
13491 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13492                          int size, const char *name)
13493 {
13494         bitVect *rsave ;
13495         operand *bsize;
13496         symbol *rsym;
13497         symbol *lbl = newiTempLabel(NULL);
13498
13499         assert (nparms == 1);
13500         /* save registers that need to be saved */
13501         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13502                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13503
13504         bsize=parms[0];
13505         aopOp (bsize,ic,FALSE,FALSE);
13506
13507         /* put the size in R4-R2 */
13508         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13509                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13510                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13511                 if (size==3) {
13512                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13513                         emitcode("pop","ar4");
13514                 }
13515                 emitcode("pop","ar3");
13516                 emitcode("pop","ar2");
13517         } else {
13518                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13519                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13520                 if (size==3) {
13521                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13522                 }
13523         }
13524         freeAsmop (bsize, NULL, ic, FALSE);
13525
13526         /* make the call */
13527         emitcode ("lcall","MM_%s",name);
13528         emitcode ("jz","!tlabel",lbl->key+100);
13529         emitcode ("mov","r2,#!constbyte",0xff);
13530         emitcode ("mov","r3,#!constbyte",0xff);
13531         emitLabel (lbl);
13532         /* we don't care about the pointer : we just save the handle */
13533         rsym = OP_SYMBOL(IC_RESULT(ic));
13534         if (rsym->liveFrom != rsym->liveTo) {
13535                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13536                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13537                         emitcode ("push","ar3");
13538                         emitcode ("push","ar2");
13539                         emitcode ("pop","%s",
13540                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13541                         emitcode ("pop","%s",
13542                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13543                 } else {
13544                         aopPut(IC_RESULT(ic),"r2",0);
13545                         aopPut(IC_RESULT(ic),"r3",1);
13546                 }
13547                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13548         }
13549         unsavermask(rsave);
13550 }
13551
13552 /*-----------------------------------------------------------------*/
13553 /* genMMDeref -                                                    */
13554 /*-----------------------------------------------------------------*/
13555 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13556 {
13557         bitVect *rsave ;
13558         operand *handle;
13559
13560         assert (nparms == 1);
13561         /* save registers that need to be saved */
13562         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13563                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13564
13565         handle=parms[0];
13566         aopOp (handle,ic,FALSE,FALSE);
13567
13568         /* put the size in R4-R2 */
13569         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13570                 emitcode("push","%s",
13571                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13572                 emitcode("push","%s",
13573                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13574                 emitcode("pop","ar3");
13575                 emitcode("pop","ar2");
13576         } else {
13577                 emitcode ("mov","r2,%s",
13578                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13579                 emitcode ("mov","r3,%s",
13580                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13581         }
13582         freeAsmop (handle, NULL, ic, FALSE);
13583
13584         /* make the call */
13585         emitcode ("lcall","MM_Deref");
13586
13587         {
13588                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13589                 if (rsym->liveFrom != rsym->liveTo) {
13590                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13591                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13592                             _startLazyDPSEvaluation ();
13593
13594                             aopPut(IC_RESULT(ic),"dpl",0);
13595                             aopPut(IC_RESULT(ic),"dph",1);
13596                             aopPut(IC_RESULT(ic),"dpx",2);
13597
13598                             _endLazyDPSEvaluation ();
13599
13600                         }
13601                 }
13602         }
13603         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13604         unsavermask(rsave);
13605 }
13606
13607 /*-----------------------------------------------------------------*/
13608 /* genMMUnrestrictedPersist -                                      */
13609 /*-----------------------------------------------------------------*/
13610 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13611 {
13612         bitVect *rsave ;
13613         operand *handle;
13614
13615         assert (nparms == 1);
13616         /* save registers that need to be saved */
13617         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13618                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13619
13620         handle=parms[0];
13621         aopOp (handle,ic,FALSE,FALSE);
13622
13623         /* put the size in R3-R2 */
13624         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13625                 emitcode("push","%s",
13626                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13627                 emitcode("push","%s",
13628                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13629                 emitcode("pop","ar3");
13630                 emitcode("pop","ar2");
13631         } else {
13632                 emitcode ("mov","r2,%s",
13633                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13634                 emitcode ("mov","r3,%s",
13635                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13636         }
13637         freeAsmop (handle, NULL, ic, FALSE);
13638
13639         /* make the call */
13640         emitcode ("lcall","MM_UnrestrictedPersist");
13641
13642         {
13643                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13644                 if (rsym->liveFrom != rsym->liveTo) {
13645                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13646                         aopPut(IC_RESULT(ic),"a",0);
13647                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13648                 }
13649         }
13650         unsavermask(rsave);
13651 }
13652
13653 /*-----------------------------------------------------------------*/
13654 /* genSystemExecJavaProcess -                                      */
13655 /*-----------------------------------------------------------------*/
13656 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13657 {
13658         bitVect *rsave ;
13659         operand *handle, *pp;
13660
13661         assert (nparms==2);
13662         /* save registers that need to be saved */
13663         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13664                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13665
13666         pp = parms[0];
13667         handle = parms[1];
13668
13669         /* put the handle in R3-R2 */
13670         aopOp (handle,ic,FALSE,FALSE);
13671         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13672                 emitcode("push","%s",
13673                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13674                 emitcode("push","%s",
13675                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13676                 emitcode("pop","ar3");
13677                 emitcode("pop","ar2");
13678         } else {
13679                 emitcode ("mov","r2,%s",
13680                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13681                 emitcode ("mov","r3,%s",
13682                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13683         }
13684         freeAsmop (handle, NULL, ic, FALSE);
13685
13686         /* put pointer in DPTR */
13687         aopOp (pp,ic,FALSE,FALSE);
13688         if (AOP_TYPE(pp) == AOP_IMMD) {
13689                 emitcode ("mov", "dptr,%s",
13690                           aopGet (pp, 0, TRUE, FALSE, NULL));
13691         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13692                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13693                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13694                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13695         }
13696         freeAsmop (handle, NULL, ic, FALSE);
13697
13698         /* make the call */
13699         emitcode ("lcall","System_ExecJavaProcess");
13700
13701         /* put result in place */
13702         {
13703                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13704                 if (rsym->liveFrom != rsym->liveTo) {
13705                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13706                         aopPut(IC_RESULT(ic),"a",0);
13707                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13708                 }
13709         }
13710
13711         unsavermask(rsave);
13712 }
13713
13714 /*-----------------------------------------------------------------*/
13715 /* genSystemRTCRegisters -                                         */
13716 /*-----------------------------------------------------------------*/
13717 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13718                                   char *name)
13719 {
13720         bitVect *rsave ;
13721         operand *pp;
13722
13723         assert (nparms==1);
13724         /* save registers that need to be saved */
13725         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13726                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13727
13728         pp=parms[0];
13729         /* put pointer in DPTR */
13730         aopOp (pp,ic,FALSE,FALSE);
13731         if (AOP_TYPE (pp) == AOP_IMMD) {
13732                 emitcode ("mov","dps,#1");
13733                 emitcode ("mov", "dptr,%s",
13734                           aopGet (pp, 0, TRUE, FALSE, NULL));
13735                 emitcode ("mov","dps,#0");
13736         } else {
13737                 emitcode ("mov","dpl1,%s",
13738                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13739                 emitcode ("mov","dph1,%s",
13740                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13741                 emitcode ("mov","dpx1,%s",
13742                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13743         }
13744         freeAsmop (pp, NULL, ic, FALSE);
13745
13746         /* make the call */
13747         emitcode ("lcall","System_%sRTCRegisters",name);
13748
13749         unsavermask(rsave);
13750 }
13751
13752 /*-----------------------------------------------------------------*/
13753 /* genSystemThreadSleep -                                          */
13754 /*-----------------------------------------------------------------*/
13755 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13756 {
13757         bitVect *rsave ;
13758         operand *to, *s;
13759
13760         assert (nparms==1);
13761         /* save registers that need to be saved */
13762         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13763                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13764
13765         to = parms[0];
13766         aopOp(to,ic,FALSE,FALSE);
13767         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13768             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13769                 emitcode ("push","%s",
13770                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13771                 emitcode ("push","%s",
13772                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13773                 emitcode ("push","%s",
13774                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13775                 emitcode ("push","%s",
13776                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13777                 emitcode ("pop","ar3");
13778                 emitcode ("pop","ar2");
13779                 emitcode ("pop","ar1");
13780                 emitcode ("pop","ar0");
13781         } else {
13782                 emitcode ("mov","r0,%s",
13783                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13784                 emitcode ("mov","r1,%s",
13785                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13786                 emitcode ("mov","r2,%s",
13787                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13788                 emitcode ("mov","r3,%s",
13789                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13790         }
13791         freeAsmop (to, NULL, ic, FALSE);
13792
13793         /* suspend in acc */
13794         s = parms[1];
13795         aopOp(s,ic,FALSE,FALSE);
13796         emitcode ("mov","a,%s",
13797                   aopGet(s,0,FALSE,TRUE,NULL));
13798         freeAsmop (s, NULL, ic, FALSE);
13799
13800         /* make the call */
13801         emitcode ("lcall","System_%s",name);
13802
13803         unsavermask(rsave);
13804 }
13805
13806 /*-----------------------------------------------------------------*/
13807 /* genSystemThreadResume -                                         */
13808 /*-----------------------------------------------------------------*/
13809 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13810 {
13811         bitVect *rsave ;
13812         operand *tid,*pid;
13813
13814         assert (nparms==2);
13815         /* save registers that need to be saved */
13816         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13817                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13818
13819         tid = parms[0];
13820         pid = parms[1];
13821
13822         /* PID in R0 */
13823         aopOp(pid,ic,FALSE,FALSE);
13824         emitcode ("mov","r0,%s",
13825                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13826         freeAsmop (pid, NULL, ic, FALSE);
13827
13828         /* tid into ACC */
13829         aopOp(tid,ic,FALSE,FALSE);
13830         emitcode ("mov","a,%s",
13831                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13832         freeAsmop (tid, NULL, ic, FALSE);
13833
13834         emitcode ("lcall","System_ThreadResume");
13835
13836         /* put result into place */
13837         {
13838                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13839                 if (rsym->liveFrom != rsym->liveTo) {
13840                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13841                         aopPut(IC_RESULT(ic),"a",0);
13842                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13843                 }
13844         }
13845         unsavermask(rsave);
13846 }
13847
13848 /*-----------------------------------------------------------------*/
13849 /* genSystemProcessResume -                                        */
13850 /*-----------------------------------------------------------------*/
13851 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13852 {
13853         bitVect *rsave ;
13854         operand *pid;
13855
13856         assert (nparms==1);
13857         /* save registers that need to be saved */
13858         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13859                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13860
13861         pid = parms[0];
13862
13863         /* pid into ACC */
13864         aopOp(pid,ic,FALSE,FALSE);
13865         emitcode ("mov","a,%s",
13866                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13867         freeAsmop (pid, NULL, ic, FALSE);
13868
13869         emitcode ("lcall","System_ProcessResume");
13870
13871         unsavermask(rsave);
13872 }
13873
13874 /*-----------------------------------------------------------------*/
13875 /* genSystem -                                                     */
13876 /*-----------------------------------------------------------------*/
13877 static void genSystem (iCode *ic,int nparms,char *name)
13878 {
13879         assert(nparms == 0);
13880
13881         emitcode ("lcall","System_%s",name);
13882 }
13883
13884 /*-----------------------------------------------------------------*/
13885 /* genSystemPoll -                                                  */
13886 /*-----------------------------------------------------------------*/
13887 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13888 {
13889         bitVect *rsave ;
13890         operand *fp;
13891
13892         assert (nparms==1);
13893         /* save registers that need to be saved */
13894         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13895                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13896
13897         fp = parms[0];
13898         aopOp (fp,ic,FALSE,FALSE);
13899         if (AOP_TYPE (fp) == AOP_IMMD) {
13900                 emitcode ("mov", "dptr,%s",
13901                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13902         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13903                 emitcode ("mov","dpl,%s",
13904                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13905                 emitcode ("mov","dph,%s",
13906                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13907                 emitcode ("mov","dpx,%s",
13908                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13909         }
13910         freeAsmop (fp, NULL, ic, FALSE);
13911
13912         emitcode ("lcall","System_%sPoll",name);
13913
13914         /* put result into place */
13915         {
13916                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13917                 if (rsym->liveFrom != rsym->liveTo) {
13918                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13919                         aopPut(IC_RESULT(ic),"a",0);
13920                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13921                 }
13922         }
13923         unsavermask(rsave);
13924 }
13925
13926 /*-----------------------------------------------------------------*/
13927 /* genSystemGetCurrentID -                                         */
13928 /*-----------------------------------------------------------------*/
13929 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13930 {
13931         assert (nparms==0);
13932
13933         emitcode ("lcall","System_GetCurrent%sId",name);
13934         /* put result into place */
13935         {
13936                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13937                 if (rsym->liveFrom != rsym->liveTo) {
13938                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13939                         aopPut(IC_RESULT(ic),"a",0);
13940                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13941                 }
13942         }
13943 }
13944
13945 /*-----------------------------------------------------------------*/
13946 /* genDjnz - generate decrement & jump if not zero instrucion      */
13947 /*-----------------------------------------------------------------*/
13948 static int
13949 genDjnz (iCode * ic, iCode * ifx)
13950 {
13951   symbol *lbl, *lbl1;
13952   if (!ifx)
13953     return 0;
13954
13955   /* if the if condition has a false label
13956      then we cannot save */
13957   if (IC_FALSE (ifx))
13958     return 0;
13959
13960   /* if the minus is not of the form a = a - 1 */
13961   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13962       !IS_OP_LITERAL (IC_RIGHT (ic)))
13963     return 0;
13964
13965   if (operandLitValue (IC_RIGHT (ic)) != 1)
13966     return 0;
13967
13968   /* if the size of this greater than one then no
13969      saving */
13970   if (getSize (operandType (IC_RESULT (ic))) > 1)
13971     return 0;
13972
13973   /* otherwise we can save BIG */
13974
13975   D (emitcode (";", "genDjnz"));
13976
13977   lbl = newiTempLabel (NULL);
13978   lbl1 = newiTempLabel (NULL);
13979
13980   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13981
13982   if (AOP_NEEDSACC(IC_RESULT(ic)))
13983   {
13984       /* If the result is accessed indirectly via
13985        * the accumulator, we must explicitly write
13986        * it back after the decrement.
13987        */
13988       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13989
13990       if (strcmp(rByte, "a"))
13991       {
13992            /* Something is hopelessly wrong */
13993            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13994                    __FILE__, __LINE__);
13995            /* We can just give up; the generated code will be inefficient,
13996             * but what the hey.
13997             */
13998            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13999            return 0;
14000       }
14001       emitcode ("dec", "%s", rByte);
14002       aopPut (IC_RESULT (ic), rByte, 0);
14003       emitcode ("jnz", "!tlabel", lbl->key + 100);
14004   }
14005   else if (IS_AOP_PREG (IC_RESULT (ic)))
14006     {
14007       emitcode ("dec", "%s",
14008                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
14009       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
14010       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14011       ifx->generated = 1;
14012       emitcode ("jnz", "!tlabel", lbl->key + 100);
14013     }
14014   else
14015     {
14016       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
14017                 lbl->key + 100);
14018     }
14019   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
14020   emitLabel (lbl);
14021   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
14022   emitLabel (lbl1);
14023
14024   if (!ifx->generated)
14025       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14026   ifx->generated = 1;
14027   return 1;
14028 }
14029
14030 /*-----------------------------------------------------------------*/
14031 /* genReceive - generate code for a receive iCode                  */
14032 /*-----------------------------------------------------------------*/
14033 static void
14034 genReceive (iCode * ic)
14035 {
14036   int size = getSize (operandType (IC_RESULT (ic)));
14037   int offset = 0;
14038   int rb1off ;
14039
14040   D (emitcode (";", "genReceive"));
14041
14042   if (ic->argreg == 1)
14043     {
14044       /* first parameter */
14045       if (AOP_IS_STR(IC_RESULT(ic)))
14046         {
14047           /* Nothing to do: it's already in the proper place. */
14048           return;
14049         }
14050       else
14051         {
14052           bool useDp2;
14053
14054           useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
14055                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
14056                  IS_TRUE_SYMOP (IC_RESULT (ic)));
14057
14058           _G.accInUse++;
14059           aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
14060           _G.accInUse--;
14061
14062           /* Sanity checking... */
14063           if (AOP_USESDPTR(IC_RESULT(ic)))
14064             {
14065               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14066                       "genReceive got unexpected DPTR.");
14067             }
14068           assignResultValue (IC_RESULT (ic), NULL);
14069         }
14070     }
14071   else if (ic->argreg > 12)
14072     { /* bit parameters */
14073       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
14074         {
14075           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
14076           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
14077           outBitC(IC_RESULT (ic));
14078         }
14079     }
14080   else
14081     {
14082       /* second receive onwards */
14083       /* this gets a little tricky since unused receives will be
14084        eliminated, we have saved the reg in the type field . and
14085        we use that to figure out which register to use */
14086       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
14087       rb1off = ic->argreg;
14088       while (size--)
14089         {
14090           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
14091         }
14092     }
14093   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14094 }
14095
14096 /*-----------------------------------------------------------------*/
14097 /* genDummyRead - generate code for dummy read of volatiles        */
14098 /*-----------------------------------------------------------------*/
14099 static void
14100 genDummyRead (iCode * ic)
14101 {
14102   operand *op;
14103   int size, offset;
14104
14105   D (emitcode(";", "genDummyRead"));
14106
14107   op = IC_RIGHT (ic);
14108   if (op && IS_SYMOP (op))
14109     {
14110       aopOp (op, ic, FALSE, FALSE);
14111
14112       /* if the result is a bit */
14113       if (AOP_TYPE (op) == AOP_CRY)
14114         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14115       else
14116         {
14117           /* bit variables done */
14118           /* general case */
14119           size = AOP_SIZE (op);
14120           offset = 0;
14121           while (size--)
14122           {
14123             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14124             offset++;
14125           }
14126         }
14127
14128       freeAsmop (op, NULL, ic, TRUE);
14129     }
14130
14131   op = IC_LEFT (ic);
14132   if (op && IS_SYMOP (op))
14133     {
14134       aopOp (op, ic, FALSE, FALSE);
14135
14136       /* if the result is a bit */
14137       if (AOP_TYPE (op) == AOP_CRY)
14138         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14139       else
14140         {
14141           /* bit variables done */
14142           /* general case */
14143           size = AOP_SIZE (op);
14144           offset = 0;
14145           while (size--)
14146           {
14147             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14148             offset++;
14149           }
14150         }
14151
14152       freeAsmop (op, NULL, ic, TRUE);
14153     }
14154 }
14155
14156 /*-----------------------------------------------------------------*/
14157 /* genCritical - generate code for start of a critical sequence    */
14158 /*-----------------------------------------------------------------*/
14159 static void
14160 genCritical (iCode *ic)
14161 {
14162   symbol *tlbl = newiTempLabel (NULL);
14163
14164   D (emitcode(";", "genCritical"));
14165
14166   if (IC_RESULT (ic))
14167     {
14168       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14169       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14170       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14171       aopPut (IC_RESULT (ic), zero, 0);
14172       emitLabel (tlbl);
14173       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14174     }
14175   else
14176     {
14177       emitcode ("setb", "c");
14178       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14179       emitcode ("clr", "c");
14180       emitLabel (tlbl);
14181       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14182     }
14183 }
14184
14185 /*-----------------------------------------------------------------*/
14186 /* genEndCritical - generate code for end of a critical sequence   */
14187 /*-----------------------------------------------------------------*/
14188 static void
14189 genEndCritical (iCode *ic)
14190 {
14191   D(emitcode(";", "genEndCritical"));
14192
14193   if (IC_RIGHT (ic))
14194     {
14195       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14196       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14197         {
14198           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14199           emitcode ("mov", "ea,c");
14200         }
14201       else
14202         {
14203           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14204           emitcode ("rrc", "a");
14205           emitcode ("mov", "ea,c");
14206         }
14207       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14208     }
14209   else
14210     {
14211       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14212       emitcode ("mov", "ea,c");
14213     }
14214 }
14215
14216
14217
14218 /*-----------------------------------------------------------------*/
14219 /* genBuiltIn - calls the appropriate function to  generating code */
14220 /* for a built in function                                         */
14221 /*-----------------------------------------------------------------*/
14222 static void genBuiltIn (iCode *ic)
14223 {
14224         operand *bi_parms[MAX_BUILTIN_ARGS];
14225         int nbi_parms;
14226         iCode *bi_iCode;
14227         symbol *bif;
14228
14229         /* get all the arguments for a built in function */
14230         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14231
14232         /* which function is it */
14233         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14234         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14235                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14236         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14237                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14238         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14239                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14240         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14241                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14242         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14243                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14244         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14245                 genInp(bi_iCode,nbi_parms,bi_parms);
14246         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14247                 genOutp(bi_iCode,nbi_parms,bi_parms);
14248         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14249                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14250                 /* JavaNative builtIns */
14251         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14252                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14253         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14254                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14255         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14256                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14257         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14258                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14259         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14260                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14261         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14262                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14263         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14264                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14265         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14266                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14267         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14268                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14269         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14270                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14271         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14272                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14273         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14274                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14275         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14276                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14277         } else if (strcmp(bif->name,"MM_Free")==0) {
14278                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14279         } else if (strcmp(bif->name,"MM_Deref")==0) {
14280                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14281         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14282                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14283         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14284                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14285         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14286                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14287         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14288                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14289         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14290                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14291         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14292                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14293         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14294                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14295         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14296                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14297         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14298                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14299         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14300                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14301         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14302                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14303         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14304                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14305         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14306                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14307         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14308                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14309         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14310                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14311         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14312                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14313         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14314                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14315         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14316                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14317         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14318                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14319         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14320                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14321         } else {
14322                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14323                 return ;
14324         }
14325         return ;
14326 }
14327
14328 /*-----------------------------------------------------------------*/
14329 /* gen390Code - generate code for Dallas 390 based controllers     */
14330 /*-----------------------------------------------------------------*/
14331 void
14332 gen390Code (iCode * lic)
14333 {
14334   iCode *ic;
14335   int cln = 0;
14336
14337   _G.currentFunc = NULL;
14338   lineHead = lineCurr = NULL;
14339   dptrn[1][0] = "dpl1";
14340   dptrn[1][1] = "dph1";
14341   dptrn[1][2] = "dpx1";
14342
14343   if (options.model == MODEL_FLAT24) {
14344     fReturnSizeDS390 = 5;
14345     fReturn = fReturn24;
14346   } else {
14347     fReturnSizeDS390 = 4;
14348     fReturn = fReturn16;
14349     options.stack10bit=0;
14350   }
14351 #if 1
14352   /* print the allocation information */
14353   if (allocInfo && currFunc)
14354     printAllocInfo (currFunc, codeOutBuf);
14355 #endif
14356   /* if debug information required */
14357   if (options.debug && currFunc)
14358     {
14359       debugFile->writeFunction (currFunc, lic);
14360     }
14361   /* stack pointer name */
14362   if (options.useXstack)
14363     spname = "_spx";
14364   else
14365     spname = "sp";
14366
14367
14368   for (ic = lic; ic; ic = ic->next)
14369     {
14370       _G.current_iCode = ic;
14371
14372       if (ic->lineno && cln != ic->lineno)
14373         {
14374           if (options.debug)
14375             {
14376               debugFile->writeCLine (ic);
14377             }
14378           if (!options.noCcodeInAsm) {
14379             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14380                       printCLine(ic->filename, ic->lineno));
14381           }
14382           cln = ic->lineno;
14383         }
14384       if (options.iCodeInAsm) {
14385         const char *iLine = printILine(ic);
14386         emitcode(";", "ic:%d: %s", ic->key, iLine);
14387         dbuf_free(iLine);
14388       }
14389       /* if the result is marked as
14390          spilt and rematerializable or code for
14391          this has already been generated then
14392          do nothing */
14393       if (resultRemat (ic) || ic->generated)
14394         continue;
14395
14396       /* depending on the operation */
14397       switch (ic->op)
14398         {
14399         case '!':
14400           genNot (ic);
14401           break;
14402
14403         case '~':
14404           genCpl (ic);
14405           break;
14406
14407         case UNARYMINUS:
14408           genUminus (ic);
14409           break;
14410
14411         case IPUSH:
14412           genIpush (ic);
14413           break;
14414
14415         case IPOP:
14416           {
14417             iCode *ifxIc, *popIc;
14418             bool CommonRegs = FALSE;
14419
14420             /* IPOP happens only when trying to restore a
14421                spilt live range, if there is an ifx statement
14422                following this pop (or several) then the if statement might
14423                be using some of the registers being popped which
14424                would destory the contents of the register so
14425                we need to check for this condition and handle it */
14426             for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
14427             for (popIc = ic; popIc && popIc->op == IPOP; popIc = popIc->next)
14428               CommonRegs |= (ifxIc && ifxIc->op == IFX && !ifxIc->generated &&
14429                              regsInCommon (IC_LEFT (popIc), IC_COND (ifxIc)));
14430             if (CommonRegs)
14431               genIfx (ifxIc, ic);
14432             else
14433               genIpop (ic);
14434           }
14435           break;
14436
14437         case CALL:
14438           genCall (ic);
14439           break;
14440
14441         case PCALL:
14442           genPcall (ic);
14443           break;
14444
14445         case FUNCTION:
14446           genFunction (ic);
14447           break;
14448
14449         case ENDFUNCTION:
14450           genEndFunction (ic);
14451           break;
14452
14453         case RETURN:
14454           genRet (ic);
14455           break;
14456
14457         case LABEL:
14458           genLabel (ic);
14459           break;
14460
14461         case GOTO:
14462           genGoto (ic);
14463           break;
14464
14465         case '+':
14466           genPlus (ic);
14467           break;
14468
14469         case '-':
14470           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14471             genMinus (ic);
14472           break;
14473
14474         case '*':
14475           genMult (ic);
14476           break;
14477
14478         case '/':
14479           genDiv (ic);
14480           break;
14481
14482         case '%':
14483           genMod (ic);
14484           break;
14485
14486         case '>':
14487           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14488           break;
14489
14490         case '<':
14491           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14492           break;
14493
14494         case LE_OP:
14495         case GE_OP:
14496         case NE_OP:
14497
14498           /* note these two are xlated by algebraic equivalence
14499              during parsing SDCC.y */
14500           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14501                   "got '>=' or '<=' shouldn't have come here");
14502           break;
14503
14504         case EQ_OP:
14505           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14506           break;
14507
14508         case AND_OP:
14509           genAndOp (ic);
14510           break;
14511
14512         case OR_OP:
14513           genOrOp (ic);
14514           break;
14515
14516         case '^':
14517           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14518           break;
14519
14520         case '|':
14521           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14522           break;
14523
14524         case BITWISEAND:
14525           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14526           break;
14527
14528         case INLINEASM:
14529           genInline (ic);
14530           break;
14531
14532         case RRC:
14533           genRRC (ic);
14534           break;
14535
14536         case RLC:
14537           genRLC (ic);
14538           break;
14539
14540         case GETHBIT:
14541           genGetHbit (ic);
14542           break;
14543
14544         case LEFT_OP:
14545           genLeftShift (ic);
14546           break;
14547
14548         case RIGHT_OP:
14549           genRightShift (ic);
14550           break;
14551
14552         case GET_VALUE_AT_ADDRESS:
14553           genPointerGet (ic,
14554                          hasInc (IC_LEFT (ic), ic,
14555                                  getSize (operandType (IC_RESULT (ic)))));
14556           break;
14557
14558         case '=':
14559           if (POINTER_SET (ic))
14560             genPointerSet (ic,
14561                            hasInc (IC_RESULT (ic), ic,
14562                                    getSize (operandType (IC_RIGHT (ic)))));
14563           else
14564             genAssign (ic);
14565           break;
14566
14567         case IFX:
14568           genIfx (ic, NULL);
14569           break;
14570
14571         case ADDRESS_OF:
14572           genAddrOf (ic);
14573           break;
14574
14575         case JUMPTABLE:
14576           genJumpTab (ic);
14577           break;
14578
14579         case CAST:
14580           genCast (ic);
14581           break;
14582
14583         case RECEIVE:
14584           genReceive (ic);
14585           break;
14586
14587         case SEND:
14588           if (ic->builtinSEND)
14589             genBuiltIn(ic);
14590           else
14591             addSet (&_G.sendSet, ic);
14592           break;
14593
14594         case DUMMY_READ_VOLATILE:
14595           genDummyRead (ic);
14596           break;
14597
14598         case CRITICAL:
14599           genCritical (ic);
14600           break;
14601
14602         case ENDCRITICAL:
14603           genEndCritical (ic);
14604           break;
14605
14606         case SWAP:
14607           genSwap (ic);
14608           break;
14609
14610 #if 0 // obsolete, and buggy for != xdata
14611         case ARRAYINIT:
14612             genArrayInit(ic);
14613             break;
14614 #endif
14615
14616         default:
14617             /* This should never happen, right? */
14618             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n",
14619                     ic->op, ic->op, __FILE__, __LINE__);
14620             ic = ic;
14621         }
14622     }
14623
14624
14625   /* now we are ready to call the
14626      peep hole optimizer */
14627   if (!options.nopeep)
14628     peepHole (&lineHead);
14629
14630   /* now do the actual printing */
14631   printLine (lineHead, codeOutBuf);
14632   return;
14633 }