aa9a8983a554fb6ebb0bd7ae2dfa1d9252100283
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) do if (options.verboseAsm) {x;} while(0)
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                        AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC    emitcode("clr","c")
170 #define SETC    emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227       }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerialzes an object                           */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic)) {
908               sym_link *from_type = operandType(IC_RIGHT(ic));
909               aop->aopu.aop_immd.from_cast_remat = 1;
910               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
911               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
912               continue;
913       } else break;
914
915       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
916     }
917
918   if (val)
919   {
920       SNPRINTF (buffer, sizeof(buffer),
921                 "(%s %c 0x%06x)",
922                 OP_SYMBOL (IC_LEFT (ic))->rname,
923                 val >= 0 ? '+' : '-',
924                 abs (val) & 0xffffff);
925   }
926   else
927   {
928       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
929       {
930           SNPRINTF(buffer, sizeof(buffer),
931                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
932       }
933       else
934       {
935           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
936       }
937   }
938
939   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
940   /* set immd2 field if required */
941   if (aop->aopu.aop_immd.from_cast_remat)
942   {
943       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
944       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
945   }
946
947   return aop;
948 }
949
950 /*-----------------------------------------------------------------*/
951 /* aopHasRegs - returns true if aop has regs between from-to       */
952 /*-----------------------------------------------------------------*/
953 static int aopHasRegs(asmop *aop, int from, int to)
954 {
955     int size =0;
956
957     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
958
959     for (; size < aop->size ; size++) {
960         int reg;
961         for (reg = from ; reg <= to ; reg++)
962             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
963     }
964     return 0;
965 }
966
967 /*-----------------------------------------------------------------*/
968 /* regsInCommon - two operands have some registers in common       */
969 /*-----------------------------------------------------------------*/
970 static bool
971 regsInCommon (operand * op1, operand * op2)
972 {
973   symbol *sym1, *sym2;
974   int i;
975
976   /* if they have registers in common */
977   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
978     return FALSE;
979
980   sym1 = OP_SYMBOL (op1);
981   sym2 = OP_SYMBOL (op2);
982
983   if (sym1->nRegs == 0 || sym2->nRegs == 0)
984     return FALSE;
985
986   for (i = 0; i < sym1->nRegs; i++)
987     {
988       int j;
989       if (!sym1->regs[i])
990         continue;
991
992       for (j = 0; j < sym2->nRegs; j++)
993         {
994           if (!sym2->regs[j])
995             continue;
996
997           if (sym2->regs[j] == sym1->regs[i])
998             return TRUE;
999         }
1000     }
1001
1002   return FALSE;
1003 }
1004
1005 /*-----------------------------------------------------------------*/
1006 /* operandsEqu - equivalent                                        */
1007 /*-----------------------------------------------------------------*/
1008 static bool
1009 operandsEqu (operand * op1, operand * op2)
1010 {
1011   symbol *sym1, *sym2;
1012
1013   /* if they're not symbols */
1014   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1015     return FALSE;
1016
1017   sym1 = OP_SYMBOL (op1);
1018   sym2 = OP_SYMBOL (op2);
1019
1020   /* if both are itemps & one is spilt
1021      and the other is not then false */
1022   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1023       sym1->isspilt != sym2->isspilt)
1024     return FALSE;
1025
1026   /* if they are the same */
1027   if (sym1 == sym2)
1028     return TRUE;
1029
1030   /* if they have the same rname */
1031   if (sym1->rname[0] && sym2->rname[0] &&
1032       strcmp (sym1->rname, sym2->rname) == 0 &&
1033       !(IS_PARM (op2) && IS_ITEMP (op1)))
1034     return TRUE;
1035
1036   /* if left is a tmp & right is not */
1037   if (IS_ITEMP (op1) &&
1038       !IS_ITEMP (op2) &&
1039       sym1->isspilt &&
1040       (sym1->usl.spillLoc == sym2))
1041     return TRUE;
1042
1043   if (IS_ITEMP (op2) &&
1044       !IS_ITEMP (op1) &&
1045       sym2->isspilt &&
1046       sym1->level > 0 &&
1047       (sym2->usl.spillLoc == sym1))
1048     return TRUE;
1049
1050   /* are they spilt to the same location */
1051   if (IS_ITEMP (op2) &&
1052       IS_ITEMP (op1) &&
1053       sym2->isspilt &&
1054       sym1->isspilt &&
1055       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1056     return TRUE;
1057
1058   return FALSE;
1059 }
1060
1061 /*-----------------------------------------------------------------*/
1062 /* sameRegs - two asmops have the same registers                   */
1063 /*-----------------------------------------------------------------*/
1064 static bool
1065 sameRegs (asmop * aop1, asmop * aop2)
1066 {
1067   int i;
1068
1069   if (aop1 == aop2)
1070     {
1071       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1072         {
1073           return FALSE;
1074         }
1075       return TRUE;
1076     }
1077
1078   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1079     return FALSE;
1080
1081   if (aop1->type != aop2->type)
1082     return FALSE;
1083
1084   if (aop1->size != aop2->size)
1085     return FALSE;
1086
1087   for (i = 0; i < aop1->size; i++)
1088     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1089       return FALSE;
1090
1091   return TRUE;
1092 }
1093
1094 /*-----------------------------------------------------------------*/
1095 /* aopOp - allocates an asmop for an operand  :                    */
1096 /*-----------------------------------------------------------------*/
1097 static void
1098 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1099 {
1100   asmop *aop;
1101   symbol *sym;
1102   int i;
1103
1104   if (!op)
1105     return;
1106
1107   /* if this a literal */
1108   if (IS_OP_LITERAL (op))
1109     {
1110       op->aop = aop = newAsmop (AOP_LIT);
1111       aop->aopu.aop_lit = op->operand.valOperand;
1112       aop->size = getSize (operandType (op));
1113       return;
1114     }
1115
1116   /* if already has a asmop then continue */
1117   if (op->aop)
1118     {
1119       if ((op->aop->type == AOP_DPTR && useDP2)
1120           || (op->aop->type == AOP_DPTR2 && !useDP2))
1121         op->aop = NULL;
1122       else
1123         {
1124           op->aop->allocated++;
1125           return;
1126         }
1127     }
1128
1129   /* if the underlying symbol has a aop */
1130   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1131     {
1132       op->aop = OP_SYMBOL (op)->aop;
1133       if ((op->aop->type == AOP_DPTR && useDP2)
1134           || (op->aop->type == AOP_DPTR2 && !useDP2))
1135         op->aop = NULL;
1136       else
1137         {
1138           op->aop->allocated++;
1139           return;
1140         }
1141     }
1142
1143   /* if this is a true symbol */
1144   if (IS_TRUE_SYMOP (op))
1145     {
1146       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1147       return;
1148     }
1149
1150   /* this is a temporary : this has
1151      only five choices :
1152      a) register
1153      b) spillocation
1154      c) rematerialize
1155      d) conditional
1156      e) can be a return use only */
1157
1158   sym = OP_SYMBOL (op);
1159
1160   /* if the type is a conditional */
1161   if (sym->regType == REG_CND)
1162     {
1163       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1164       aop->size = 0;
1165       return;
1166     }
1167
1168   /* if it is spilt then two situations
1169      a) is rematerialize
1170      b) has a spill location */
1171   if (sym->isspilt || sym->nRegs == 0)
1172     {
1173
1174       /* rematerialize it NOW */
1175       if (sym->remat)
1176         {
1177           sym->aop = op->aop = aop =
1178             aopForRemat (sym);
1179           aop->size = getSize (sym->type);
1180           return;
1181         }
1182
1183       if (sym->accuse)
1184         {
1185           int i;
1186           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1187           aop->size = getSize (sym->type);
1188           for (i = 0; i < 2; i++)
1189             aop->aopu.aop_str[i] = accUse[i];
1190           return;
1191         }
1192
1193       if (sym->ruonly)
1194         {
1195           unsigned i;
1196
1197           if (useDP2)
1198             {
1199               /* a AOP_STR uses DPTR, but DPTR is already in use;
1200                * we're just hosed.
1201                */
1202                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1203             }
1204
1205           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1206           aop->size = getSize (sym->type);
1207           for (i = 0; i < fReturnSizeDS390; i++)
1208             aop->aopu.aop_str[i] = fReturn[i];
1209           return;
1210         }
1211
1212       if (sym->dptr) { /* has been allocated to a DPTRn */
1213           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1214           aop->size = getSize (sym->type);
1215           aop->aopu.dptr = sym->dptr;
1216           return ;
1217       }
1218
1219       if (sym->usl.spillLoc)
1220         {
1221           asmop *oldAsmOp = NULL;
1222
1223           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1224             {
1225               /* force a new aop if sizes differ */
1226               oldAsmOp = sym->usl.spillLoc->aop;
1227               sym->usl.spillLoc->aop = NULL;
1228             }
1229           sym->aop = op->aop = aop =
1230                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1231           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1232             {
1233               /* Don't reuse the new aop, go with the last one */
1234               sym->usl.spillLoc->aop = oldAsmOp;
1235             }
1236           aop->size = getSize (sym->type);
1237           return;
1238         }
1239
1240       /* else must be a dummy iTemp */
1241       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1242       aop->size = getSize (sym->type);
1243       return;
1244     }
1245
1246   /* if the type is a bit register */
1247   if (sym->regType == REG_BIT)
1248     {
1249       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1250       aop->size = sym->nRegs;//1???
1251       aop->aopu.aop_reg[0] = sym->regs[0];
1252       aop->aopu.aop_dir = sym->regs[0]->name;
1253       return;
1254     }
1255
1256   /* must be in a register */
1257   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1258   aop->size = sym->nRegs;
1259   for (i = 0; i < sym->nRegs; i++)
1260     aop->aopu.aop_reg[i] = sym->regs[i];
1261 }
1262
1263 /*-----------------------------------------------------------------*/
1264 /* freeAsmop - free up the asmop given to an operand               */
1265 /*----------------------------------------------------------------*/
1266 static void
1267 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1268 {
1269   asmop *aop;
1270
1271   if (!op)
1272     aop = aaop;
1273   else
1274     aop = op->aop;
1275
1276   if (!aop)
1277     return;
1278
1279   aop->allocated--;
1280
1281   if (aop->allocated)
1282     goto dealloc;
1283
1284   /* depending on the asmop type only three cases need work
1285      AOP_R0, AOP_R1 & AOP_STK */
1286   switch (aop->type)
1287     {
1288     case AOP_R0:
1289       if (_G.r0Pushed)
1290         {
1291           if (pop)
1292             {
1293               emitcode ("pop", "ar0");
1294               _G.r0Pushed--;
1295             }
1296         }
1297       bitVectUnSetBit (ic->rUsed, R0_IDX);
1298       break;
1299
1300     case AOP_R1:
1301       if (_G.r1Pushed)
1302         {
1303           if (pop)
1304             {
1305               emitcode ("pop", "ar1");
1306               _G.r1Pushed--;
1307             }
1308         }
1309       bitVectUnSetBit (ic->rUsed, R1_IDX);
1310       break;
1311
1312     case AOP_STK:
1313       {
1314         int sz = aop->size;
1315         int stk = aop->aopu.aop_stk + aop->size;
1316         bitVectUnSetBit (ic->rUsed, R0_IDX);
1317         bitVectUnSetBit (ic->rUsed, R1_IDX);
1318
1319         getFreePtr (ic, &aop, FALSE);
1320
1321         if (options.stack10bit)
1322           {
1323             /* I'm not sure what to do here yet... */
1324             /* #STUB */
1325             fprintf (stderr,
1326                      "*** Warning: probably generating bad code for "
1327                      "10 bit stack mode.\n");
1328           }
1329
1330         if (stk)
1331           {
1332             emitcode ("mov", "a,_bp");
1333             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1334             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1335           }
1336         else
1337           {
1338             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1339           }
1340
1341         while (sz--)
1342           {
1343             emitcode ("pop", "acc");
1344             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1345             if (!sz)
1346               break;
1347             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1348           }
1349         op->aop = aop;
1350         freeAsmop (op, NULL, ic, TRUE);
1351         if (_G.r1Pushed)
1352           {
1353             emitcode ("pop", "ar1");
1354             _G.r1Pushed--;
1355           }
1356         if (_G.r0Pushed)
1357           {
1358             emitcode ("pop", "ar0");
1359             _G.r0Pushed--;
1360           }
1361       }
1362     case AOP_DPTR2:
1363         if (_G.dptr1InUse) {
1364             emitcode ("pop","dpx1");
1365             emitcode ("pop","dph1");
1366             emitcode ("pop","dpl1");
1367         }
1368         break;
1369     case AOP_DPTR:
1370         if (_G.dptrInUse) {
1371             emitcode ("pop","dpx");
1372             emitcode ("pop","dph");
1373             emitcode ("pop","dpl");
1374         }
1375         break;
1376     }
1377
1378 dealloc:
1379   /* all other cases just dealloc */
1380   if (op)
1381     {
1382       op->aop = NULL;
1383       if (IS_SYMOP (op))
1384         {
1385           OP_SYMBOL (op)->aop = NULL;
1386           /* if the symbol has a spill */
1387           if (SPIL_LOC (op))
1388             SPIL_LOC (op)->aop = NULL;
1389         }
1390     }
1391 }
1392
1393 #define DEFAULT_ACC_WARNING 0
1394 static int saveAccWarn = DEFAULT_ACC_WARNING;
1395
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1399 /*                 clobber the accumulator                         */
1400 /*-----------------------------------------------------------------*/
1401 static bool
1402 aopGetUsesAcc (operand * oper, int offset)
1403 {
1404   asmop * aop = AOP (oper);
1405
1406   if (offset > (aop->size - 1))
1407     return FALSE;
1408
1409   switch (aop->type)
1410     {
1411
1412     case AOP_R0:
1413     case AOP_R1:
1414       if (aop->paged)
1415         return TRUE;
1416       return FALSE;
1417     case AOP_DPTR:
1418     case AOP_DPTR2:
1419     case AOP_DPTRn:
1420       return TRUE;
1421     case AOP_IMMD:
1422       return FALSE;
1423     case AOP_DIR:
1424       return FALSE;
1425     case AOP_REG:
1426       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1427       return FALSE;
1428     case AOP_CRY:
1429       return TRUE;
1430     case AOP_ACC:
1431       if (offset)
1432         return FALSE;
1433       return TRUE;
1434     case AOP_LIT:
1435       return FALSE;
1436     case AOP_STR:
1437       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1438         return TRUE;
1439       return FALSE;
1440     case AOP_DUMMY:
1441       return FALSE;
1442     default:
1443       /* Error case --- will have been caught already */
1444       wassert(0);
1445       return FALSE;
1446     }
1447 }
1448
1449 /*-------------------------------------------------------------------*/
1450 /* aopGet - for fetching value of the aop                            */
1451 /*                                                                   */
1452 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1453 /* in the accumulator. Set it to the name of a free register         */
1454 /* if acc must be preserved; the register will be used to preserve   */
1455 /* acc temporarily and to return the result byte.                    */
1456 /*-------------------------------------------------------------------*/
1457 static char *
1458 aopGet (operand * oper,
1459         int   offset,
1460         bool  bit16,
1461         bool  dname,
1462         char  *saveAcc)
1463 {
1464   asmop * aop = AOP (oper);
1465
1466   /* offset is greater than
1467      size then zero */
1468   if (offset > (aop->size - 1) &&
1469       aop->type != AOP_LIT)
1470     return zero;
1471
1472   /* depending on type */
1473   switch (aop->type)
1474     {
1475     case AOP_DUMMY:
1476       return zero;
1477
1478     case AOP_R0:
1479     case AOP_R1:
1480       /* if we need to increment it */
1481       while (offset > aop->coff)
1482         {
1483           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1484           aop->coff++;
1485         }
1486
1487       while (offset < aop->coff)
1488         {
1489           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1490           aop->coff--;
1491         }
1492
1493       aop->coff = offset;
1494       if (aop->paged)
1495         {
1496           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1497           return (dname ? "acc" : "a");
1498         }
1499       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1500       return Safe_strdup(buffer);
1501
1502     case AOP_DPTRn:
1503         assert(offset <= 3);
1504         return dptrn[aop->aopu.dptr][offset];
1505
1506     case AOP_DPTR:
1507     case AOP_DPTR2:
1508
1509       if (aop->type == AOP_DPTR2)
1510         {
1511           genSetDPTR (1);
1512         }
1513
1514       if (saveAcc)
1515         {
1516             TR_AP("#1");
1517 //          if (aop->type != AOP_DPTR2)
1518 //          {
1519 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1520 //              emitcode(";", "spanky: saveAcc for DPTR");
1521 //          }
1522
1523             emitcode ("xch", "a, %s", saveAcc);
1524         }
1525
1526       _flushLazyDPS ();
1527
1528       while (offset > aop->coff)
1529         {
1530           emitcode ("inc", "dptr");
1531           aop->coff++;
1532         }
1533
1534       while (offset < aop->coff)
1535         {
1536           emitcode ("lcall", "__decdptr");
1537           aop->coff--;
1538         }
1539
1540       aop->coff = offset;
1541       if (aop->code)
1542         {
1543           emitcode ("clr", "a");
1544           emitcode ("movc", "a,@a+dptr");
1545         }
1546       else
1547         {
1548           emitcode ("movx", "a,@dptr");
1549         }
1550
1551       if (aop->type == AOP_DPTR2)
1552         {
1553           genSetDPTR (0);
1554         }
1555
1556       if (saveAcc)
1557         {
1558           TR_AP("#2");
1559           emitcode ("xch", "a, %s", saveAcc);
1560 //        if (strcmp(saveAcc, "_ap"))
1561 //          {
1562 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1563 //          }
1564
1565           return saveAcc;
1566         }
1567       return (dname ? "acc" : "a");
1568
1569     case AOP_IMMD:
1570       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1571         {
1572           SNPRINTF(buffer, sizeof(buffer),
1573                    "%s",aop->aopu.aop_immd.aop_immd2);
1574         }
1575       else if (bit16)
1576         {
1577           SNPRINTF(buffer, sizeof(buffer),
1578                    "#%s", aop->aopu.aop_immd.aop_immd1);
1579         }
1580       else if (offset)
1581         {
1582           switch (offset) {
1583           case 1:
1584               tsprintf(buffer, sizeof(buffer),
1585                        "#!his",aop->aopu.aop_immd.aop_immd1);
1586               break;
1587           case 2:
1588               tsprintf(buffer, sizeof(buffer),
1589                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1590               break;
1591           case 3:
1592               tsprintf(buffer, sizeof(buffer),
1593                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1594               break;
1595           default: /* should not need this (just in case) */
1596               SNPRINTF (buffer, sizeof(buffer),
1597                         "#(%s >> %d)",
1598                        aop->aopu.aop_immd.aop_immd1,
1599                        offset * 8);
1600           }
1601         }
1602       else
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "#%s",
1606                     aop->aopu.aop_immd.aop_immd1);
1607         }
1608       return Safe_strdup(buffer);
1609
1610     case AOP_DIR:
1611       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1612         {
1613           SNPRINTF (buffer, sizeof(buffer),
1614                     "(%s >> %d)",
1615                     aop->aopu.aop_dir, offset * 8);
1616         }
1617       else if (offset)
1618         {
1619           SNPRINTF (buffer, sizeof(buffer),
1620                     "(%s + %d)",
1621                    aop->aopu.aop_dir,
1622                    offset);
1623         }
1624       else
1625         {
1626           SNPRINTF (buffer, sizeof(buffer),
1627                     "%s",
1628                     aop->aopu.aop_dir);
1629         }
1630
1631       return Safe_strdup(buffer);
1632
1633     case AOP_REG:
1634       if (dname)
1635         return aop->aopu.aop_reg[offset]->dname;
1636       else
1637         return aop->aopu.aop_reg[offset]->name;
1638
1639     case AOP_CRY:
1640       emitcode ("clr", "a");
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("rlc", "a");
1643       return (dname ? "acc" : "a");
1644
1645     case AOP_ACC:
1646       if (!offset && dname)
1647         return "acc";
1648       return aop->aopu.aop_str[offset];
1649
1650     case AOP_LIT:
1651       return aopLiteral (aop->aopu.aop_lit, offset);
1652
1653     case AOP_STR:
1654       aop->coff = offset;
1655       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1656           dname)
1657         return "acc";
1658
1659       return aop->aopu.aop_str[offset];
1660
1661     }
1662
1663   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1664           "aopget got unsupported aop->type");
1665   exit (1);
1666
1667   return NULL;  // not reached, but makes compiler happy.
1668 }
1669
1670 /*-----------------------------------------------------------------*/
1671 /* aopPut - puts a string for a aop and indicates if acc is in use */
1672 /*-----------------------------------------------------------------*/
1673 static bool
1674 aopPut (operand * result, const char *s, int offset)
1675 {
1676   bool bvolatile = isOperandVolatile (result, FALSE);
1677   bool accuse = FALSE;
1678   asmop * aop = AOP (result);
1679
1680   if (aop->size && offset > (aop->size - 1))
1681     {
1682       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1683               "aopPut got offset > aop->size");
1684       exit (1);
1685     }
1686
1687   /* will assign value to value */
1688   /* depending on where it is ofcourse */
1689   switch (aop->type)
1690     {
1691     case AOP_DUMMY:
1692       MOVA (s);         /* read s in case it was volatile */
1693       accuse = TRUE;
1694       break;
1695
1696     case AOP_DIR:
1697       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1698         {
1699           SNPRINTF (buffer, sizeof(buffer),
1700                     "(%s >> %d)",
1701                     aop->aopu.aop_dir, offset * 8);
1702         }
1703       else if (offset)
1704         {
1705           SNPRINTF (buffer, sizeof(buffer),
1706                     "(%s + %d)",
1707                     aop->aopu.aop_dir, offset);
1708         }
1709       else
1710         {
1711           SNPRINTF (buffer, sizeof(buffer),
1712                     "%s",
1713                     aop->aopu.aop_dir);
1714         }
1715
1716       if (strcmp (buffer, s) || bvolatile)
1717         {
1718           emitcode ("mov", "%s,%s", buffer, s);
1719         }
1720       if (!strcmp (buffer, "acc"))
1721         {
1722           accuse = TRUE;
1723         }
1724       break;
1725
1726     case AOP_REG:
1727       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1728           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1729         {
1730           if (*s == '@' ||
1731               strcmp (s, "r0") == 0 ||
1732               strcmp (s, "r1") == 0 ||
1733               strcmp (s, "r2") == 0 ||
1734               strcmp (s, "r3") == 0 ||
1735               strcmp (s, "r4") == 0 ||
1736               strcmp (s, "r5") == 0 ||
1737               strcmp (s, "r6") == 0 ||
1738               strcmp (s, "r7") == 0)
1739             {
1740               emitcode ("mov", "%s,%s",
1741                         aop->aopu.aop_reg[offset]->dname, s);
1742             }
1743             else
1744             {
1745               emitcode ("mov", "%s,%s",
1746                         aop->aopu.aop_reg[offset]->name, s);
1747             }
1748         }
1749       break;
1750
1751     case AOP_DPTRn:
1752         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1753         break;
1754
1755     case AOP_DPTR:
1756     case AOP_DPTR2:
1757
1758       if (aop->type == AOP_DPTR2)
1759         {
1760           genSetDPTR (1);
1761         }
1762       _flushLazyDPS ();
1763
1764       if (aop->code)
1765         {
1766           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1767                   "aopPut writing to code space");
1768           exit (1);
1769         }
1770
1771       while (offset > aop->coff)
1772         {
1773           aop->coff++;
1774           emitcode ("inc", "dptr");
1775         }
1776
1777       while (offset < aop->coff)
1778         {
1779           aop->coff--;
1780           emitcode ("lcall", "__decdptr");
1781         }
1782
1783       aop->coff = offset;
1784
1785       /* if not in accumulator */
1786       MOVA (s);
1787
1788       emitcode ("movx", "@dptr,a");
1789
1790       if (aop->type == AOP_DPTR2)
1791         {
1792           genSetDPTR (0);
1793         }
1794       break;
1795
1796     case AOP_R0:
1797     case AOP_R1:
1798       while (offset > aop->coff)
1799         {
1800           aop->coff++;
1801           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1802         }
1803       while (offset < aop->coff)
1804         {
1805           aop->coff--;
1806           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1807         }
1808       aop->coff = offset;
1809
1810       if (aop->paged)
1811         {
1812           MOVA (s);
1813           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1814         }
1815       else if (*s == '@')
1816         {
1817           MOVA (s);
1818           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1819         }
1820       else if (strcmp (s, "r0") == 0 ||
1821                strcmp (s, "r1") == 0 ||
1822                strcmp (s, "r2") == 0 ||
1823                strcmp (s, "r3") == 0 ||
1824                strcmp (s, "r4") == 0 ||
1825                strcmp (s, "r5") == 0 ||
1826                strcmp (s, "r6") == 0 ||
1827                strcmp (s, "r7") == 0)
1828         {
1829           char buffer[10];
1830           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1831           emitcode ("mov", "@%s,%s",
1832                     aop->aopu.aop_ptr->name, buffer);
1833         }
1834         else
1835         {
1836             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1837         }
1838       break;
1839
1840     case AOP_STK:
1841       if (strcmp (s, "a") == 0)
1842         emitcode ("push", "acc");
1843       else
1844         if (*s=='@') {
1845           MOVA(s);
1846           emitcode ("push", "acc");
1847         } else {
1848           emitcode ("push", s);
1849         }
1850
1851       break;
1852
1853     case AOP_CRY:
1854       /* if not bit variable */
1855       if (!aop->aopu.aop_dir)
1856         {
1857           /* inefficient: move carry into A and use jz/jnz */
1858           emitcode ("clr", "a");
1859           emitcode ("rlc", "a");
1860           accuse = TRUE;
1861         }
1862       else
1863         {
1864           if (s == zero)
1865             emitcode ("clr", "%s", aop->aopu.aop_dir);
1866           else if (s == one)
1867             emitcode ("setb", "%s", aop->aopu.aop_dir);
1868           else if (!strcmp (s, "c"))
1869             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1870           else if (strcmp (s, aop->aopu.aop_dir))
1871             {
1872               MOVA (s);
1873               /* set C, if a >= 1 */
1874               emitcode ("add", "a,#!constbyte",0xff);
1875               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1876             }
1877         }
1878       break;
1879
1880     case AOP_STR:
1881       aop->coff = offset;
1882       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1883         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1884       break;
1885
1886     case AOP_ACC:
1887       accuse = TRUE;
1888       aop->coff = offset;
1889       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1890         break;
1891
1892       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1893         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1894       break;
1895
1896     default:
1897       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1898               "aopPut got unsupported aop->type");
1899       exit (1);
1900     }
1901
1902     return accuse;
1903 }
1904
1905
1906 /*--------------------------------------------------------------------*/
1907 /* reAdjustPreg - points a register back to where it should (coff==0) */
1908 /*--------------------------------------------------------------------*/
1909 static void
1910 reAdjustPreg (asmop * aop)
1911 {
1912   if ((aop->coff==0) || (aop->size <= 1))
1913     return;
1914
1915   switch (aop->type)
1916     {
1917     case AOP_R0:
1918     case AOP_R1:
1919       while (aop->coff--)
1920         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1921       break;
1922     case AOP_DPTR:
1923     case AOP_DPTR2:
1924       if (aop->type == AOP_DPTR2)
1925         {
1926           genSetDPTR (1);
1927           _flushLazyDPS ();
1928         }
1929       while (aop->coff--)
1930         {
1931           emitcode ("lcall", "__decdptr");
1932         }
1933
1934       if (aop->type == AOP_DPTR2)
1935         {
1936           genSetDPTR (0);
1937         }
1938       break;
1939     }
1940   aop->coff = 0;
1941 }
1942
1943 /*-----------------------------------------------------------------*/
1944 /* opIsGptr: returns non-zero if the passed operand is       */
1945 /* a generic pointer type.             */
1946 /*-----------------------------------------------------------------*/
1947 static int
1948 opIsGptr (operand * op)
1949 {
1950   sym_link *type = operandType (op);
1951
1952   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1953     {
1954       return 1;
1955     }
1956   return 0;
1957 }
1958
1959 /*-----------------------------------------------------------------*/
1960 /* getDataSize - get the operand data size                         */
1961 /*-----------------------------------------------------------------*/
1962 static int
1963 getDataSize (operand * op)
1964 {
1965   int size;
1966   size = AOP_SIZE (op);
1967   if (size == GPTRSIZE)
1968     {
1969       sym_link *type = operandType (op);
1970       if (IS_GENPTR (type))
1971         {
1972           /* generic pointer; arithmetic operations
1973            * should ignore the high byte (pointer type).
1974            */
1975           size--;
1976         }
1977     }
1978   return size;
1979 }
1980
1981 /*-----------------------------------------------------------------*/
1982 /* outAcc - output Acc                                             */
1983 /*-----------------------------------------------------------------*/
1984 static void
1985 outAcc (operand * result)
1986 {
1987   int size, offset;
1988   size = getDataSize (result);
1989   if (size)
1990     {
1991       aopPut (result, "a", 0);
1992       size--;
1993       offset = 1;
1994       /* unsigned or positive */
1995       while (size--)
1996         {
1997           aopPut (result, zero, offset++);
1998         }
1999     }
2000 }
2001
2002 /*-----------------------------------------------------------------*/
2003 /* outBitC - output a bit C                                        */
2004 /*-----------------------------------------------------------------*/
2005 static void
2006 outBitC (operand * result)
2007 {
2008   /* if the result is bit */
2009   if (AOP_TYPE (result) == AOP_CRY)
2010     {
2011       aopPut (result, "c", 0);
2012     }
2013   else
2014     {
2015       emitcode ("clr", "a");
2016       emitcode ("rlc", "a");
2017       outAcc (result);
2018     }
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* toBoolean - emit code for orl a,operator(sizeop)                */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 toBoolean (operand * oper)
2026 {
2027   int  size = AOP_SIZE (oper) - 1;
2028   int  offset = 1;
2029   bool pushedB;
2030
2031   /* The generic part of a generic pointer should
2032    * not participate in it's truth value.
2033    *
2034    * i.e. 0x10000000 is zero.
2035    */
2036   if (opIsGptr (oper))
2037     {
2038       D (emitcode (";", "toBoolean: generic ptr special case."));
2039       size--;
2040     }
2041
2042   _startLazyDPSEvaluation ();
2043   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2044   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2045     {
2046       pushedB = pushB ();
2047       emitcode("mov", "b,a");
2048       while (--size)
2049         {
2050           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2051           emitcode ("orl", "b,a");
2052         }
2053       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2054       emitcode ("orl", "a,b");
2055       popB (pushedB);
2056     }
2057   else
2058     {
2059       while (size--)
2060         {
2061           emitcode ("orl", "a,%s",
2062                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2063         }
2064     }
2065   _endLazyDPSEvaluation ();
2066 }
2067
2068
2069 /*-----------------------------------------------------------------*/
2070 /* genNot - generate code for ! operation                          */
2071 /*-----------------------------------------------------------------*/
2072 static void
2073 genNot (iCode * ic)
2074 {
2075   symbol *tlbl;
2076
2077   D (emitcode (";", "genNot"));
2078
2079   /* assign asmOps to operand & result */
2080   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2081   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2082
2083   /* if in bit space then a special case */
2084   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2085     {
2086       /* if left==result then cpl bit */
2087       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2088         {
2089           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2090         }
2091       else
2092         {
2093           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2094           emitcode ("cpl", "c");
2095           outBitC (IC_RESULT (ic));
2096         }
2097       goto release;
2098     }
2099
2100   toBoolean (IC_LEFT (ic));
2101
2102   /* set C, if a == 0 */
2103   tlbl = newiTempLabel (NULL);
2104   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2105   emitLabel (tlbl);
2106   outBitC (IC_RESULT (ic));
2107
2108 release:
2109   /* release the aops */
2110   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2111   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2112 }
2113
2114
2115 /*-----------------------------------------------------------------*/
2116 /* genCpl - generate code for complement                           */
2117 /*-----------------------------------------------------------------*/
2118 static void
2119 genCpl (iCode * ic)
2120 {
2121   int offset = 0;
2122   int size;
2123   symbol *tlbl;
2124   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2125
2126   D(emitcode (";", "genCpl"));
2127
2128   /* assign asmOps to operand & result */
2129   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2130   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2131
2132   /* special case if in bit space */
2133   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2134     {
2135       char *l;
2136
2137       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2138           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2139         {
2140           /* promotion rules are responsible for this strange result:
2141              bit -> int -> ~int -> bit
2142              uchar -> int -> ~int -> bit
2143           */
2144           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2145           goto release;
2146         }
2147
2148       tlbl=newiTempLabel(NULL);
2149       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2150       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2151           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2152           IS_AOP_PREG (IC_LEFT (ic)))
2153         {
2154           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2155         }
2156       else
2157         {
2158           MOVA (l);
2159           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2160         }
2161       emitLabel (tlbl);
2162       outBitC (IC_RESULT(ic));
2163       goto release;
2164     }
2165
2166   size = AOP_SIZE (IC_RESULT (ic));
2167   _startLazyDPSEvaluation ();
2168   while (size--)
2169     {
2170       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2171       MOVA (l);
2172       emitcode ("cpl", "a");
2173       aopPut (IC_RESULT (ic), "a", offset++);
2174     }
2175   _endLazyDPSEvaluation ();
2176
2177
2178 release:
2179   /* release the aops */
2180   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2181   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2182 }
2183
2184 /*-----------------------------------------------------------------*/
2185 /* genUminusFloat - unary minus for floating points                */
2186 /*-----------------------------------------------------------------*/
2187 static void
2188 genUminusFloat (operand * op, operand * result)
2189 {
2190   int size, offset = 0;
2191   char *l;
2192
2193   D (emitcode (";", "genUminusFloat"));
2194
2195   /* for this we just copy and then flip the bit */
2196
2197   _startLazyDPSEvaluation ();
2198   size = AOP_SIZE (op) - 1;
2199
2200   while (size--)
2201     {
2202       aopPut (result,
2203               aopGet (op, offset, FALSE, FALSE, NULL),
2204               offset);
2205       offset++;
2206     }
2207
2208   l = aopGet (op, offset, FALSE, FALSE, NULL);
2209   MOVA (l);
2210
2211   emitcode ("cpl", "acc.7");
2212   aopPut (result, "a", offset);
2213   _endLazyDPSEvaluation ();
2214 }
2215
2216 /*-----------------------------------------------------------------*/
2217 /* genUminus - unary minus code generation                         */
2218 /*-----------------------------------------------------------------*/
2219 static void
2220 genUminus (iCode * ic)
2221 {
2222   int offset, size;
2223   sym_link *optype;
2224
2225   D (emitcode (";", "genUminus"));
2226
2227   /* assign asmops */
2228   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2229   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2230
2231   /* if both in bit space then special
2232      case */
2233   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2234       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2235     {
2236
2237       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2238       emitcode ("cpl", "c");
2239       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2240       goto release;
2241     }
2242
2243   optype = operandType (IC_LEFT (ic));
2244
2245   /* if float then do float stuff */
2246   if (IS_FLOAT (optype))
2247     {
2248       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2249       goto release;
2250     }
2251
2252   /* otherwise subtract from zero */
2253   size = AOP_SIZE (IC_LEFT (ic));
2254   offset = 0;
2255   _startLazyDPSEvaluation ();
2256   while (size--)
2257     {
2258       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2259       if (!strcmp (l, "a"))
2260         {
2261           if (offset == 0)
2262             SETC;
2263           emitcode ("cpl", "a");
2264           emitcode ("addc", "a,#0");
2265         }
2266       else
2267         {
2268           if (offset == 0)
2269             CLRC;
2270           emitcode ("clr", "a");
2271           emitcode ("subb", "a,%s", l);
2272         }
2273       aopPut (IC_RESULT (ic), "a", offset++);
2274     }
2275   _endLazyDPSEvaluation ();
2276
2277   /* if any remaining bytes in the result */
2278   /* we just need to propagate the sign   */
2279   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2280     {
2281       emitcode ("rlc", "a");
2282       emitcode ("subb", "a,acc");
2283       while (size--)
2284         aopPut (IC_RESULT (ic), "a", offset++);
2285     }
2286
2287 release:
2288   /* release the aops */
2289   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2290   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2291 }
2292
2293 /*-----------------------------------------------------------------*/
2294 /* savermask - saves registers in the mask                         */
2295 /*-----------------------------------------------------------------*/
2296 static void savermask(bitVect *rs_mask)
2297 {
2298   int i;
2299
2300   if (options.useXstack)
2301     {
2302       if (bitVectBitValue (rs_mask, R0_IDX))
2303           emitcode ("mov", "b,r0");
2304       emitcode ("mov", "r0,%s", spname);
2305       for (i = 0; i < ds390_nRegs; i++)
2306         {
2307           if (bitVectBitValue (rs_mask, i))
2308             {
2309               if (i == R0_IDX)
2310                   emitcode ("mov", "a,b");
2311               else
2312                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2313               emitcode ("movx", "@r0,a");
2314               emitcode ("inc", "r0");
2315             }
2316         }
2317       emitcode ("mov", "%s,r0", spname);
2318       if (bitVectBitValue (rs_mask, R0_IDX))
2319           emitcode ("mov", "r0,b");
2320     }
2321   else
2322     {
2323       bool bits_pushed = FALSE;
2324       for (i = 0; i < ds390_nRegs; i++)
2325         {
2326           if (bitVectBitValue (rs_mask, i))
2327             {
2328               bits_pushed = pushReg (i, bits_pushed);
2329             }
2330         }
2331     }
2332 }
2333
2334 /*-----------------------------------------------------------------*/
2335 /* saveRegisters - will look for a call and save the registers     */
2336 /*-----------------------------------------------------------------*/
2337 static void
2338 saveRegisters (iCode * lic)
2339 {
2340   iCode *ic;
2341   bitVect *rsave;
2342
2343   /* look for call */
2344   for (ic = lic; ic; ic = ic->next)
2345     if (ic->op == CALL || ic->op == PCALL)
2346       break;
2347
2348   if (!ic)
2349     {
2350       fprintf (stderr, "found parameter push with no function call\n");
2351       return;
2352     }
2353
2354   /* if the registers have been saved already or don't need to be then
2355      do nothing */
2356   if (ic->regsSaved
2357       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2358     return;
2359
2360   /* special case if DPTR alive across a function call then must save it
2361      even though callee saves */
2362   if (IS_SYMOP(IC_LEFT(ic)) &&
2363       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2364     {
2365       int i;
2366       rsave = newBitVect(ic->rMask->size);
2367       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2368           if (bitVectBitValue(ic->rMask,i))
2369               rsave = bitVectSetBit(rsave,i);
2370       }
2371       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2372     }
2373   else
2374     {
2375       /* save the registers in use at this time but skip the
2376          ones for the result */
2377       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2378                              ds390_rUmaskForOp (IC_RESULT(ic)));
2379     }
2380   ic->regsSaved = 1;
2381   savermask(rsave);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* usavermask - restore registers with mask                        */
2386 /*-----------------------------------------------------------------*/
2387 static void unsavermask(bitVect *rs_mask)
2388 {
2389   int i;
2390
2391   if (options.useXstack)
2392     {
2393       emitcode ("mov", "r0,%s", spname);
2394       for (i = ds390_nRegs; i >= 0; i--)
2395         {
2396           if (bitVectBitValue (rs_mask, i))
2397             {
2398               regs * reg = REG_WITH_INDEX (i);
2399               emitcode ("dec", "r0");
2400               emitcode ("movx", "a,@r0");
2401               if (i == R0_IDX)
2402                 {
2403                   emitcode ("push", "acc");
2404                 }
2405               else
2406                 {
2407                   emitcode ("mov", "%s,a", reg->name);
2408                 }
2409             }
2410         }
2411       emitcode ("mov", "%s,r0", spname);
2412       if (bitVectBitValue (rs_mask, R0_IDX))
2413         {
2414           emitcode ("pop", "ar0");
2415         }
2416     }
2417   else
2418     {
2419       bool bits_popped = FALSE;
2420       for (i = ds390_nRegs; i >= 0; i--)
2421         {
2422           if (bitVectBitValue (rs_mask, i))
2423             {
2424               bits_popped = popReg (i, bits_popped);
2425             }
2426         }
2427     }
2428 }
2429
2430 /*-----------------------------------------------------------------*/
2431 /* unsaveRegisters - pop the pushed registers                      */
2432 /*-----------------------------------------------------------------*/
2433 static void
2434 unsaveRegisters (iCode * ic)
2435 {
2436   bitVect *rsave;
2437
2438   if (IS_SYMOP(IC_LEFT (ic)) &&
2439       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2440       int i;
2441       rsave = newBitVect(ic->rMask->size);
2442       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2443           if (bitVectBitValue(ic->rMask,i))
2444               rsave = bitVectSetBit(rsave,i);
2445       }
2446       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2447   } else {
2448     /* restore the registers in use at this time but skip the
2449        ones for the result */
2450     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2451                            ds390_rUmaskForOp (IC_RESULT(ic)));
2452   }
2453   unsavermask(rsave);
2454 }
2455
2456
2457 /*-----------------------------------------------------------------*/
2458 /* pushSide -                */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 pushSide (operand * oper, int size)
2462 {
2463   int offset = 0;
2464   _startLazyDPSEvaluation ();
2465   while (size--)
2466     {
2467       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2468       if (AOP_TYPE (oper) != AOP_REG &&
2469           AOP_TYPE (oper) != AOP_DIR &&
2470           strcmp (l, "a"))
2471         {
2472           MOVA (l);
2473           emitcode ("push", "acc");
2474         }
2475       else
2476         {
2477           emitcode ("push", "%s", l);
2478         }
2479     }
2480   _endLazyDPSEvaluation ();
2481 }
2482
2483 /*-----------------------------------------------------------------*/
2484 /* assignResultValue - also indicates if acc is in use afterwards  */
2485 /*-----------------------------------------------------------------*/
2486 static bool
2487 assignResultValue (operand * oper, operand * func)
2488 {
2489   int offset = 0;
2490   unsigned size = AOP_SIZE (oper);
2491   bool accuse = FALSE;
2492   bool pushedA = FALSE;
2493
2494   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2495     {
2496       outBitC (oper);
2497       return FALSE;
2498     }
2499
2500   if (size == fReturnSizeDS390)
2501   {
2502       /* I don't think this case can ever happen... */
2503       /* ACC is the last part of this. If writing the result
2504        * uses ACC, we must preserve it.
2505        */
2506       if (AOP_NEEDSACC(oper))
2507       {
2508           emitcode(";", "assignResultValue special case for ACC.");
2509           emitcode("push", "acc");
2510           pushedA = TRUE;
2511           size--;
2512       }
2513   }
2514
2515   _startLazyDPSEvaluation ();
2516   while (size--)
2517     {
2518       accuse |= aopPut (oper, fReturn[offset], offset);
2519       offset++;
2520     }
2521   _endLazyDPSEvaluation ();
2522
2523   if (pushedA)
2524     {
2525         emitcode ("pop", "acc");
2526         accuse |= aopPut (oper, "a", offset);
2527     }
2528   return accuse;
2529 }
2530
2531
2532 /*-----------------------------------------------------------------*/
2533 /* genXpush - pushes onto the external stack                       */
2534 /*-----------------------------------------------------------------*/
2535 static void
2536 genXpush (iCode * ic)
2537 {
2538   asmop *aop = newAsmop (0);
2539   regs *r;
2540   int size, offset = 0;
2541
2542   D (emitcode (";", "genXpush"));
2543
2544   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2545   r = getFreePtr (ic, &aop, FALSE);
2546
2547   size = AOP_SIZE (IC_LEFT (ic));
2548
2549   if (size == 1)
2550     {
2551       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2552       emitcode ("mov", "%s,_spx", r->name);
2553       emitcode ("inc", "_spx"); // allocate space first
2554       emitcode ("movx", "@%s,a", r->name);
2555     }
2556   else
2557     {
2558       // allocate space first
2559       emitcode ("mov", "%s,_spx", r->name);
2560       MOVA (r->name);
2561       emitcode ("add", "a,#%d", size);
2562       emitcode ("mov", "_spx,a");
2563
2564       _startLazyDPSEvaluation ();
2565       while (size--)
2566         {
2567           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2568           emitcode ("movx", "@%s,a", r->name);
2569           emitcode ("inc", "%s", r->name);
2570         }
2571       _endLazyDPSEvaluation ();
2572     }
2573
2574   freeAsmop (NULL, aop, ic, TRUE);
2575   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2576 }
2577
2578 /*-----------------------------------------------------------------*/
2579 /* genIpush - generate code for pushing this gets a little complex  */
2580 /*-----------------------------------------------------------------*/
2581 static void
2582 genIpush (iCode * ic)
2583 {
2584   int size, offset = 0;
2585   char *l;
2586   char *prev = "";
2587
2588   D (emitcode (";", "genIpush"));
2589
2590   /* if this is not a parm push : ie. it is spill push
2591      and spill push is always done on the local stack */
2592   if (!ic->parmPush)
2593     {
2594
2595       /* and the item is spilt then do nothing */
2596       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2597         return;
2598
2599       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2600       size = AOP_SIZE (IC_LEFT (ic));
2601       /* push it on the stack */
2602       _startLazyDPSEvaluation ();
2603       while (size--)
2604         {
2605           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2606           if (*l == '#')
2607             {
2608               MOVA (l);
2609               l = "acc";
2610             }
2611           emitcode ("push", "%s", l);
2612         }
2613       _endLazyDPSEvaluation ();
2614       return;
2615     }
2616
2617   /* this is a parameter push: in this case we call
2618      the routine to find the call and save those
2619      registers that need to be saved */
2620   saveRegisters (ic);
2621
2622   /* if use external stack then call the external
2623      stack pushing routine */
2624   if (options.useXstack)
2625     {
2626       genXpush (ic);
2627       return;
2628     }
2629
2630   /* then do the push */
2631   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2632
2633   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2634   size = AOP_SIZE (IC_LEFT (ic));
2635
2636   _startLazyDPSEvaluation ();
2637   while (size--)
2638     {
2639       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2640       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2641           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2642           strcmp (l, "acc"))
2643         {
2644           if (strcmp (l, prev) || *l == '@')
2645             MOVA (l);
2646           emitcode ("push", "acc");
2647         }
2648       else
2649         {
2650             emitcode ("push", "%s", l);
2651         }
2652       prev = l;
2653     }
2654   _endLazyDPSEvaluation ();
2655
2656   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2657 }
2658
2659 /*-----------------------------------------------------------------*/
2660 /* genIpop - recover the registers: can happen only for spilling   */
2661 /*-----------------------------------------------------------------*/
2662 static void
2663 genIpop (iCode * ic)
2664 {
2665   int size, offset;
2666
2667   D (emitcode (";", "genIpop"));
2668
2669   /* if the temp was not pushed then */
2670   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2671     return;
2672
2673   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2674   size = AOP_SIZE (IC_LEFT (ic));
2675   offset = (size - 1);
2676   _startLazyDPSEvaluation ();
2677   while (size--)
2678     {
2679       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2680                                      FALSE, TRUE, NULL));
2681     }
2682   _endLazyDPSEvaluation ();
2683
2684   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2685 }
2686
2687 /*-----------------------------------------------------------------*/
2688 /* saveRBank - saves an entire register bank on the stack          */
2689 /*-----------------------------------------------------------------*/
2690 static void
2691 saveRBank (int bank, iCode * ic, bool pushPsw)
2692 {
2693   int i;
2694   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2695   asmop *aop = NULL;
2696   regs *r = NULL;
2697
2698   if (options.useXstack)
2699     {
2700       if (!ic)
2701         {
2702           /* Assume r0 is available for use. */
2703           r = REG_WITH_INDEX (R0_IDX);;
2704         }
2705       else
2706         {
2707           aop = newAsmop (0);
2708           r = getFreePtr (ic, &aop, FALSE);
2709         }
2710       // allocate space first
2711       emitcode ("mov", "%s,_spx", r->name);
2712       MOVA (r->name);
2713       emitcode ("add", "a,#%d", count);
2714       emitcode ("mov", "_spx,a");
2715     }
2716
2717   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2718     {
2719       if (options.useXstack)
2720         {
2721           emitcode ("mov", "a,(%s+%d)",
2722                     regs390[i].base, 8 * bank + regs390[i].offset);
2723           emitcode ("movx", "@%s,a", r->name);
2724           if (--count)
2725             emitcode ("inc", "%s", r->name);
2726         }
2727       else
2728         emitcode ("push", "(%s+%d)",
2729                   regs390[i].base, 8 * bank + regs390[i].offset);
2730     }
2731
2732   if (ds390_nBitRegs > 0)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("mov", "a,bits");
2737           emitcode ("movx", "@%s,a", r->name);
2738           if (--count)
2739             emitcode ("inc", "%s", r->name);
2740         }
2741       else
2742         {
2743           emitcode ("push", "bits");
2744         }
2745       BitBankUsed = 1;
2746     }
2747
2748   if (pushPsw)
2749     {
2750       if (options.useXstack)
2751         {
2752           emitcode ("mov", "a,psw");
2753           emitcode ("movx", "@%s,a", r->name);
2754         }
2755       else
2756       {
2757         emitcode ("push", "psw");
2758       }
2759
2760       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2761     }
2762
2763   if (aop)
2764     {
2765       freeAsmop (NULL, aop, ic, TRUE);
2766     }
2767
2768   if (ic)
2769   {
2770     ic->bankSaved = 1;
2771   }
2772 }
2773
2774 /*-----------------------------------------------------------------*/
2775 /* unsaveRBank - restores the register bank from stack             */
2776 /*-----------------------------------------------------------------*/
2777 static void
2778 unsaveRBank (int bank, iCode * ic, bool popPsw)
2779 {
2780   int i;
2781   asmop *aop = NULL;
2782   regs *r = NULL;
2783
2784   if (options.useXstack)
2785     {
2786       if (!ic)
2787         {
2788           /* Assume r0 is available for use. */
2789           r = REG_WITH_INDEX (R0_IDX);;
2790         }
2791       else
2792         {
2793           aop = newAsmop (0);
2794           r = getFreePtr (ic, &aop, FALSE);
2795         }
2796       emitcode ("mov", "%s,_spx", r->name);
2797     }
2798
2799   if (popPsw)
2800     {
2801       if (options.useXstack)
2802         {
2803           emitcode ("dec", "%s", r->name);
2804           emitcode ("movx", "a,@%s", r->name);
2805           emitcode ("mov", "psw,a");
2806         }
2807       else
2808       {
2809         emitcode ("pop", "psw");
2810       }
2811     }
2812
2813   if (ds390_nBitRegs > 0)
2814     {
2815       if (options.useXstack)
2816         {
2817           emitcode ("dec", "%s", r->name);
2818           emitcode ("movx", "a,@%s", r->name);
2819           emitcode ("mov", "bits,a");
2820         }
2821       else
2822         {
2823           emitcode ("pop", "bits");
2824         }
2825     }
2826
2827   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2828     {
2829       if (options.useXstack)
2830         {
2831           emitcode ("dec", "%s", r->name);
2832           emitcode ("movx", "a,@%s", r->name);
2833           emitcode ("mov", "(%s+%d),a",
2834                     regs390[i].base, 8 * bank + regs390[i].offset);
2835         }
2836       else
2837         {
2838           emitcode ("pop", "(%s+%d)",
2839                     regs390[i].base, 8 * bank + regs390[i].offset);
2840         }
2841     }
2842
2843   if (options.useXstack)
2844     {
2845       emitcode ("mov", "_spx,%s", r->name);
2846     }
2847
2848   if (aop)
2849     {
2850       freeAsmop (NULL, aop, ic, TRUE);
2851     }
2852 }
2853
2854 /*-----------------------------------------------------------------*/
2855 /* genSend - gen code for SEND                                     */
2856 /*-----------------------------------------------------------------*/
2857 static void genSend(set *sendSet)
2858 {
2859   iCode *sic;
2860   int bit_count = 0;
2861   int sendCount = 0 ;
2862   static int rb1_count = 0;
2863
2864   /* first we do all bit parameters */
2865   for (sic = setFirstItem (sendSet); sic;
2866        sic = setNextItem (sendSet))
2867     {
2868       if (sic->argreg > 12)
2869         {
2870           int bit = sic->argreg-13;
2871
2872           aopOp (IC_LEFT (sic), sic, FALSE,
2873                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2874
2875           /* if left is a literal then
2876              we know what the value is */
2877           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2878             {
2879               if (((int) operandLitValue (IC_LEFT (sic))))
2880                   emitcode ("setb", "b[%d]", bit);
2881               else
2882                   emitcode ("clr", "b[%d]", bit);
2883             }
2884           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2885             {
2886               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2887                 if (strcmp (l, "c"))
2888                     emitcode ("mov", "c,%s", l);
2889                 emitcode ("mov", "b[%d],c", bit);
2890             }
2891           else
2892             {
2893               /* we need to or */
2894               toBoolean (IC_LEFT (sic));
2895               /* set C, if a >= 1 */
2896               emitcode ("add", "a,#0xff");
2897               emitcode ("mov", "b[%d],c", bit);
2898             }
2899           bit_count++;
2900           BitBankUsed = 1;
2901
2902           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2903         }
2904     }
2905
2906   if (bit_count)
2907     {
2908       saveRegisters (setFirstItem (sendSet));
2909       emitcode ("mov", "bits,b");
2910     }
2911
2912   /* then we do all other parameters */
2913   for (sic = setFirstItem (sendSet); sic;
2914        sic = setNextItem (sendSet))
2915     {
2916       if (sic->argreg <= 12)
2917       {
2918         int size, offset = 0;
2919
2920         size = getSize (operandType (IC_LEFT (sic)));
2921         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2922         if (sendCount == 0) { /* first parameter */
2923             // we know that dpl(hxb) is the result, so
2924             rb1_count = 0 ;
2925             _startLazyDPSEvaluation ();
2926             if (size>1) {
2927                 aopOp (IC_LEFT (sic), sic, FALSE,
2928                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2929             } else {
2930                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2931             }
2932             while (size--)
2933               {
2934                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2935                 if (strcmp (l, fReturn[offset]))
2936                   {
2937                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2938                   }
2939                 offset++;
2940               }
2941             _endLazyDPSEvaluation ();
2942             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2943             rb1_count =0;
2944         } else { /* if more parameter in registers */
2945             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2946             while (size--) {
2947                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2948                                                                 FALSE, FALSE, NULL));
2949             }
2950             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2951         }
2952         sendCount++;
2953       }
2954     }
2955 }
2956
2957 static void
2958 adjustEsp(const char *reg)
2959 {
2960     emitcode ("anl","%s,#3", reg);
2961     if (TARGET_IS_DS400)
2962     {
2963         emitcode ("orl","%s,#!constbyte",
2964                   reg,
2965                   (options.stack_loc >> 8) & 0xff);
2966     }
2967 }
2968
2969 /*-----------------------------------------------------------------*/
2970 /* selectRegBank - emit code to select the register bank           */
2971 /*-----------------------------------------------------------------*/
2972 static void
2973 selectRegBank (short bank, bool keepFlags)
2974 {
2975   /* if f.e. result is in carry */
2976   if (keepFlags)
2977     {
2978       emitcode ("anl", "psw,#0xE7");
2979       if (bank)
2980         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2981     }
2982   else
2983     {
2984       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2985     }
2986 }
2987
2988 /*-----------------------------------------------------------------*/
2989 /* genCall - generates a call statement                            */
2990 /*-----------------------------------------------------------------*/
2991 static void
2992 genCall (iCode * ic)
2993 {
2994   sym_link *dtype;
2995   sym_link *etype;
2996   bool restoreBank = FALSE;
2997   bool swapBanks = FALSE;
2998   bool accuse = FALSE;
2999   bool accPushed = FALSE;
3000   bool resultInF0 = FALSE;
3001   bool assignResultGenerated = FALSE;
3002
3003   D (emitcode (";", "genCall"));
3004
3005   /* if we are calling a not _naked function that is not using
3006      the same register bank then we need to save the
3007      destination registers on the stack */
3008   dtype = operandType (IC_LEFT (ic));
3009   etype = getSpec(dtype);
3010   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3011       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3012       IFFUNC_ISISR (currFunc->type))
3013   {
3014       if (!ic->bankSaved)
3015       {
3016            /* This is unexpected; the bank should have been saved in
3017             * genFunction.
3018             */
3019            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3020            restoreBank = TRUE;
3021       }
3022       swapBanks = TRUE;
3023   }
3024
3025   /* if caller saves & we have not saved then */
3026   if (!ic->regsSaved)
3027       saveRegisters (ic);
3028
3029   /* if send set is not empty then assign */
3030   /* We've saved all the registers we care about;
3031   * therefore, we may clobber any register not used
3032   * in the calling convention (i.e. anything not in
3033   * fReturn.
3034   */
3035   if (_G.sendSet)
3036     {
3037         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3038             genSend(reverseSet(_G.sendSet));
3039         } else {
3040             genSend(_G.sendSet);
3041         }
3042       _G.sendSet = NULL;
3043     }
3044
3045   if (swapBanks)
3046     {
3047       emitcode ("mov", "psw,#!constbyte",
3048          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3049     }
3050
3051   /* make the call */
3052   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3053                             OP_SYMBOL (IC_LEFT (ic))->rname :
3054                             OP_SYMBOL (IC_LEFT (ic))->name));
3055
3056   if (swapBanks)
3057     {
3058       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3059     }
3060
3061   /* if we need assign a result value */
3062   if ((IS_ITEMP (IC_RESULT (ic)) &&
3063        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3064        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3065         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3066         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3067       IS_TRUE_SYMOP (IC_RESULT (ic)))
3068     {
3069       if (isOperandInFarSpace (IC_RESULT (ic))
3070           && getSize (operandType (IC_RESULT (ic))) <= 2)
3071         {
3072           int size = getSize (operandType (IC_RESULT (ic)));
3073           bool pushedB = FALSE;
3074
3075           /* Special case for 1 or 2 byte return in far space. */
3076           MOVA (fReturn[0]);
3077           if (size > 1)
3078             {
3079               pushedB = pushB ();
3080               emitcode ("mov", "b,%s", fReturn[1]);
3081             }
3082
3083           _G.accInUse++;
3084           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3085           _G.accInUse--;
3086
3087           popB (pushedB);
3088
3089           aopPut (IC_RESULT (ic), "a", 0);
3090
3091           if (size > 1)
3092             {
3093               aopPut (IC_RESULT (ic), "b", 1);
3094             }
3095           assignResultGenerated = TRUE;
3096           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3097         }
3098       else
3099         {
3100           bool pushedB = pushB ();
3101           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3102           popB (pushedB);
3103
3104           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3105           assignResultGenerated = TRUE;
3106           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3107         }
3108     }
3109
3110   /* adjust the stack for parameters if required */
3111   if (ic->parmBytes)
3112     {
3113       int i;
3114       if (options.stack10bit) {
3115           if (ic->parmBytes <= 10) {
3116               emitcode(";","stack adjustment for parms");
3117               for (i=0; i < ic->parmBytes ; i++) {
3118                   emitcode("pop","acc");
3119               }
3120           } else {
3121               PROTECT_SP;
3122               emitcode ("clr","c");
3123               emitcode ("mov","a,sp");
3124               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3125               emitcode ("mov","sp,a");
3126               emitcode ("mov","a,esp");
3127               adjustEsp("a");
3128               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3129               emitcode ("mov","esp,a");
3130               UNPROTECT_SP;
3131           }
3132       } else {
3133           if (ic->parmBytes > 3)
3134             {
3135               if (accuse)
3136                 {
3137                   emitcode ("push", "acc");
3138                   accPushed = TRUE;
3139                 }
3140               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3141                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3142                   !assignResultGenerated)
3143                 {
3144                   emitcode ("mov", "F0,c");
3145                   resultInF0 = TRUE;
3146                 }
3147
3148               emitcode ("mov", "a,%s", spname);
3149               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3150               emitcode ("mov", "%s,a", spname);
3151
3152               /* unsaveRegisters from xstack needs acc, but */
3153               /* unsaveRegisters from stack needs this popped */
3154               if (accPushed && !options.useXstack)
3155                 {
3156                   emitcode ("pop", "acc");
3157                   accPushed = FALSE;
3158                 }
3159             }
3160           else
3161               for (i = 0; i < ic->parmBytes; i++)
3162                   emitcode ("dec", "%s", spname);
3163       }
3164   }
3165
3166   /* if we had saved some registers then unsave them */
3167   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3168     {
3169       if (accuse && !accPushed && options.useXstack)
3170         {
3171           /* xstack needs acc, but doesn't touch normal stack */
3172           emitcode ("push", "acc");
3173           accPushed = TRUE;
3174         }
3175       unsaveRegisters (ic);
3176     }
3177
3178   /* if register bank was saved then pop them */
3179   if (restoreBank)
3180     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3181
3182   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3183     {
3184       if (resultInF0)
3185           emitcode ("mov", "c,F0");
3186
3187       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3188       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3189       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3190     }
3191
3192   if (accPushed)
3193     emitcode ("pop", "acc");
3194 }
3195
3196 /*-----------------------------------------------------------------*/
3197 /* genPcall - generates a call by pointer statement                */
3198 /*-----------------------------------------------------------------*/
3199 static void
3200 genPcall (iCode * ic)
3201 {
3202   sym_link *dtype;
3203   sym_link *etype;
3204   symbol *rlbl = newiTempLabel (NULL);
3205   bool restoreBank=FALSE;
3206   bool resultInF0 = FALSE;
3207
3208   D (emitcode (";", "genPcall"));
3209
3210   dtype = operandType (IC_LEFT (ic))->next;
3211   etype = getSpec(dtype);
3212   /* if caller saves & we have not saved then */
3213   if (!ic->regsSaved)
3214     saveRegisters (ic);
3215
3216   /* if we are calling a not _naked function that is not using
3217      the same register bank then we need to save the
3218      destination registers on the stack */
3219   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3220       IFFUNC_ISISR (currFunc->type) &&
3221       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3222     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3223     restoreBank=TRUE;
3224   }
3225
3226   /* push the return address on to the stack */
3227   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3228   emitcode ("push", "acc");
3229   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3230   emitcode ("push", "acc");
3231
3232   if (options.model == MODEL_FLAT24)
3233     {
3234       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3235       emitcode ("push", "acc");
3236     }
3237
3238   /* now push the calling address */
3239   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3240
3241   pushSide (IC_LEFT (ic), FPTRSIZE);
3242
3243   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3244
3245   /* if send set is not empty the assign */
3246   if (_G.sendSet)
3247     {
3248         genSend(reverseSet(_G.sendSet));
3249         _G.sendSet = NULL;
3250     }
3251
3252   /* make the call */
3253   emitcode ("ret", "");
3254   emitLabel (rlbl);
3255
3256
3257   /* if we need assign a result value */
3258   if ((IS_ITEMP (IC_RESULT (ic)) &&
3259        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3260        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3261         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3262       IS_TRUE_SYMOP (IC_RESULT (ic)))
3263     {
3264
3265       _G.accInUse++;
3266       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3267       _G.accInUse--;
3268
3269       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3270
3271       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3272     }
3273
3274   /* adjust the stack for parameters if required */
3275   if (ic->parmBytes)
3276     {
3277       int i;
3278       if (options.stack10bit) {
3279           if (ic->parmBytes <= 10) {
3280               emitcode(";","stack adjustment for parms");
3281               for (i=0; i < ic->parmBytes ; i++) {
3282                   emitcode("pop","acc");
3283               }
3284           } else {
3285               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3286                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3287                 {
3288                   emitcode ("mov", "F0,c");
3289                   resultInF0 = TRUE;
3290                 }
3291
3292               PROTECT_SP;
3293               emitcode ("clr","c");
3294               emitcode ("mov","a,sp");
3295               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3296               emitcode ("mov","sp,a");
3297               emitcode ("mov","a,esp");
3298               adjustEsp("a");
3299               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3300               emitcode ("mov","esp,a");
3301               UNPROTECT_SP;
3302           }
3303       } else {
3304           if (ic->parmBytes > 3) {
3305               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3306                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3307                 {
3308                   emitcode ("mov", "F0,c");
3309                   resultInF0 = TRUE;
3310                 }
3311
3312               emitcode ("mov", "a,%s", spname);
3313               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3314               emitcode ("mov", "%s,a", spname);
3315           }
3316           else
3317               for (i = 0; i < ic->parmBytes; i++)
3318                   emitcode ("dec", "%s", spname);
3319       }
3320     }
3321   /* if register bank was saved then unsave them */
3322   if (restoreBank)
3323     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3324
3325   /* if we had saved some registers then unsave them */
3326   if (ic->regsSaved)
3327     unsaveRegisters (ic);
3328
3329   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3330     {
3331       if (resultInF0)
3332           emitcode ("mov", "c,F0");
3333
3334       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3335       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3336       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3337     }
3338 }
3339
3340 /*-----------------------------------------------------------------*/
3341 /* resultRemat - result  is rematerializable                       */
3342 /*-----------------------------------------------------------------*/
3343 static int
3344 resultRemat (iCode * ic)
3345 {
3346   if (SKIP_IC (ic) || ic->op == IFX)
3347     return 0;
3348
3349   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3350     {
3351       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3352       if (sym->remat && !POINTER_SET (ic))
3353         return 1;
3354     }
3355
3356   return 0;
3357 }
3358
3359 /*-----------------------------------------------------------------*/
3360 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3361 /*-----------------------------------------------------------------*/
3362 static int
3363 regsCmp(void *p1, void *p2)
3364 {
3365   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3366 }
3367
3368 static bool
3369 inExcludeList (char *s)
3370 {
3371   const char *p = setFirstItem(options.excludeRegsSet);
3372
3373   if (p == NULL || STRCASECMP(p, "none") == 0)
3374     return FALSE;
3375
3376
3377   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3378 }
3379
3380 /*-----------------------------------------------------------------*/
3381 /* genFunction - generated code for function entry                 */
3382 /*-----------------------------------------------------------------*/
3383 static void
3384 genFunction (iCode * ic)
3385 {
3386   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3387   sym_link *ftype;
3388   bool     switchedPSW = FALSE;
3389   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3390
3391   D (emitcode (";", "genFunction"));
3392
3393   _G.nRegsSaved = 0;
3394   /* create the function header */
3395   emitcode (";", "-----------------------------------------");
3396   emitcode (";", " function %s", sym->name);
3397   emitcode (";", "-----------------------------------------");
3398
3399   emitcode ("", "%s:", sym->rname);
3400   lineCurr->isLabel = 1;
3401   ftype = operandType (IC_LEFT (ic));
3402   _G.currentFunc = sym;
3403
3404   if (IFFUNC_ISNAKED(ftype))
3405   {
3406       emitcode(";", "naked function: no prologue.");
3407       return;
3408   }
3409
3410   if (options.stack_probe)
3411       emitcode ("lcall","__stack_probe");
3412
3413   /* here we need to generate the equates for the
3414      register bank if required */
3415   if (FUNC_REGBANK (ftype) != rbank)
3416     {
3417       int i;
3418
3419       rbank = FUNC_REGBANK (ftype);
3420       for (i = 0; i < ds390_nRegs; i++)
3421         {
3422           if (regs390[i].print) {
3423               if (strcmp (regs390[i].base, "0") == 0)
3424                   emitcode ("", "%s !equ !constbyte",
3425                             regs390[i].dname,
3426                             8 * rbank + regs390[i].offset);
3427               else
3428                   emitcode ("", "%s !equ %s + !constbyte",
3429                             regs390[i].dname,
3430                             regs390[i].base,
3431                             8 * rbank + regs390[i].offset);
3432           }
3433         }
3434     }
3435
3436   /* if this is an interrupt service routine then
3437      save acc, b, dpl, dph  */
3438   if (IFFUNC_ISISR (sym->type))
3439       { /* is ISR */
3440       if (!inExcludeList ("acc"))
3441         emitcode ("push", "acc");
3442       if (!inExcludeList ("b"))
3443         emitcode ("push", "b");
3444       if (!inExcludeList ("dpl"))
3445         emitcode ("push", "dpl");
3446       if (!inExcludeList ("dph"))
3447         emitcode ("push", "dph");
3448       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3449         {
3450           emitcode ("push", "dpx");
3451           /* Make sure we're using standard DPTR */
3452           emitcode ("push", "dps");
3453           emitcode ("mov", "dps,#0");
3454           if (options.stack10bit)
3455             {
3456               /* This ISR could conceivably use DPTR2. Better save it. */
3457               emitcode ("push", "dpl1");
3458               emitcode ("push", "dph1");
3459               emitcode ("push", "dpx1");
3460               emitcode ("push",  DP2_RESULT_REG);
3461             }
3462         }
3463       /* if this isr has no bank i.e. is going to
3464          run with bank 0 , then we need to save more
3465          registers :-) */
3466       if (!FUNC_REGBANK (sym->type))
3467         {
3468             int i;
3469
3470           /* if this function does not call any other
3471              function then we can be economical and
3472              save only those registers that are used */
3473           if (!IFFUNC_HASFCALL(sym->type))
3474             {
3475               /* if any registers used */
3476               if (sym->regsUsed)
3477                 {
3478                   bool bits_pushed = FALSE;
3479                   /* save the registers used */
3480                   for (i = 0; i < sym->regsUsed->size; i++)
3481                     {
3482                       if (bitVectBitValue (sym->regsUsed, i))
3483                         bits_pushed = pushReg (i, bits_pushed);
3484                     }
3485                 }
3486             }
3487           else
3488             {
3489               /* this function has a function call. We cannot
3490                  determine register usage so we will have to push the
3491                  entire bank */
3492               saveRBank (0, ic, FALSE);
3493               if (options.parms_in_bank1) {
3494                   for (i=0; i < 8 ; i++ ) {
3495                       emitcode ("push","%s",rb1regs[i]);
3496                   }
3497               }
3498             }
3499         }
3500         else
3501         {
3502             /* This ISR uses a non-zero bank.
3503              *
3504              * We assume that the bank is available for our
3505              * exclusive use.
3506              *
3507              * However, if this ISR calls a function which uses some
3508              * other bank, we must save that bank entirely.
3509              */
3510             unsigned long banksToSave = 0;
3511
3512             if (IFFUNC_HASFCALL(sym->type))
3513             {
3514
3515 #define MAX_REGISTER_BANKS 4
3516
3517                 iCode *i;
3518                 int ix;
3519
3520                 for (i = ic; i; i = i->next)
3521                 {
3522                     if (i->op == ENDFUNCTION)
3523                     {
3524                         /* we got to the end OK. */
3525                         break;
3526                     }
3527
3528                     if (i->op == CALL)
3529                     {
3530                         sym_link *dtype;
3531
3532                         dtype = operandType (IC_LEFT(i));
3533                         if (dtype
3534                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3535                         {
3536                              /* Mark this bank for saving. */
3537                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3538                              {
3539                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3540                              }
3541                              else
3542                              {
3543                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3544                              }
3545
3546                              /* And note that we don't need to do it in
3547                               * genCall.
3548                               */
3549                              i->bankSaved = 1;
3550                         }
3551                     }
3552                     if (i->op == PCALL)
3553                     {
3554                         /* This is a mess; we have no idea what
3555                          * register bank the called function might
3556                          * use.
3557                          *
3558                          * The only thing I can think of to do is
3559                          * throw a warning and hope.
3560                          */
3561                         werror(W_FUNCPTR_IN_USING_ISR);
3562                     }
3563                 }
3564
3565                 if (banksToSave && options.useXstack)
3566                 {
3567                     /* Since we aren't passing it an ic,
3568                      * saveRBank will assume r0 is available to abuse.
3569                      *
3570                      * So switch to our (trashable) bank now, so
3571                      * the caller's R0 isn't trashed.
3572                      */
3573                     emitcode ("push", "psw");
3574                     emitcode ("mov", "psw,#!constbyte",
3575                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3576                     switchedPSW = TRUE;
3577                 }
3578
3579                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3580                 {
3581                      if (banksToSave & (1 << ix))
3582                      {
3583                          saveRBank(ix, NULL, FALSE);
3584                      }
3585                 }
3586             }
3587             // TODO: this needs a closer look
3588             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3589         }
3590     }
3591   else
3592     {
3593       /* if callee-save to be used for this function
3594          then save the registers being used in this function */
3595       if (IFFUNC_CALLEESAVES(sym->type))
3596         {
3597           int i;
3598
3599           /* if any registers used */
3600           if (sym->regsUsed)
3601             {
3602               bool bits_pushed = FALSE;
3603               /* save the registers used */
3604               for (i = 0; i < sym->regsUsed->size; i++)
3605                 {
3606                   if (bitVectBitValue (sym->regsUsed, i))
3607                     {
3608                       bits_pushed = pushReg (i, bits_pushed);
3609                       _G.nRegsSaved++;
3610                     }
3611                 }
3612             }
3613         }
3614     }
3615
3616   /* set the register bank to the desired value */
3617   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3618    && !switchedPSW)
3619     {
3620       emitcode ("push", "psw");
3621       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3622     }
3623
3624   if (fReentrant &&
3625        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3626       if (options.stack10bit) {
3627           emitcode ("push","_bpx");
3628           emitcode ("push","_bpx+1");
3629           emitcode ("mov","_bpx,%s",spname);
3630           emitcode ("mov","_bpx+1,esp");
3631           adjustEsp("_bpx+1");
3632       } else {
3633           if (options.useXstack)
3634           {
3635               emitcode ("mov", "r0,%s", spname);
3636               emitcode ("mov", "a,_bp");
3637               emitcode ("movx", "@r0,a");
3638               emitcode ("inc", "%s", spname);
3639           } else {
3640               /* set up the stack */
3641               emitcode ("push", "_bp"); /* save the callers stack  */
3642           }
3643           emitcode ("mov", "_bp,%s", spname);
3644       }
3645   }
3646
3647   /* adjust the stack for the function */
3648   if (sym->stack) {
3649       int i = sym->stack;
3650       if (options.stack10bit) {
3651           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3652           assert (sym->recvSize <= 4);
3653           if (sym->stack <= 8) {
3654               while (i--) emitcode ("push","acc");
3655           } else {
3656               PROTECT_SP;
3657               emitcode ("mov","a,sp");
3658               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3659               emitcode ("mov","sp,a");
3660               emitcode ("mov","a,esp");
3661               adjustEsp("a");
3662               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3663               emitcode ("mov","esp,a");
3664               UNPROTECT_SP;
3665           }
3666       } else {
3667           if (i > 256)
3668               werror (W_STACK_OVERFLOW, sym->name);
3669
3670           if (i > 3 && sym->recvSize < 4) {
3671
3672               emitcode ("mov", "a,sp");
3673               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3674               emitcode ("mov", "sp,a");
3675
3676           } else
3677               while (i--)
3678                   emitcode ("inc", "sp");
3679       }
3680   }
3681
3682   if (sym->xstack)
3683     {
3684
3685       emitcode ("mov", "a,_spx");
3686       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3687       emitcode ("mov", "_spx,a");
3688     }
3689
3690   /* if critical function then turn interrupts off */
3691   if (IFFUNC_ISCRITICAL (ftype))
3692     {
3693       symbol *tlbl = newiTempLabel (NULL);
3694       emitcode ("setb", "c");
3695       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3696       emitcode ("clr", "c");
3697       emitLabel (tlbl);
3698       emitcode ("push", "psw"); /* save old ea via c in psw */
3699     }
3700 }
3701
3702 /*-----------------------------------------------------------------*/
3703 /* genEndFunction - generates epilogue for functions               */
3704 /*-----------------------------------------------------------------*/
3705 static void
3706 genEndFunction (iCode * ic)
3707 {
3708   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3709   lineNode *lnp = lineCurr;
3710   bitVect *regsUsed;
3711   bitVect *regsUsedPrologue;
3712   bitVect *regsUnneeded;
3713   int idx;
3714
3715   D (emitcode (";", "genEndFunction"));
3716
3717   _G.currentFunc = NULL;
3718   if (IFFUNC_ISNAKED(sym->type))
3719   {
3720       emitcode(";", "naked function: no epilogue.");
3721       if (options.debug && currFunc)
3722         debugFile->writeEndFunction (currFunc, ic, 0);
3723       return;
3724   }
3725
3726   if (IFFUNC_ISCRITICAL (sym->type))
3727     {
3728       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3729         {
3730           emitcode ("rlc", "a");   /* save c in a */
3731           emitcode ("pop", "psw"); /* restore ea via c in psw */
3732           emitcode ("mov", "ea,c");
3733           emitcode ("rrc", "a");   /* restore c from a */
3734         }
3735       else
3736         {
3737           emitcode ("pop", "psw"); /* restore ea via c in psw */
3738           emitcode ("mov", "ea,c");
3739         }
3740     }
3741
3742   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3743        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3744
3745       if (options.stack10bit) {
3746           PROTECT_SP;
3747           emitcode ("mov", "sp,_bpx", spname);
3748           emitcode ("mov", "esp,_bpx+1", spname);
3749           UNPROTECT_SP;
3750       } else {
3751           emitcode ("mov", "%s,_bp", spname);
3752       }
3753   }
3754
3755   /* if use external stack but some variables were
3756      added to the local stack then decrement the
3757      local stack */
3758   if (options.useXstack && sym->stack) {
3759       emitcode ("mov", "a,sp");
3760       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3761       emitcode ("mov", "sp,a");
3762   }
3763
3764
3765   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3766        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3767
3768       if (options.useXstack) {
3769           emitcode ("mov", "r0,%s", spname);
3770           emitcode ("movx", "a,@r0");
3771           emitcode ("mov", "_bp,a");
3772           emitcode ("dec", "%s", spname);
3773       } else {
3774           if (options.stack10bit) {
3775               emitcode ("pop", "_bpx+1");
3776               emitcode ("pop", "_bpx");
3777           } else {
3778               emitcode ("pop", "_bp");
3779           }
3780       }
3781   }
3782
3783   /* restore the register bank  */
3784   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3785   {
3786     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3787      || !options.useXstack)
3788     {
3789         /* Special case of ISR using non-zero bank with useXstack
3790          * is handled below.
3791          */
3792         emitcode ("pop", "psw");
3793     }
3794   }
3795
3796   if (IFFUNC_ISISR (sym->type))
3797     { /* is ISR */
3798
3799       /* now we need to restore the registers */
3800       /* if this isr has no bank i.e. is going to
3801          run with bank 0 , then we need to save more
3802          registers :-) */
3803       if (!FUNC_REGBANK (sym->type))
3804         {
3805           int i;
3806           /* if this function does not call any other
3807              function then we can be economical and
3808              save only those registers that are used */
3809           if (!IFFUNC_HASFCALL(sym->type))
3810             {
3811               /* if any registers used */
3812               if (sym->regsUsed)
3813                 {
3814                   bool bits_popped = FALSE;
3815                   /* save the registers used */
3816                   for (i = sym->regsUsed->size; i >= 0; i--)
3817                     {
3818                       if (bitVectBitValue (sym->regsUsed, i))
3819                         bits_popped = popReg (i, bits_popped);
3820                     }
3821                 }
3822             }
3823           else
3824             {
3825               /* this function has a function call. We cannot
3826                  determine register usage so we will have to pop the
3827                  entire bank */
3828               if (options.parms_in_bank1) {
3829                   for (i = 7 ; i >= 0 ; i-- ) {
3830                       emitcode ("pop","%s",rb1regs[i]);
3831                   }
3832               }
3833               unsaveRBank (0, ic, FALSE);
3834             }
3835         }
3836       else
3837         {
3838             /* This ISR uses a non-zero bank.
3839              *
3840              * Restore any register banks saved by genFunction
3841              * in reverse order.
3842              */
3843             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3844             int ix;
3845
3846             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3847             {
3848                 if (savedBanks & (1 << ix))
3849                 {
3850                     unsaveRBank(ix, NULL, FALSE);
3851                 }
3852             }
3853
3854             if (options.useXstack)
3855             {
3856                 /* Restore bank AFTER calling unsaveRBank,
3857                  * since it can trash r0.
3858                  */
3859                 emitcode ("pop", "psw");
3860             }
3861         }
3862
3863       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3864         {
3865           if (options.stack10bit)
3866             {
3867               emitcode ("pop", DP2_RESULT_REG);
3868               emitcode ("pop", "dpx1");
3869               emitcode ("pop", "dph1");
3870               emitcode ("pop", "dpl1");
3871             }
3872           emitcode ("pop", "dps");
3873           emitcode ("pop", "dpx");
3874         }
3875       if (!inExcludeList ("dph"))
3876         emitcode ("pop", "dph");
3877       if (!inExcludeList ("dpl"))
3878         emitcode ("pop", "dpl");
3879       if (!inExcludeList ("b"))
3880         emitcode ("pop", "b");
3881       if (!inExcludeList ("acc"))
3882         emitcode ("pop", "acc");
3883
3884       /* if debug then send end of function */
3885       if (options.debug && currFunc)
3886         {
3887           debugFile->writeEndFunction (currFunc, ic, 1);
3888         }
3889
3890       emitcode ("reti", "");
3891     }
3892   else
3893     {
3894       if (IFFUNC_CALLEESAVES(sym->type))
3895         {
3896           int i;
3897
3898           /* if any registers used */
3899           if (sym->regsUsed)
3900             {
3901               /* save the registers used */
3902               for (i = sym->regsUsed->size; i >= 0; i--)
3903                 {
3904                   if (bitVectBitValue (sym->regsUsed, i))
3905                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3906                 }
3907             }
3908         }
3909
3910       /* if debug then send end of function */
3911       if (options.debug && currFunc)
3912         {
3913           debugFile->writeEndFunction (currFunc, ic, 1);
3914         }
3915
3916       emitcode ("ret", "");
3917     }
3918
3919   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3920     return;
3921
3922   /* If this was an interrupt handler using bank 0 that called another */
3923   /* function, then all registers must be saved; nothing to optimized. */
3924   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3925       && !FUNC_REGBANK(sym->type))
3926     return;
3927
3928   /* There are no push/pops to optimize if not callee-saves or ISR */
3929   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3930     return;
3931
3932   /* If there were stack parameters, we cannot optimize without also    */
3933   /* fixing all of the stack offsets; this is too dificult to consider. */
3934   if (FUNC_HASSTACKPARM(sym->type))
3935     return;
3936
3937   /* Compute the registers actually used */
3938   regsUsed = newBitVect (ds390_nRegs);
3939   regsUsedPrologue = newBitVect (ds390_nRegs);
3940   while (lnp)
3941     {
3942       if (lnp->ic && lnp->ic->op == FUNCTION)
3943         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3944       else
3945         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3946
3947       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3948           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3949         break;
3950       if (!lnp->prev)
3951         break;
3952       lnp = lnp->prev;
3953     }
3954
3955   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3956       && !bitVectBitValue (regsUsed, DPS_IDX))
3957     {
3958       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3959     }
3960
3961   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3962       && !bitVectBitValue (regsUsed, CND_IDX))
3963     {
3964       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3965       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3966           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3967         bitVectUnSetBit (regsUsed, CND_IDX);
3968     }
3969   else
3970     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3971
3972   /* If this was an interrupt handler that called another function */
3973   /* function, then assume working registers may be modified by it. */
3974   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3975     {
3976       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3986       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3987     }
3988
3989   /* Remove the unneeded push/pops */
3990   regsUnneeded = newBitVect (ds390_nRegs);
3991   while (lnp)
3992     {
3993       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3994         {
3995           if (!strncmp(lnp->line, "push", 4))
3996             {
3997               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3998               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3999                 {
4000                   connectLine (lnp->prev, lnp->next);
4001                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4002                 }
4003             }
4004           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4005             {
4006               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4007               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4008                 {
4009                   connectLine (lnp->prev, lnp->next);
4010                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4011                 }
4012             }
4013         }
4014       lnp = lnp->next;
4015     }
4016
4017   for (idx = 0; idx < regsUnneeded->size; idx++)
4018     if (bitVectBitValue (regsUnneeded, idx))
4019       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4020
4021   freeBitVect (regsUnneeded);
4022   freeBitVect (regsUsed);
4023   freeBitVect (regsUsedPrologue);
4024 }
4025
4026 /*-----------------------------------------------------------------*/
4027 /* genJavaNativeRet - generate code for return JavaNative          */
4028 /*-----------------------------------------------------------------*/
4029 static void genJavaNativeRet(iCode *ic)
4030 {
4031     int i, size;
4032
4033     aopOp (IC_LEFT (ic), ic, FALSE,
4034            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4035     size = AOP_SIZE (IC_LEFT (ic));
4036
4037     assert (size <= 4);
4038
4039     /* it is assigned to GPR0-R3 then push them */
4040     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4041         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4042         for (i = 0 ; i < size ; i++ ) {
4043             emitcode ("push","%s",
4044                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4045         }
4046         for (i = (size-1) ; i >= 0 ; i--) {
4047             emitcode ("pop","a%s",javaRet[i]);
4048         }
4049     } else {
4050         for (i = 0 ; i < size ; i++)
4051             emitcode ("mov","%s,%s",javaRet[i],
4052                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4053     }
4054     for (i = size ; i < 4 ; i++ )
4055             emitcode ("mov","%s,#0",javaRet[i]);
4056     return;
4057 }
4058
4059 /*-----------------------------------------------------------------*/
4060 /* genRet - generate code for return statement                     */
4061 /*-----------------------------------------------------------------*/
4062 static void
4063 genRet (iCode * ic)
4064 {
4065   int size, offset = 0, pushed = 0;
4066
4067   D (emitcode (";", "genRet"));
4068
4069   /* if we have no return value then
4070      just generate the "ret" */
4071   if (!IC_LEFT (ic))
4072     goto jumpret;
4073
4074   /* if this is a JavaNative function then return
4075      value in different register */
4076   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4077       genJavaNativeRet(ic);
4078       goto jumpret;
4079   }
4080   /* we have something to return then
4081      move the return value into place */
4082   aopOp (IC_LEFT (ic), ic, FALSE,
4083          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4084   size = AOP_SIZE (IC_LEFT (ic));
4085
4086   _startLazyDPSEvaluation ();
4087
4088   if (IS_BIT(_G.currentFunc->etype))
4089     {
4090       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4091       size = 0;
4092     }
4093
4094   while (size--)
4095     {
4096       char *l;
4097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4098         {
4099           l = aopGet (IC_LEFT (ic), offset++,
4100                       FALSE, TRUE, NULL);
4101           emitcode ("push", "%s", l);
4102           pushed++;
4103         }
4104       else
4105         {
4106           /* Since A is the last element of fReturn,
4107            * it is OK to clobber it in the aopGet.
4108            */
4109           l = aopGet (IC_LEFT (ic), offset,
4110                       FALSE, FALSE, NULL);
4111           if (strcmp (fReturn[offset], l))
4112             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4113         }
4114     }
4115   _endLazyDPSEvaluation ();
4116
4117   while (pushed)
4118     {
4119       pushed--;
4120       if (strcmp (fReturn[pushed], "a"))
4121         emitcode ("pop", fReturn[pushed]);
4122       else
4123         emitcode ("pop", "acc");
4124     }
4125   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4126
4127 jumpret:
4128   /* generate a jump to the return label
4129      if the next is not the return statement */
4130   if (!(ic->next && ic->next->op == LABEL &&
4131         IC_LABEL (ic->next) == returnLabel))
4132
4133     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4134
4135 }
4136
4137 /*-----------------------------------------------------------------*/
4138 /* genLabel - generates a label                                    */
4139 /*-----------------------------------------------------------------*/
4140 static void
4141 genLabel (iCode * ic)
4142 {
4143   /* special case never generate */
4144   if (IC_LABEL (ic) == entryLabel)
4145     return;
4146
4147   D (emitcode (";", "genLabel"));
4148
4149   emitLabel (IC_LABEL (ic));
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genGoto - generates a ljmp                                      */
4154 /*-----------------------------------------------------------------*/
4155 static void
4156 genGoto (iCode * ic)
4157 {
4158   D (emitcode (";", "genGoto"));
4159
4160   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4161 }
4162
4163 /*-----------------------------------------------------------------*/
4164 /* findLabelBackwards: walks back through the iCode chain looking  */
4165 /* for the given label. Returns number of iCode instructions     */
4166 /* between that label and given ic.          */
4167 /* Returns zero if label not found.          */
4168 /*-----------------------------------------------------------------*/
4169 static int
4170 findLabelBackwards (iCode * ic, int key)
4171 {
4172   int count = 0;
4173
4174   while (ic->prev)
4175     {
4176       ic = ic->prev;
4177       count++;
4178
4179       /* If we have any pushes or pops, we cannot predict the distance.
4180          I don't like this at all, this should be dealt with in the
4181          back-end */
4182       if (ic->op == IPUSH || ic->op == IPOP) {
4183         return 0;
4184       }
4185
4186       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4187         {
4188           /* printf("findLabelBackwards = %d\n", count); */
4189           return count;
4190         }
4191     }
4192
4193   return 0;
4194 }
4195
4196 /*-----------------------------------------------------------------*/
4197 /* genPlusIncr :- does addition with increment if possible         */
4198 /*-----------------------------------------------------------------*/
4199 static bool
4200 genPlusIncr (iCode * ic)
4201 {
4202   unsigned int icount;
4203   unsigned int size = getDataSize (IC_RESULT (ic));
4204
4205   /* will try to generate an increment */
4206   /* if the right side is not a literal
4207      we cannot */
4208   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4209     return FALSE;
4210
4211   /* if the literal value of the right hand side
4212      is greater than 4 then it is not worth it */
4213   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4214     return FALSE;
4215
4216   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4217       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4218       while (icount--) {
4219           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4220       }
4221       return TRUE;
4222   }
4223   /* if increment 16 bits in register */
4224   if (
4225        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4226        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4227        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4228        (size > 1) &&
4229        (icount == 1))
4230     {
4231       symbol  *tlbl;
4232       int     emitTlbl;
4233       int     labelRange;
4234       char    *l;
4235
4236       /* If the next instruction is a goto and the goto target
4237        * is <= 5 instructions previous to this, we can generate
4238        * jumps straight to that target.
4239        */
4240       if (ic->next && ic->next->op == GOTO
4241           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4242           && labelRange <= 5)
4243         {
4244           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4245           tlbl = IC_LABEL (ic->next);
4246           emitTlbl = 0;
4247         }
4248       else
4249         {
4250           tlbl = newiTempLabel (NULL);
4251           emitTlbl = 1;
4252         }
4253       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4254       emitcode ("inc", "%s", l);
4255
4256       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4257           IS_AOP_PREG (IC_RESULT (ic)))
4258         {
4259           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4260         }
4261       else
4262         {
4263           emitcode ("clr", "a");
4264           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4265         }
4266
4267       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4268       emitcode ("inc", "%s", l);
4269       if (size > 2)
4270         {
4271           if (!strcmp(l, "acc"))
4272             {
4273                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4274             }
4275           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4276                    IS_AOP_PREG (IC_RESULT (ic)))
4277             {
4278                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4279             }
4280           else
4281             {
4282                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4283             }
4284
4285           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4286           emitcode ("inc", "%s", l);
4287         }
4288       if (size > 3)
4289         {
4290           if (!strcmp(l, "acc"))
4291             {
4292                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4293             }
4294           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4295                    IS_AOP_PREG (IC_RESULT (ic)))
4296             {
4297                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4298             }
4299           else
4300             {
4301                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4302             }
4303
4304           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4305           emitcode ("inc", "%s", l);
4306         }
4307
4308       if (emitTlbl)
4309         {
4310           emitLabel (tlbl);
4311         }
4312       return TRUE;
4313     }
4314
4315   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4316       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4317       options.model == MODEL_FLAT24 )
4318     {
4319       if (IC_RESULT(ic)->isGptr)
4320         {
4321           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4322         }
4323       switch (size) {
4324       case 3:
4325           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4326       case 2:
4327           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4328       case 1:
4329           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4330           break;
4331       }
4332       while (icount--)
4333         emitcode ("inc", "dptr");
4334       return TRUE;
4335   }
4336
4337   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4338       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4339       icount <= 5 ) {
4340       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4341       while (icount--)
4342         emitcode ("inc", "dptr");
4343       emitcode ("mov", "dps,#0");
4344       return TRUE;
4345   }
4346
4347   /* if the sizes are greater than 1 then we cannot */
4348   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4349       AOP_SIZE (IC_LEFT (ic)) > 1)
4350     return FALSE;
4351
4352   /* we can if the aops of the left & result match or
4353      if they are in registers and the registers are the
4354      same */
4355   if (
4356        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4357        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4358        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4359     {
4360       if (icount > 3)
4361         {
4362           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4363           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4364           aopPut (IC_RESULT (ic), "a", 0);
4365         }
4366       else
4367         {
4368           _startLazyDPSEvaluation ();
4369           while (icount--)
4370             {
4371               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4372             }
4373           _endLazyDPSEvaluation ();
4374         }
4375
4376       return TRUE;
4377     }
4378
4379   return FALSE;
4380 }
4381
4382 /*-----------------------------------------------------------------*/
4383 /* outBitAcc - output a bit in acc                                 */
4384 /*-----------------------------------------------------------------*/
4385 static void
4386 outBitAcc (operand * result)
4387 {
4388   symbol *tlbl = newiTempLabel (NULL);
4389   /* if the result is a bit */
4390   if (AOP_TYPE (result) == AOP_CRY)
4391     {
4392       aopPut (result, "a", 0);
4393     }
4394   else
4395     {
4396       emitcode ("jz", "!tlabel", tlbl->key + 100);
4397       emitcode ("mov", "a,%s", one);
4398       emitLabel (tlbl);
4399       outAcc (result);
4400     }
4401 }
4402
4403 /*-----------------------------------------------------------------*/
4404 /* genPlusBits - generates code for addition of two bits           */
4405 /*-----------------------------------------------------------------*/
4406 static void
4407 genPlusBits (iCode * ic)
4408 {
4409   D (emitcode (";", "genPlusBits"));
4410
4411   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4412     {
4413       symbol *lbl = newiTempLabel (NULL);
4414       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4415       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4416       emitcode ("cpl", "c");
4417       emitLabel (lbl);
4418       outBitC (IC_RESULT (ic));
4419     }
4420   else
4421     {
4422       emitcode ("clr", "a");
4423       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4424       emitcode ("rlc", "a");
4425       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4426       emitcode ("addc", "a,%s", zero);
4427       outAcc (IC_RESULT (ic));
4428     }
4429 }
4430
4431 static void
4432 adjustArithmeticResult (iCode * ic)
4433 {
4434   if (opIsGptr (IC_RESULT (ic)) &&
4435       opIsGptr (IC_LEFT (ic)) &&
4436       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4437     {
4438       aopPut (IC_RESULT (ic),
4439               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4440               GPTRSIZE - 1);
4441     }
4442
4443   if (opIsGptr (IC_RESULT (ic)) &&
4444       opIsGptr (IC_RIGHT (ic)) &&
4445       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4446     {
4447       aopPut (IC_RESULT (ic),
4448               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4449               GPTRSIZE - 1);
4450     }
4451
4452   if (opIsGptr (IC_RESULT (ic)) &&
4453       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4454       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4455       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4456       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4457     {
4458       char buffer[5];
4459       SNPRINTF (buffer, sizeof(buffer),
4460                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4461       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4462     }
4463 }
4464
4465 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4466 // generates the result if possible. If result is generated, returns TRUE; otherwise
4467 // returns false and caller must deal with fact that result isn't aopOp'd.
4468 bool aopOp3(iCode * ic)
4469 {
4470     bool dp1InUse, dp2InUse;
4471     bool useDp2;
4472
4473     // First, generate the right opcode. DPTR may be used if neither left nor result are
4474     // of type AOP_STR.
4475
4476 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4477 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4478 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4479 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4480 //      );
4481 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4482 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4483 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4484 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4485 //      );
4486
4487     // Right uses DPTR unless left or result is an AOP_STR; however,
4488     // if right is an AOP_STR, it must use DPTR regardless.
4489     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4490      && !AOP_IS_STR (IC_RIGHT (ic)))
4491     {
4492         useDp2 = TRUE;
4493     }
4494     else
4495     {
4496         useDp2 = FALSE;
4497     }
4498
4499     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4500
4501     // if the right used DPTR, left MUST use DPTR2.
4502     // if the right used DPTR2, left MUST use DPTR.
4503     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4504     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4505     // enabling us to assign DPTR to result.
4506
4507     if (AOP_USESDPTR (IC_RIGHT (ic)))
4508     {
4509         useDp2 = TRUE;
4510     }
4511     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4512     {
4513         useDp2 = FALSE;
4514     }
4515     else
4516     {
4517         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4518         {
4519             useDp2 = TRUE;
4520         }
4521         else
4522         {
4523             useDp2 = FALSE;
4524         }
4525     }
4526
4527     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4528
4529
4530     // We've op'd the left & right. So, if left or right are the same operand as result,
4531     // we know aopOp will succeed, and we can just do it & bail.
4532     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4533       {
4534         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4535         return TRUE;
4536       }
4537     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4538       {
4539 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4540         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4541         return TRUE;
4542       }
4543
4544     // Operands may be equivalent (but not equal) if they share a spill location. If
4545     // so, use the same DPTR or DPTR2.
4546     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4547       {
4548         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4549         return TRUE;
4550       }
4551     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4552       {
4553         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4554         return TRUE;
4555       }
4556
4557     // Note which dptrs are currently in use.
4558     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4559     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4560
4561     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4562     // generate it.
4563     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4564     {
4565         return FALSE;
4566     }
4567
4568     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4569     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4570     {
4571         return FALSE;
4572     }
4573
4574     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4575     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4576     {
4577         return FALSE;
4578     }
4579
4580     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4581
4582     // Some sanity checking...
4583     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4584     {
4585         fprintf(stderr,
4586                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4587                 __FILE__, __LINE__, ic->filename, ic->lineno);
4588         emitcode(";", ">>> unexpected DPTR here.");
4589     }
4590
4591     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4592     {
4593         fprintf(stderr,
4594                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4595                 __FILE__, __LINE__, ic->filename, ic->lineno);
4596         emitcode(";", ">>> unexpected DPTR2 here.");
4597     }
4598
4599     return TRUE;
4600 }
4601
4602 // Macro to aopOp all three operands of an ic. If this cannot be done,
4603 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4604 // will be set TRUE. The caller must then handle the case specially, noting
4605 // that the IC_RESULT operand is not aopOp'd.
4606 //
4607 #define AOP_OP_3_NOFATAL(ic, rc) \
4608             do { rc = !aopOp3(ic); } while (0)
4609
4610 // aopOp the left & right operands of an ic.
4611 #define AOP_OP_2(ic) \
4612     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4613     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4614
4615 // convienience macro.
4616 #define AOP_SET_LOCALS(ic) \
4617     left = IC_LEFT(ic); \
4618     right = IC_RIGHT(ic); \
4619     result = IC_RESULT(ic);
4620
4621
4622 // Given an integer value of pushedSize bytes on the stack,
4623 // adjust it to be resultSize bytes, either by discarding
4624 // the most significant bytes or by zero-padding.
4625 //
4626 // On exit from this macro, pushedSize will have been adjusted to
4627 // equal resultSize, and ACC may be trashed.
4628 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4629       /* If the pushed data is bigger than the result,          \
4630        * simply discard unused bytes. Icky, but works.          \
4631        */                                                       \
4632       while (pushedSize > resultSize)                           \
4633       {                                                         \
4634           D (emitcode (";", "discarding unused result byte.")); \
4635           emitcode ("pop", "acc");                              \
4636           pushedSize--;                                         \
4637       }                                                         \
4638       if (pushedSize < resultSize)                              \
4639       {                                                         \
4640           emitcode ("clr", "a");                                \
4641           /* Conversly, we haven't pushed enough here.          \
4642            * just zero-pad, and all is well.                    \
4643            */                                                   \
4644           while (pushedSize < resultSize)                       \
4645           {                                                     \
4646               emitcode("push", "acc");                          \
4647               pushedSize++;                                     \
4648           }                                                     \
4649       }                                                         \
4650       assert(pushedSize == resultSize);
4651
4652 /*-----------------------------------------------------------------*/
4653 /* genPlus - generates code for addition                           */
4654 /*-----------------------------------------------------------------*/
4655 static void
4656 genPlus (iCode * ic)
4657 {
4658   int size, offset = 0;
4659   bool pushResult;
4660   int rSize;
4661   bool swappedLR = FALSE;
4662
4663   D (emitcode (";", "genPlus"));
4664
4665   /* special cases :- */
4666   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4667       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4668       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4669       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4670       if (size <= 9) {
4671           while (size--) emitcode ("inc","dptr");
4672       } else {
4673           emitcode ("mov", "a,dpl");
4674           emitcode ("add", "a,#!constbyte", size & 0xff);
4675           emitcode ("mov", "dpl,a");
4676           emitcode ("mov", "a,dph");
4677           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4678           emitcode ("mov", "dph,a");
4679           emitcode ("mov", "a,dpx");
4680           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4681           emitcode ("mov", "dpx,a");
4682       }
4683       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4684       return ;
4685   }
4686   if ( IS_SYMOP (IC_LEFT (ic)) &&
4687        OP_SYMBOL (IC_LEFT (ic))->remat &&
4688        isOperandInFarSpace (IC_RIGHT (ic))) {
4689       operand *op = IC_RIGHT(ic);
4690       IC_RIGHT(ic) = IC_LEFT(ic);
4691       IC_LEFT(ic) = op;
4692   }
4693
4694   AOP_OP_3_NOFATAL (ic, pushResult);
4695
4696   if (pushResult)
4697     {
4698       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4699     }
4700
4701   if (!pushResult)
4702     {
4703       /* if literal, literal on the right or
4704          if left requires ACC or right is already
4705          in ACC */
4706       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4707           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4708           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4709         {
4710           operand *t = IC_RIGHT (ic);
4711           IC_RIGHT (ic) = IC_LEFT (ic);
4712           IC_LEFT (ic) = t;
4713           swappedLR = TRUE;
4714           D (emitcode (";", "Swapped plus args."));
4715         }
4716
4717       /* if both left & right are in bit
4718          space */
4719       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4720           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4721         {
4722           genPlusBits (ic);
4723           goto release;
4724         }
4725
4726       /* if left in bit space & right literal */
4727       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4728           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4729         {
4730           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4731           /* if result in bit space */
4732           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4733             {
4734               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4735                 emitcode ("cpl", "c");
4736               outBitC (IC_RESULT (ic));
4737             }
4738           else
4739             {
4740               size = getDataSize (IC_RESULT (ic));
4741               _startLazyDPSEvaluation ();
4742               while (size--)
4743                 {
4744                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4745                   emitcode ("addc", "a,%s", zero);
4746                   aopPut (IC_RESULT (ic), "a", offset++);
4747                 }
4748               _endLazyDPSEvaluation ();
4749             }
4750           goto release;
4751         }
4752
4753       /* if I can do an increment instead
4754          of add then GOOD for ME */
4755       if (genPlusIncr (ic) == TRUE)
4756         {
4757           D (emitcode (";", "did genPlusIncr"));
4758           goto release;
4759         }
4760
4761     }
4762   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4763
4764   _startLazyDPSEvaluation ();
4765   while (size--)
4766     {
4767       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4768         {
4769           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4770           if (offset == 0)
4771             emitcode ("add", "a,%s",
4772                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4773           else
4774             emitcode ("addc", "a,%s",
4775                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4776         }
4777       else
4778         {
4779           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4780           {
4781               /* right is going to use ACC or we would have taken the
4782                * above branch.
4783                */
4784               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4785               TR_AP("#3");
4786               D(emitcode(";", "+ AOP_ACC special case."););
4787               emitcode("xch", "a, %s", DP2_RESULT_REG);
4788           }
4789           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4790           if (offset == 0)
4791           {
4792             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4793             {
4794                 TR_AP("#4");
4795                 emitcode("add", "a, %s", DP2_RESULT_REG);
4796             }
4797             else
4798             {
4799                 emitcode ("add", "a,%s",
4800                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4801                                   DP2_RESULT_REG));
4802             }
4803           }
4804           else
4805           {
4806             emitcode ("addc", "a,%s",
4807                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4808                           DP2_RESULT_REG));
4809           }
4810         }
4811       if (!pushResult)
4812         {
4813           aopPut (IC_RESULT (ic), "a", offset);
4814         }
4815       else
4816         {
4817           emitcode ("push", "acc");
4818         }
4819       offset++;
4820     }
4821   _endLazyDPSEvaluation ();
4822
4823   if (pushResult)
4824     {
4825       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4826
4827       size = getDataSize (IC_LEFT (ic));
4828       rSize = getDataSize (IC_RESULT (ic));
4829
4830       ADJUST_PUSHED_RESULT(size, rSize);
4831
4832       _startLazyDPSEvaluation ();
4833       while (size--)
4834         {
4835           emitcode ("pop", "acc");
4836           aopPut (IC_RESULT (ic), "a", size);
4837         }
4838       _endLazyDPSEvaluation ();
4839     }
4840
4841   adjustArithmeticResult (ic);
4842
4843 release:
4844   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4845   if (!swappedLR)
4846     {
4847       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4848       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4849     }
4850   else
4851     {
4852       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4853       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4854     }
4855 }
4856
4857 /*-----------------------------------------------------------------*/
4858 /* genMinusDec :- does subtraction with decrement if possible      */
4859 /*-----------------------------------------------------------------*/
4860 static bool
4861 genMinusDec (iCode * ic)
4862 {
4863   unsigned int icount;
4864   unsigned int size = getDataSize (IC_RESULT (ic));
4865
4866   /* will try to generate an increment */
4867   /* if the right side is not a literal
4868      we cannot */
4869   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4870     return FALSE;
4871
4872   /* if the literal value of the right hand side
4873      is greater than 4 then it is not worth it */
4874   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4875     return FALSE;
4876
4877   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4878       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4879       while (icount--) {
4880           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4881       }
4882       return TRUE;
4883   }
4884   /* if decrement 16 bits in register */
4885   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4886       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4887       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4888       (size > 1) &&
4889       (icount == 1))
4890     {
4891       symbol *tlbl;
4892       int    emitTlbl;
4893       int    labelRange;
4894       char   *l;
4895
4896       /* If the next instruction is a goto and the goto target
4897          * is <= 5 instructions previous to this, we can generate
4898          * jumps straight to that target.
4899        */
4900       if (ic->next && ic->next->op == GOTO
4901           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4902           && labelRange <= 5)
4903         {
4904           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4905           tlbl = IC_LABEL (ic->next);
4906           emitTlbl = 0;
4907         }
4908       else
4909         {
4910           tlbl = newiTempLabel (NULL);
4911           emitTlbl = 1;
4912         }
4913
4914       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4915       emitcode ("dec", "%s", l);
4916
4917       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4918           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4919           IS_AOP_PREG (IC_RESULT (ic)))
4920       {
4921           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4922       }
4923       else
4924       {
4925           emitcode ("mov", "a,#!constbyte",0xff);
4926           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4927       }
4928       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4929       emitcode ("dec", "%s", l);
4930       if (size > 2)
4931         {
4932             if (!strcmp(l, "acc"))
4933             {
4934                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4935             }
4936             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4937                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4938                      IS_AOP_PREG (IC_RESULT (ic)))
4939             {
4940                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4941             }
4942             else
4943             {
4944                 emitcode ("mov", "a,#!constbyte",0xff);
4945                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4946             }
4947             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4948             emitcode ("dec", "%s", l);
4949         }
4950       if (size > 3)
4951         {
4952             if (!strcmp(l, "acc"))
4953             {
4954                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4955             }
4956             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4957                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4958                      IS_AOP_PREG (IC_RESULT (ic)))
4959             {
4960                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4961             }
4962             else
4963             {
4964                 emitcode ("mov", "a,#!constbyte",0xff);
4965                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4966             }
4967             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4968             emitcode ("dec", "%s", l);
4969         }
4970       if (emitTlbl)
4971         {
4972           emitLabel (tlbl);
4973         }
4974       return TRUE;
4975     }
4976
4977   /* if the sizes are greater than 1 then we cannot */
4978   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4979       AOP_SIZE (IC_LEFT (ic)) > 1)
4980     return FALSE;
4981
4982   /* we can if the aops of the left & result match or
4983      if they are in registers and the registers are the
4984      same */
4985   if (
4986        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4987        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4988        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4989     {
4990       char *l;
4991
4992       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4993         {
4994           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4995           l = "a";
4996         }
4997       else
4998         {
4999           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5000         }
5001
5002       _startLazyDPSEvaluation ();
5003       while (icount--)
5004         {
5005           emitcode ("dec", "%s", l);
5006         }
5007       _endLazyDPSEvaluation ();
5008
5009       if (AOP_NEEDSACC (IC_RESULT (ic)))
5010         aopPut (IC_RESULT (ic), "a", 0);
5011
5012       return TRUE;
5013     }
5014
5015   return FALSE;
5016 }
5017
5018 /*-----------------------------------------------------------------*/
5019 /* addSign - complete with sign                                    */
5020 /*-----------------------------------------------------------------*/
5021 static void
5022 addSign (operand * result, int offset, int sign)
5023 {
5024   int size = (getDataSize (result) - offset);
5025   if (size > 0)
5026     {
5027       _startLazyDPSEvaluation();
5028       if (sign)
5029         {
5030           emitcode ("rlc", "a");
5031           emitcode ("subb", "a,acc");
5032           while (size--)
5033             {
5034               aopPut (result, "a", offset++);
5035             }
5036         }
5037       else
5038       {
5039         while (size--)
5040         {
5041           aopPut (result, zero, offset++);
5042         }
5043       }
5044       _endLazyDPSEvaluation();
5045     }
5046 }
5047
5048 /*-----------------------------------------------------------------*/
5049 /* genMinusBits - generates code for subtraction  of two bits      */
5050 /*-----------------------------------------------------------------*/
5051 static void
5052 genMinusBits (iCode * ic)
5053 {
5054   symbol *lbl = newiTempLabel (NULL);
5055
5056   D (emitcode (";", "genMinusBits"));
5057
5058   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5059     {
5060       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5061       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5062       emitcode ("cpl", "c");
5063       emitLabel (lbl);
5064       outBitC (IC_RESULT (ic));
5065     }
5066   else
5067     {
5068       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5069       emitcode ("subb", "a,acc");
5070       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5071       emitcode ("inc", "a");
5072       emitLabel (lbl);
5073       aopPut (IC_RESULT (ic), "a", 0);
5074       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5075     }
5076 }
5077
5078 /*-----------------------------------------------------------------*/
5079 /* genMinus - generates code for subtraction                       */
5080 /*-----------------------------------------------------------------*/
5081 static void
5082 genMinus (iCode * ic)
5083 {
5084     int size, offset = 0;
5085     int rSize;
5086     long lit = 0L;
5087     bool pushResult;
5088
5089     D (emitcode (";", "genMinus"));
5090
5091     AOP_OP_3_NOFATAL(ic, pushResult);
5092
5093     if (!pushResult)
5094     {
5095       /* special cases :- */
5096       /* if both left & right are in bit space */
5097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5098           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5099         {
5100           genMinusBits (ic);
5101           goto release;
5102         }
5103
5104       /* if I can do an decrement instead
5105          of subtract then GOOD for ME */
5106       if (genMinusDec (ic) == TRUE)
5107         goto release;
5108
5109     }
5110
5111   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5112
5113   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5114     {
5115       CLRC;
5116     }
5117   else
5118     {
5119       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5120       lit = -lit;
5121     }
5122
5123
5124   /* if literal, add a,#-lit, else normal subb */
5125   _startLazyDPSEvaluation ();
5126   while (size--) {
5127       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5128           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5129               emitcode ("mov","b,%s",
5130                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5131               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5132               emitcode ("subb","a,b");
5133           } else {
5134               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5135               emitcode ("subb", "a,%s",
5136                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5137                                 DP2_RESULT_REG));
5138           }
5139       } else {
5140           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5141           /* first add without previous c */
5142           if (!offset) {
5143               if (!size && lit==-1) {
5144                   emitcode ("dec", "a");
5145               } else {
5146                   emitcode ("add", "a,#!constbyte",
5147                             (unsigned int) (lit & 0x0FFL));
5148               }
5149           } else {
5150               emitcode ("addc", "a,#!constbyte",
5151                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5152           }
5153       }
5154
5155       if (pushResult) {
5156           emitcode ("push", "acc");
5157       } else {
5158           aopPut (IC_RESULT (ic), "a", offset);
5159       }
5160       offset++;
5161   }
5162   _endLazyDPSEvaluation ();
5163
5164   if (pushResult)
5165     {
5166       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5167
5168       size = getDataSize (IC_LEFT (ic));
5169       rSize = getDataSize (IC_RESULT (ic));
5170
5171       ADJUST_PUSHED_RESULT(size, rSize);
5172
5173       _startLazyDPSEvaluation ();
5174       while (size--)
5175         {
5176           emitcode ("pop", "acc");
5177           aopPut (IC_RESULT (ic), "a", size);
5178         }
5179       _endLazyDPSEvaluation ();
5180     }
5181
5182   adjustArithmeticResult (ic);
5183
5184 release:
5185   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5186   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5187   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5188 }
5189
5190
5191 /*-----------------------------------------------------------------*/
5192 /* genMultbits :- multiplication of bits                           */
5193 /*-----------------------------------------------------------------*/
5194 static void
5195 genMultbits (operand * left,
5196              operand * right,
5197              operand * result,
5198              iCode   * ic)
5199 {
5200   D (emitcode (";", "genMultbits"));
5201
5202   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5203   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5204   aopOp(result, ic, TRUE, FALSE);
5205   outBitC (result);
5206 }
5207
5208 /*-----------------------------------------------------------------*/
5209 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5210 /*-----------------------------------------------------------------*/
5211 static void
5212 genMultOneByte (operand * left,
5213                 operand * right,
5214                 operand * result,
5215                 iCode   * ic)
5216 {
5217   symbol *lbl;
5218   int size;
5219   bool runtimeSign, compiletimeSign;
5220   bool lUnsigned, rUnsigned, pushedB;
5221
5222   /* (if two literals: the value is computed before) */
5223   /* if one literal, literal on the right */
5224   if (AOP_TYPE (left) == AOP_LIT)
5225     {
5226       operand *t = right;
5227       right = left;
5228       left = t;
5229       /* emitcode (";", "swapped left and right"); */
5230     }
5231   /* if no literal, unsigned on the right: shorter code */
5232   if (   AOP_TYPE (right) != AOP_LIT
5233       && SPEC_USIGN (getSpec (operandType (left))))
5234     {
5235       operand *t = right;
5236       right = left;
5237       left = t;
5238     }
5239
5240   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5241   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5242
5243   pushedB = pushB ();
5244
5245   if ((lUnsigned && rUnsigned)
5246 /* sorry, I don't know how to get size
5247    without calling aopOp (result,...);
5248    see Feature Request  */
5249       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5250                    no need to take care about the signedness! */
5251     {
5252       /* just an unsigned 8 * 8 = 8 multiply
5253          or 8u * 8u = 16u */
5254       /* emitcode (";","unsigned"); */
5255       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5256       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5257       emitcode ("mul", "ab");
5258
5259       _G.accInUse++;
5260       aopOp (result, ic, TRUE, FALSE);
5261       size = AOP_SIZE (result);
5262
5263       if (size < 1 || size > 2)
5264         {
5265           /* this should never happen */
5266           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5267                    size, __FILE__, lineno);
5268           exit (1);
5269         }
5270
5271       aopPut (result, "a", 0);
5272       _G.accInUse--;
5273       if (size == 2)
5274         aopPut (result, "b", 1);
5275
5276       popB (pushedB);
5277       return;
5278     }
5279
5280   /* we have to do a signed multiply */
5281   /* emitcode (";", "signed"); */
5282
5283   /* now sign adjust for both left & right */
5284
5285   /* let's see what's needed: */
5286   /* apply negative sign during runtime */
5287   runtimeSign = FALSE;
5288   /* negative sign from literals */
5289   compiletimeSign = FALSE;
5290
5291   if (!lUnsigned)
5292     {
5293       if (AOP_TYPE(left) == AOP_LIT)
5294         {
5295           /* signed literal */
5296           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5297           if (val < 0)
5298             compiletimeSign = TRUE;
5299         }
5300       else
5301         /* signed but not literal */
5302         runtimeSign = TRUE;
5303     }
5304
5305   if (!rUnsigned)
5306     {
5307       if (AOP_TYPE(right) == AOP_LIT)
5308         {
5309           /* signed literal */
5310           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5311           if (val < 0)
5312             compiletimeSign ^= TRUE;
5313         }
5314       else
5315         /* signed but not literal */
5316         runtimeSign = TRUE;
5317     }
5318
5319   /* initialize F0, which stores the runtime sign */
5320   if (runtimeSign)
5321     {
5322       if (compiletimeSign)
5323         emitcode ("setb", "F0"); /* set sign flag */
5324       else
5325         emitcode ("clr", "F0"); /* reset sign flag */
5326     }
5327
5328   /* save the signs of the operands */
5329   if (AOP_TYPE(right) == AOP_LIT)
5330     {
5331       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5332
5333       if (!rUnsigned && val < 0)
5334         emitcode ("mov", "b,#!constbyte", -val);
5335       else
5336         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5337     }
5338   else /* ! literal */
5339     {
5340       if (rUnsigned)  /* emitcode (";", "signed"); */
5341         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5342       else
5343         {
5344           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5345           lbl = newiTempLabel (NULL);
5346           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5347           emitcode ("cpl", "F0"); /* complement sign flag */
5348           emitcode ("cpl", "a");  /* 2's complement */
5349           emitcode ("inc", "a");
5350           emitLabel (lbl);
5351           emitcode ("mov", "b,a");
5352         }
5353     }
5354
5355   if (AOP_TYPE(left) == AOP_LIT)
5356     {
5357       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5358
5359       if (!lUnsigned && val < 0)
5360         emitcode ("mov", "a,#!constbyte", -val);
5361       else
5362         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5363     }
5364   else /* ! literal */
5365     {
5366       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5367
5368       if (!lUnsigned)  /* emitcode (";", "signed"); */
5369         {
5370           lbl = newiTempLabel (NULL);
5371           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5372           emitcode ("cpl", "F0"); /* complement sign flag */
5373           emitcode ("cpl", "a");  /* 2's complement */
5374           emitcode ("inc", "a");
5375           emitLabel (lbl);
5376         }
5377     }
5378
5379   /* now the multiplication */
5380   emitcode ("mul", "ab");
5381   _G.accInUse++;
5382   aopOp(result, ic, TRUE, FALSE);
5383   size = AOP_SIZE (result);
5384
5385   if (size < 1 || size > 2)
5386     {
5387       /* this should never happen */
5388       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5389                size, __FILE__, lineno);
5390       exit (1);
5391     }
5392
5393   if (runtimeSign || compiletimeSign)
5394     {
5395       lbl = newiTempLabel (NULL);
5396       if (runtimeSign)
5397         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5398       emitcode ("cpl", "a"); /* lsb 2's complement */
5399       if (size != 2)
5400         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5401       else
5402         {
5403           emitcode ("add", "a,#1"); /* this sets carry flag */
5404           emitcode ("xch", "a,b");
5405           emitcode ("cpl", "a"); /* msb 2's complement */
5406           emitcode ("addc", "a,#0");
5407           emitcode ("xch", "a,b");
5408         }
5409       emitLabel (lbl);
5410     }
5411   aopPut (result, "a", 0);
5412   _G.accInUse--;
5413   if (size == 2)
5414     aopPut (result, "b", 1);
5415
5416   popB (pushedB);
5417 }
5418
5419 /*-----------------------------------------------------------------*/
5420 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5421 /*-----------------------------------------------------------------*/
5422 static void genMultTwoByte (operand *left, operand *right,
5423                             operand *result, iCode *ic)
5424 {
5425         sym_link *retype = getSpec(operandType(right));
5426         sym_link *letype = getSpec(operandType(left));
5427         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5428         symbol *lbl;
5429
5430         if (AOP_TYPE (left) == AOP_LIT) {
5431                 operand *t = right;
5432                 right = left;
5433                 left = t;
5434         }
5435         /* save EA bit in F1 */
5436         lbl = newiTempLabel(NULL);
5437         emitcode ("setb","F1");
5438         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5439         emitcode ("clr","F1");
5440         emitLabel (lbl);
5441
5442         /* load up MB with right */
5443         if (!umult) {
5444                 emitcode("clr","F0");
5445                 if (AOP_TYPE(right) == AOP_LIT) {
5446                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5447                         if (val < 0) {
5448                                 emitcode("setb","F0");
5449                                 val = -val;
5450                         }
5451                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5452                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5453                 } else {
5454                         lbl = newiTempLabel(NULL);
5455                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5456                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5457                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5458                         emitcode ("xch", "a,b");
5459                         emitcode ("cpl","a");
5460                         emitcode ("add", "a,#1");
5461                         emitcode ("xch", "a,b");
5462                         emitcode ("cpl", "a"); // msb
5463                         emitcode ("addc", "a,#0");
5464                         emitcode ("setb","F0");
5465                         emitLabel (lbl);
5466                         emitcode ("mov","mb,b");
5467                         emitcode ("mov","mb,a");
5468                 }
5469         } else {
5470                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5471                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5472         }
5473         /* load up MA with left */
5474         if (!umult) {
5475                 lbl = newiTempLabel(NULL);
5476                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5477                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5478                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5479                 emitcode ("xch", "a,b");
5480                 emitcode ("cpl","a");
5481                 emitcode ("add", "a,#1");
5482                 emitcode ("xch", "a,b");
5483                 emitcode ("cpl", "a"); // msb
5484                 emitcode ("addc","a,#0");
5485                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5486                 emitcode ("setb","F0");
5487                 emitLabel (lbl);
5488                 emitcode ("mov","ma,b");
5489                 emitcode ("mov","ma,a");
5490         } else {
5491                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5492                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5493         }
5494         /* wait for multiplication to finish */
5495         lbl = newiTempLabel(NULL);
5496         emitLabel (lbl);
5497         emitcode("mov","a,mcnt1");
5498         emitcode("anl","a,#!constbyte",0x80);
5499         emitcode("jnz","!tlabel",lbl->key+100);
5500
5501         freeAsmop (left, NULL, ic, TRUE);
5502         freeAsmop (right, NULL, ic,TRUE);
5503         aopOp(result, ic, TRUE, FALSE);
5504
5505         /* if unsigned then simple */
5506         if (umult) {
5507                 emitcode ("mov","a,ma");
5508                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5509                 emitcode ("mov","a,ma");
5510                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5511                 aopPut(result,"ma",1);
5512                 aopPut(result,"ma",0);
5513         } else {
5514                 emitcode("push","ma");
5515                 emitcode("push","ma");
5516                 emitcode("push","ma");
5517                 MOVA("ma");
5518                 /* negate result if needed */
5519                 lbl = newiTempLabel(NULL);
5520                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5521                 emitcode("cpl","a");
5522                 emitcode("add","a,#1");
5523                 emitLabel (lbl);
5524                 if (AOP_TYPE(result) == AOP_ACC)
5525                 {
5526                     D (emitcode(";", "ACC special case."));
5527                     /* We know result is the only live aop, and
5528                      * it's obviously not a DPTR2, so AP is available.
5529                      */
5530                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5531                 }
5532                 else
5533                 {
5534                     aopPut(result,"a",0);
5535                 }
5536
5537                 emitcode("pop","acc");
5538                 lbl = newiTempLabel(NULL);
5539                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5540                 emitcode("cpl","a");
5541                 emitcode("addc","a,#0");
5542                 emitLabel (lbl);
5543                 aopPut(result,"a",1);
5544                 emitcode("pop","acc");
5545                 if (AOP_SIZE(result) >= 3) {
5546                         lbl = newiTempLabel(NULL);
5547                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5548                         emitcode("cpl","a");
5549                         emitcode("addc","a,#0");
5550                         emitLabel (lbl);
5551                         aopPut(result,"a",2);
5552                 }
5553                 emitcode("pop","acc");
5554                 if (AOP_SIZE(result) >= 4) {
5555                         lbl = newiTempLabel(NULL);
5556                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                         emitcode("cpl","a");
5558                         emitcode("addc","a,#0");
5559                         emitLabel (lbl);
5560                         aopPut(result,"a",3);
5561                 }
5562                 if (AOP_TYPE(result) == AOP_ACC)
5563                 {
5564                     /* We stashed the result away above. */
5565                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5566                 }
5567
5568         }
5569         freeAsmop (result, NULL, ic, TRUE);
5570
5571         /* restore EA bit in F1 */
5572         lbl = newiTempLabel(NULL);
5573         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5574         emitcode ("setb","EA");
5575         emitLabel (lbl);
5576         return ;
5577 }
5578
5579 /*-----------------------------------------------------------------*/
5580 /* genMult - generates code for multiplication                     */
5581 /*-----------------------------------------------------------------*/
5582 static void
5583 genMult (iCode * ic)
5584 {
5585   operand *left = IC_LEFT (ic);
5586   operand *right = IC_RIGHT (ic);
5587   operand *result = IC_RESULT (ic);
5588
5589   D (emitcode (";", "genMult"));
5590
5591   /* assign the asmops */
5592   AOP_OP_2 (ic);
5593
5594   /* special cases first */
5595   /* both are bits */
5596   if (AOP_TYPE (left) == AOP_CRY &&
5597       AOP_TYPE (right) == AOP_CRY)
5598     {
5599       genMultbits (left, right, result, ic);
5600       goto release;
5601     }
5602
5603   /* if both are of size == 1 */
5604   if (AOP_SIZE (left) == 1 &&
5605       AOP_SIZE (right) == 1)
5606     {
5607       genMultOneByte (left, right, result, ic);
5608       goto release;
5609     }
5610
5611   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5612           /* use the ds390 ARITHMETIC accel UNIT */
5613           genMultTwoByte (left, right, result, ic);
5614           return ;
5615   }
5616   /* should have been converted to function call */
5617   assert (0);
5618
5619 release:
5620   freeAsmop (result, NULL, ic, TRUE);
5621   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5622   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5623 }
5624
5625 /*-----------------------------------------------------------------*/
5626 /* genDivbits :- division of bits                                  */
5627 /*-----------------------------------------------------------------*/
5628 static void
5629 genDivbits (operand * left,
5630             operand * right,
5631             operand * result,
5632             iCode   * ic)
5633 {
5634   char *l;
5635   bool pushedB;
5636
5637   D(emitcode (";", "genDivbits"));
5638
5639   pushedB = pushB ();
5640
5641   /* the result must be bit */
5642   LOAD_AB_FOR_DIV (left, right, l);
5643   emitcode ("div", "ab");
5644   emitcode ("rrc", "a");
5645   aopOp(result, ic, TRUE, FALSE);
5646
5647   popB (pushedB);
5648
5649   aopPut (result, "c", 0);
5650 }
5651
5652 /*-----------------------------------------------------------------*/
5653 /* genDivOneByte : 8 bit division                                  */
5654 /*-----------------------------------------------------------------*/
5655 static void
5656 genDivOneByte (operand * left,
5657                operand * right,
5658                operand * result,
5659                iCode   * ic)
5660 {
5661   bool lUnsigned, rUnsigned, pushedB;
5662   bool runtimeSign, compiletimeSign;
5663   char *l;
5664   symbol *lbl;
5665   int size, offset;
5666
5667   D(emitcode (";", "genDivOneByte"));
5668
5669   offset = 1;
5670   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5671   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5672
5673   pushedB = pushB ();
5674
5675   /* signed or unsigned */
5676   if (lUnsigned && rUnsigned)
5677     {
5678       /* unsigned is easy */
5679       LOAD_AB_FOR_DIV (left, right, l);
5680       emitcode ("div", "ab");
5681
5682       _G.accInUse++;
5683       aopOp (result, ic, TRUE, FALSE);
5684       aopPut (result, "a", 0);
5685       _G.accInUse--;
5686
5687       size = AOP_SIZE (result) - 1;
5688
5689       while (size--)
5690         aopPut (result, zero, offset++);
5691
5692       popB (pushedB);
5693       return;
5694     }
5695
5696   /* signed is a little bit more difficult */
5697
5698   /* now sign adjust for both left & right */
5699
5700   /* let's see what's needed: */
5701   /* apply negative sign during runtime */
5702   runtimeSign = FALSE;
5703   /* negative sign from literals */
5704   compiletimeSign = FALSE;
5705
5706   if (!lUnsigned)
5707     {
5708       if (AOP_TYPE(left) == AOP_LIT)
5709         {
5710           /* signed literal */
5711           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5712           if (val < 0)
5713             compiletimeSign = TRUE;
5714         }
5715       else
5716         /* signed but not literal */
5717         runtimeSign = TRUE;
5718     }
5719
5720   if (!rUnsigned)
5721     {
5722       if (AOP_TYPE(right) == AOP_LIT)
5723         {
5724           /* signed literal */
5725           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5726           if (val < 0)
5727             compiletimeSign ^= TRUE;
5728         }
5729       else
5730         /* signed but not literal */
5731         runtimeSign = TRUE;
5732     }
5733
5734   /* initialize F0, which stores the runtime sign */
5735   if (runtimeSign)
5736     {
5737       if (compiletimeSign)
5738         emitcode ("setb", "F0"); /* set sign flag */
5739       else
5740         emitcode ("clr", "F0"); /* reset sign flag */
5741     }
5742
5743   /* save the signs of the operands */
5744   if (AOP_TYPE(right) == AOP_LIT)
5745     {
5746       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5747
5748       if (!rUnsigned && val < 0)
5749         emitcode ("mov", "b,#0x%02x", -val);
5750       else
5751         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5752     }
5753   else /* ! literal */
5754     {
5755       if (rUnsigned)
5756         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5757       else
5758         {
5759           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5760           lbl = newiTempLabel (NULL);
5761           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5762           emitcode ("cpl", "F0"); /* complement sign flag */
5763           emitcode ("cpl", "a");  /* 2's complement */
5764           emitcode ("inc", "a");
5765           emitLabel (lbl);
5766           emitcode ("mov", "b,a");
5767         }
5768     }
5769
5770   if (AOP_TYPE(left) == AOP_LIT)
5771     {
5772       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5773
5774       if (!lUnsigned && val < 0)
5775         emitcode ("mov", "a,#0x%02x", -val);
5776       else
5777         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5778     }
5779   else /* ! literal */
5780     {
5781       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5782
5783       if (!lUnsigned)
5784         {
5785           lbl = newiTempLabel (NULL);
5786           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5787           emitcode ("cpl", "F0"); /* complement sign flag */
5788           emitcode ("cpl", "a");  /* 2's complement */
5789           emitcode ("inc", "a");
5790           emitLabel (lbl);
5791         }
5792     }
5793
5794   /* now the division */
5795   emitcode ("nop", "; workaround for DS80C390 div bug.");
5796   emitcode ("div", "ab");
5797
5798   if (runtimeSign || compiletimeSign)
5799     {
5800       lbl = newiTempLabel (NULL);
5801       if (runtimeSign)
5802         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5803       emitcode ("cpl", "a"); /* lsb 2's complement */
5804       emitcode ("inc", "a");
5805       emitLabel (lbl);
5806
5807       _G.accInUse++;
5808       aopOp (result, ic, TRUE, FALSE);
5809       size = AOP_SIZE (result) - 1;
5810
5811       if (size > 0)
5812         {
5813           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5814              then the result will be in b, a */
5815           emitcode ("mov", "b,a"); /* 1 */
5816           /* msb is 0x00 or 0xff depending on the sign */
5817           if (runtimeSign)
5818             {
5819               emitcode ("mov",  "c,F0");
5820               emitcode ("subb", "a,acc");
5821               emitcode ("xch",  "a,b"); /* 2 */
5822               while (size--)
5823                 aopPut (result, "b", offset++); /* write msb's */
5824             }
5825           else /* compiletimeSign */
5826             while (size--)
5827               aopPut (result, "#0xff", offset++); /* write msb's */
5828         }
5829       aopPut (result, "a", 0); /* 3: write lsb */
5830     }
5831   else
5832     {
5833       _G.accInUse++;
5834       aopOp(result, ic, TRUE, FALSE);
5835       size = AOP_SIZE (result) - 1;
5836
5837       aopPut (result, "a", 0);
5838       while (size--)
5839         aopPut (result, zero, offset++);
5840     }
5841   _G.accInUse--;
5842   popB (pushedB);
5843 }
5844
5845 /*-----------------------------------------------------------------*/
5846 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5847 /*-----------------------------------------------------------------*/
5848 static void genDivTwoByte (operand *left, operand *right,
5849                             operand *result, iCode *ic)
5850 {
5851         sym_link *retype = getSpec(operandType(right));
5852         sym_link *letype = getSpec(operandType(left));
5853         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5854         symbol *lbl;
5855
5856         /* save EA bit in F1 */
5857         lbl = newiTempLabel(NULL);
5858         emitcode ("setb","F1");
5859         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5860         emitcode ("clr","F1");
5861         emitLabel (lbl);
5862
5863         /* load up MA with left */
5864         if (!umult) {
5865                 emitcode("clr","F0");
5866                 lbl = newiTempLabel(NULL);
5867                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5868                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5869                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5870                 emitcode ("xch", "a,b");
5871                 emitcode ("cpl","a");
5872                 emitcode ("add", "a,#1");
5873                 emitcode ("xch", "a,b");
5874                 emitcode ("cpl", "a"); // msb
5875                 emitcode ("addc","a,#0");
5876                 emitcode ("setb","F0");
5877                 emitLabel (lbl);
5878                 emitcode ("mov","ma,b");
5879                 emitcode ("mov","ma,a");
5880         } else {
5881                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5882                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5883         }
5884
5885         /* load up MB with right */
5886         if (!umult) {
5887                 if (AOP_TYPE(right) == AOP_LIT) {
5888                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5889                         if (val < 0) {
5890                                 lbl = newiTempLabel(NULL);
5891                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5892                                 emitcode("setb","F0");
5893                                 emitLabel (lbl);
5894                                 val = -val;
5895                         }
5896                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5897                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5898                 } else {
5899                         lbl = newiTempLabel(NULL);
5900                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5901                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5902                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5903                         emitcode ("xch", "a,b");
5904                         emitcode ("cpl","a");
5905                         emitcode ("add", "a,#1");
5906                         emitcode ("xch", "a,b");
5907                         emitcode ("cpl", "a"); // msb
5908                         emitcode ("addc", "a,#0");
5909                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5910                         emitcode ("setb","F0");
5911                         emitLabel (lbl);
5912                         emitcode ("mov","mb,b");
5913                         emitcode ("mov","mb,a");
5914                 }
5915         } else {
5916                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5917                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5918         }
5919
5920         /* wait for multiplication to finish */
5921         lbl = newiTempLabel(NULL);
5922         emitLabel (lbl);
5923         emitcode("mov","a,mcnt1");
5924         emitcode("anl","a,#!constbyte",0x80);
5925         emitcode("jnz","!tlabel",lbl->key+100);
5926
5927         freeAsmop (left, NULL, ic, TRUE);
5928         freeAsmop (right, NULL, ic,TRUE);
5929         aopOp(result, ic, TRUE, FALSE);
5930
5931         /* if unsigned then simple */
5932         if (umult) {
5933                 aopPut(result,"ma",1);
5934                 aopPut(result,"ma",0);
5935         } else {
5936                 emitcode("push","ma");
5937                 MOVA("ma");
5938                 /* negate result if needed */
5939                 lbl = newiTempLabel(NULL);
5940                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5941                 emitcode("cpl","a");
5942                 emitcode("add","a,#1");
5943                 emitLabel (lbl);
5944                 aopPut(result,"a",0);
5945                 emitcode("pop","acc");
5946                 lbl = newiTempLabel(NULL);
5947                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5948                 emitcode("cpl","a");
5949                 emitcode("addc","a,#0");
5950                 emitLabel (lbl);
5951                 aopPut(result,"a",1);
5952         }
5953         freeAsmop (result, NULL, ic, TRUE);
5954         /* restore EA bit in F1 */
5955         lbl = newiTempLabel(NULL);
5956         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5957         emitcode ("setb","EA");
5958         emitLabel (lbl);
5959         return ;
5960 }
5961
5962 /*-----------------------------------------------------------------*/
5963 /* genDiv - generates code for division                            */
5964 /*-----------------------------------------------------------------*/
5965 static void
5966 genDiv (iCode * ic)
5967 {
5968   operand *left = IC_LEFT (ic);
5969   operand *right = IC_RIGHT (ic);
5970   operand *result = IC_RESULT (ic);
5971
5972   D (emitcode (";", "genDiv"));
5973
5974   /* assign the amsops */
5975   AOP_OP_2 (ic);
5976
5977   /* special cases first */
5978   /* both are bits */
5979   if (AOP_TYPE (left) == AOP_CRY &&
5980       AOP_TYPE (right) == AOP_CRY)
5981     {
5982       genDivbits (left, right, result, ic);
5983       goto release;
5984     }
5985
5986   /* if both are of size == 1 */
5987   if (AOP_SIZE (left) == 1 &&
5988       AOP_SIZE (right) == 1)
5989     {
5990       genDivOneByte (left, right, result, ic);
5991       goto release;
5992     }
5993
5994   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5995           /* use the ds390 ARITHMETIC accel UNIT */
5996           genDivTwoByte (left, right, result, ic);
5997           return ;
5998   }
5999   /* should have been converted to function call */
6000   assert (0);
6001 release:
6002   freeAsmop (result, NULL, ic, TRUE);
6003   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6004   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genModbits :- modulus of bits                                   */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genModbits (operand * left,
6012             operand * right,
6013             operand * result,
6014             iCode   * ic)
6015 {
6016   char *l;
6017   bool pushedB;
6018
6019   D (emitcode (";", "genModbits"));
6020
6021   pushedB = pushB ();
6022
6023   /* the result must be bit */
6024   LOAD_AB_FOR_DIV (left, right, l);
6025   emitcode ("div", "ab");
6026   emitcode ("mov", "a,b");
6027   emitcode ("rrc", "a");
6028   aopOp(result, ic, TRUE, FALSE);
6029
6030   popB (pushedB);
6031
6032   aopPut (result, "c", 0);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* genModOneByte : 8 bit modulus                                   */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 genModOneByte (operand * left,
6040                operand * right,
6041                operand * result,
6042                iCode   * ic)
6043 {
6044   bool lUnsigned, rUnsigned, pushedB;
6045   bool runtimeSign, compiletimeSign;
6046   char *l;
6047   symbol *lbl;
6048   int size, offset;
6049
6050   D (emitcode (";", "genModOneByte"));
6051
6052   offset = 1;
6053   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6054   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6055
6056   pushedB = pushB ();
6057
6058   /* signed or unsigned */
6059   if (lUnsigned && rUnsigned)
6060     {
6061       /* unsigned is easy */
6062       LOAD_AB_FOR_DIV (left, right, l);
6063       emitcode ("div", "ab");
6064       aopOp (result, ic, TRUE, FALSE);
6065       aopPut (result, "b", 0);
6066
6067       for (size = AOP_SIZE (result) - 1; size--;)
6068         aopPut (result, zero, offset++);
6069
6070       popB (pushedB);
6071       return;
6072     }
6073
6074   /* signed is a little bit more difficult */
6075
6076   /* now sign adjust for both left & right */
6077
6078   /* modulus: sign of the right operand has no influence on the result! */
6079   if (AOP_TYPE(right) == AOP_LIT)
6080     {
6081       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6082
6083       if (!rUnsigned && val < 0)
6084         emitcode ("mov", "b,#0x%02x", -val);
6085       else
6086         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6087     }
6088   else /* not literal */
6089     {
6090       if (rUnsigned)
6091         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6092       else
6093         {
6094           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6095           lbl = newiTempLabel (NULL);
6096           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6097           emitcode ("cpl", "a");  /* 2's complement */
6098           emitcode ("inc", "a");
6099           emitLabel (lbl);
6100           emitcode ("mov", "b,a");
6101         }
6102     }
6103
6104   /* let's see what's needed: */
6105   /* apply negative sign during runtime */
6106   runtimeSign = FALSE;
6107   /* negative sign from literals */
6108   compiletimeSign = FALSE;
6109
6110   /* sign adjust left side */
6111   if (AOP_TYPE(left) == AOP_LIT)
6112     {
6113       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6114
6115       if (!lUnsigned && val < 0)
6116         {
6117           compiletimeSign = TRUE; /* set sign flag */
6118           emitcode ("mov", "a,#0x%02x", -val);
6119         }
6120       else
6121         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6122     }
6123   else /* ! literal */
6124     {
6125       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6126
6127       if (!lUnsigned)
6128         {
6129           runtimeSign = TRUE;
6130           emitcode ("clr", "F0"); /* clear sign flag */
6131
6132           lbl = newiTempLabel (NULL);
6133           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6134           emitcode ("setb", "F0"); /* set sign flag */
6135           emitcode ("cpl", "a");   /* 2's complement */
6136           emitcode ("inc", "a");
6137           emitLabel (lbl);
6138         }
6139     }
6140
6141   /* now the modulus */
6142   emitcode ("nop", "; workaround for DS80C390 div bug.");
6143   emitcode ("div", "ab");
6144
6145   if (runtimeSign || compiletimeSign)
6146     {
6147       emitcode ("mov", "a,b");
6148       lbl = newiTempLabel (NULL);
6149       if (runtimeSign)
6150         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6151       emitcode ("cpl", "a"); /* lsb 2's complement */
6152       emitcode ("inc", "a");
6153       emitLabel (lbl);
6154
6155       _G.accInUse++;
6156       aopOp (result, ic, TRUE, FALSE);
6157       size = AOP_SIZE (result) - 1;
6158
6159       if (size > 0)
6160         {
6161           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6162              then the result will be in b, a */
6163           emitcode ("mov", "b,a"); /* 1 */
6164           /* msb is 0x00 or 0xff depending on the sign */
6165           if (runtimeSign)
6166             {
6167               emitcode ("mov",  "c,F0");
6168               emitcode ("subb", "a,acc");
6169               emitcode ("xch",  "a,b"); /* 2 */
6170               while (size--)
6171                 aopPut (result, "b", offset++); /* write msb's */
6172             }
6173           else /* compiletimeSign */
6174             while (size--)
6175               aopPut (result, "#0xff", offset++); /* write msb's */
6176         }
6177       aopPut (result, "a", 0); /* 3: write lsb */
6178     }
6179   else
6180     {
6181       _G.accInUse++;
6182       aopOp(result, ic, TRUE, FALSE);
6183       size = AOP_SIZE (result) - 1;
6184
6185       aopPut (result, "b", 0);
6186       while (size--)
6187         aopPut (result, zero, offset++);
6188     }
6189   _G.accInUse--;
6190   popB (pushedB);
6191 }
6192
6193 /*-----------------------------------------------------------------*/
6194 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6195 /*-----------------------------------------------------------------*/
6196 static void genModTwoByte (operand *left, operand *right,
6197                             operand *result, iCode *ic)
6198 {
6199         sym_link *retype = getSpec(operandType(right));
6200         sym_link *letype = getSpec(operandType(left));
6201         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6202         symbol *lbl;
6203
6204         /* load up MA with left */
6205         /* save EA bit in F1 */
6206         lbl = newiTempLabel(NULL);
6207         emitcode ("setb","F1");
6208         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6209         emitcode ("clr","F1");
6210         emitLabel (lbl);
6211
6212         if (!umult) {
6213                 lbl = newiTempLabel(NULL);
6214                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6215                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6216                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6217                 emitcode ("xch", "a,b");
6218                 emitcode ("cpl","a");
6219                 emitcode ("add", "a,#1");
6220                 emitcode ("xch", "a,b");
6221                 emitcode ("cpl", "a"); // msb
6222                 emitcode ("addc","a,#0");
6223                 emitLabel (lbl);
6224                 emitcode ("mov","ma,b");
6225                 emitcode ("mov","ma,a");
6226         } else {
6227                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6228                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6229         }
6230
6231         /* load up MB with right */
6232         if (!umult) {
6233                 if (AOP_TYPE(right) == AOP_LIT) {
6234                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6235                         if (val < 0) {
6236                                 val = -val;
6237                         }
6238                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6239                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6240                 } else {
6241                         lbl = newiTempLabel(NULL);
6242                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6243                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6244                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6245                         emitcode ("xch", "a,b");
6246                         emitcode ("cpl","a");
6247                         emitcode ("add", "a,#1");
6248                         emitcode ("xch", "a,b");
6249                         emitcode ("cpl", "a"); // msb
6250                         emitcode ("addc", "a,#0");
6251                         emitLabel (lbl);
6252                         emitcode ("mov","mb,b");
6253                         emitcode ("mov","mb,a");
6254                 }
6255         } else {
6256                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6257                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6258         }
6259
6260         /* wait for multiplication to finish */
6261         lbl = newiTempLabel(NULL);
6262         emitLabel (lbl);
6263         emitcode("mov","a,mcnt1");
6264         emitcode("anl","a,#!constbyte",0x80);
6265         emitcode("jnz","!tlabel",lbl->key+100);
6266
6267         freeAsmop (left, NULL, ic, TRUE);
6268         freeAsmop (right, NULL, ic,TRUE);
6269         aopOp(result, ic, TRUE, FALSE);
6270
6271         aopPut(result,"mb",1);
6272         aopPut(result,"mb",0);
6273         freeAsmop (result, NULL, ic, TRUE);
6274
6275         /* restore EA bit in F1 */
6276         lbl = newiTempLabel(NULL);
6277         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6278         emitcode ("setb","EA");
6279         emitLabel (lbl);
6280 }
6281
6282 /*-----------------------------------------------------------------*/
6283 /* genMod - generates code for division                            */
6284 /*-----------------------------------------------------------------*/
6285 static void
6286 genMod (iCode * ic)
6287 {
6288   operand *left = IC_LEFT (ic);
6289   operand *right = IC_RIGHT (ic);
6290   operand *result = IC_RESULT (ic);
6291
6292   D (emitcode (";", "genMod"));
6293
6294   /* assign the asmops */
6295   AOP_OP_2 (ic);
6296
6297   /* special cases first */
6298   /* both are bits */
6299   if (AOP_TYPE (left) == AOP_CRY &&
6300       AOP_TYPE (right) == AOP_CRY)
6301     {
6302       genModbits (left, right, result, ic);
6303       goto release;
6304     }
6305
6306   /* if both are of size == 1 */
6307   if (AOP_SIZE (left) == 1 &&
6308       AOP_SIZE (right) == 1)
6309     {
6310       genModOneByte (left, right, result, ic);
6311       goto release;
6312     }
6313
6314   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6315           /* use the ds390 ARITHMETIC accel UNIT */
6316           genModTwoByte (left, right, result, ic);
6317           return ;
6318   }
6319
6320   /* should have been converted to function call */
6321   assert (0);
6322
6323 release:
6324   freeAsmop (result, NULL, ic, TRUE);
6325   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327 }
6328
6329 /*-----------------------------------------------------------------*/
6330 /* genIfxJump :- will create a jump depending on the ifx           */
6331 /*-----------------------------------------------------------------*/
6332 static void
6333 genIfxJump (iCode * ic, char *jval)
6334 {
6335   symbol *jlbl;
6336   symbol *tlbl = newiTempLabel (NULL);
6337   char *inst;
6338
6339   D (emitcode (";", "genIfxJump"));
6340
6341   /* if true label then we jump if condition
6342      supplied is true */
6343   if (IC_TRUE (ic))
6344     {
6345       jlbl = IC_TRUE (ic);
6346       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6347                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6348     }
6349   else
6350     {
6351       /* false label is present */
6352       jlbl = IC_FALSE (ic);
6353       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6354                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6355     }
6356   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6357     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6358   else
6359     emitcode (inst, "!tlabel", tlbl->key + 100);
6360   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6361   emitLabel (tlbl);
6362
6363   /* mark the icode as generated */
6364   ic->generated = 1;
6365 }
6366
6367 /*-----------------------------------------------------------------*/
6368 /* genCmp :- greater or less than comparison                       */
6369 /*-----------------------------------------------------------------*/
6370 static void
6371 genCmp (operand * left, operand * right,
6372         iCode * ic, iCode * ifx, int sign)
6373 {
6374   int size, offset = 0;
6375   unsigned long lit = 0L;
6376   operand *result;
6377
6378   D (emitcode (";", "genCmp"));
6379
6380   result = IC_RESULT (ic);
6381
6382   /* if left & right are bit variables */
6383   if (AOP_TYPE (left) == AOP_CRY &&
6384       AOP_TYPE (right) == AOP_CRY)
6385     {
6386       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6387       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6388     }
6389   else
6390     {
6391       /* subtract right from left if at the
6392          end the carry flag is set then we know that
6393          left is greater than right */
6394       size = max (AOP_SIZE (left), AOP_SIZE (right));
6395
6396       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6397       if ((size == 1) && !sign &&
6398           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6399         {
6400           symbol *lbl = newiTempLabel (NULL);
6401           emitcode ("cjne", "%s,%s,!tlabel",
6402                     aopGet (left, offset, FALSE, FALSE, NULL),
6403                     aopGet (right, offset, FALSE, FALSE, NULL),
6404                     lbl->key + 100);
6405           emitLabel (lbl);
6406         }
6407       else
6408         {
6409           if (AOP_TYPE (right) == AOP_LIT)
6410             {
6411               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6412               /* optimize if(x < 0) or if(x >= 0) */
6413               if (lit == 0L)
6414                 {
6415                   if (!sign)
6416                     {
6417                       CLRC;
6418                     }
6419                   else
6420                     {
6421                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6422
6423                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6425
6426                       aopOp (result, ic, FALSE, FALSE);
6427
6428                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6429                         {
6430                           freeAsmop (result, NULL, ic, TRUE);
6431                           genIfxJump (ifx, "acc.7");
6432                           return;
6433                         }
6434                       else
6435                         {
6436                           emitcode ("rlc", "a");
6437                         }
6438                       goto release_freedLR;
6439                     }
6440                   goto release;
6441                 }
6442             }
6443           CLRC;
6444           while (size--)
6445             {
6446               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6447               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6448               // emitcode (";", "genCmp #2");
6449               if (sign && (size == 0))
6450                 {
6451                   // emitcode (";", "genCmp #3");
6452                   emitcode ("xrl", "a,#!constbyte",0x80);
6453                   if (AOP_TYPE (right) == AOP_LIT)
6454                     {
6455                       unsigned long lit = (unsigned long)
6456                       floatFromVal (AOP (right)->aopu.aop_lit);
6457                       // emitcode (";", "genCmp #3.1");
6458                       emitcode ("subb", "a,#!constbyte",
6459                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6460                     }
6461                   else
6462                     {
6463                       // emitcode (";", "genCmp #3.2");
6464                       saveAccWarn = 0;
6465                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6466                       saveAccWarn = DEFAULT_ACC_WARNING;
6467                       emitcode ("xrl", "b,#!constbyte",0x80);
6468                       emitcode ("subb", "a,b");
6469                     }
6470                 }
6471               else
6472                 {
6473                   const char *s;
6474
6475                   // emitcode (";", "genCmp #4");
6476                   saveAccWarn = 0;
6477                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6478                   saveAccWarn = DEFAULT_ACC_WARNING;
6479
6480                   emitcode ("subb", "a,%s", s);
6481                 }
6482             }
6483         }
6484     }
6485
6486 release:
6487 /* Don't need the left & right operands any more; do need the result. */
6488   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6490
6491   aopOp (result, ic, FALSE, FALSE);
6492
6493 release_freedLR:
6494
6495   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6496     {
6497       outBitC (result);
6498     }
6499   else
6500     {
6501       /* if the result is used in the next
6502          ifx conditional branch then generate
6503          code a little differently */
6504       if (ifx)
6505         {
6506           genIfxJump (ifx, "c");
6507         }
6508       else
6509         {
6510           outBitC (result);
6511         }
6512       /* leave the result in acc */
6513     }
6514   freeAsmop (result, NULL, ic, TRUE);
6515 }
6516
6517 /*-----------------------------------------------------------------*/
6518 /* genCmpGt :- greater than comparison                             */
6519 /*-----------------------------------------------------------------*/
6520 static void
6521 genCmpGt (iCode * ic, iCode * ifx)
6522 {
6523   operand *left, *right;
6524   sym_link *letype, *retype;
6525   int sign;
6526
6527   D (emitcode (";", "genCmpGt"));
6528
6529   left = IC_LEFT (ic);
6530   right = IC_RIGHT (ic);
6531
6532   letype = getSpec (operandType (left));
6533   retype = getSpec (operandType (right));
6534   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6535
6536   /* assign the left & right amsops */
6537   AOP_OP_2 (ic);
6538
6539   genCmp (right, left, ic, ifx, sign);
6540 }
6541
6542 /*-----------------------------------------------------------------*/
6543 /* genCmpLt - less than comparisons                                */
6544 /*-----------------------------------------------------------------*/
6545 static void
6546 genCmpLt (iCode * ic, iCode * ifx)
6547 {
6548   operand *left, *right;
6549   sym_link *letype, *retype;
6550   int sign;
6551
6552   D (emitcode (";", "genCmpLt"));
6553
6554   left = IC_LEFT (ic);
6555   right = IC_RIGHT (ic);
6556
6557   letype = getSpec (operandType (left));
6558   retype = getSpec (operandType (right));
6559   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6560
6561   /* assign the left & right amsops */
6562   AOP_OP_2 (ic);
6563
6564   genCmp (left, right, ic, ifx, sign);
6565 }
6566
6567 /*-----------------------------------------------------------------*/
6568 /* gencjneshort - compare and jump if not equal                    */
6569 /*-----------------------------------------------------------------*/
6570 static void
6571 gencjneshort (operand * left, operand * right, symbol * lbl)
6572 {
6573   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6574   int offset = 0;
6575   unsigned long lit = 0L;
6576
6577   D (emitcode (";", "gencjneshort"));
6578
6579   /* if the left side is a literal or
6580      if the right is in a pointer register and left
6581      is not */
6582   if ((AOP_TYPE (left) == AOP_LIT) ||
6583       (AOP_TYPE (left) == AOP_IMMD) ||
6584       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6585     {
6586       operand *t = right;
6587       right = left;
6588       left = t;
6589     }
6590
6591   if (AOP_TYPE (right) == AOP_LIT)
6592     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6593
6594   if (opIsGptr (left) || opIsGptr (right))
6595     {
6596       /* We are comparing a generic pointer to something.
6597        * Exclude the generic type byte from the comparison.
6598        */
6599       size--;
6600       D (emitcode (";", "cjneshort: generic ptr special case."););
6601     }
6602
6603
6604   /* if the right side is a literal then anything goes */
6605   if (AOP_TYPE (right) == AOP_LIT &&
6606       AOP_TYPE (left) != AOP_DIR)
6607     {
6608       while (size--)
6609         {
6610           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6611           emitcode ("cjne", "a,%s,!tlabel",
6612                     aopGet (right, offset, FALSE, FALSE, NULL),
6613                     lbl->key + 100);
6614           offset++;
6615         }
6616     }
6617
6618   /* if the right side is in a register or in direct space or
6619      if the left is a pointer register & right is not */
6620   else if (AOP_TYPE (right) == AOP_REG ||
6621            AOP_TYPE (right) == AOP_DIR ||
6622            AOP_TYPE (right) == AOP_LIT ||
6623            AOP_TYPE (right) == AOP_IMMD ||
6624            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6625            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6626     {
6627       while (size--)
6628         {
6629           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6630           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6631               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6632             emitcode ("jnz", "!tlabel", lbl->key + 100);
6633           else
6634             emitcode ("cjne", "a,%s,!tlabel",
6635                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6636                       lbl->key + 100);
6637           offset++;
6638         }
6639     }
6640   else
6641     {
6642       /* right is a pointer reg need both a & b */
6643       while (size--)
6644         {
6645           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6646           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6647           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6648           offset++;
6649         }
6650     }
6651 }
6652
6653 /*-----------------------------------------------------------------*/
6654 /* gencjne - compare and jump if not equal                         */
6655 /*-----------------------------------------------------------------*/
6656 static void
6657 gencjne (operand * left, operand * right, symbol * lbl)
6658 {
6659   symbol *tlbl = newiTempLabel (NULL);
6660
6661   D (emitcode (";", "gencjne"));
6662
6663   gencjneshort (left, right, lbl);
6664
6665   emitcode ("mov", "a,%s", one);
6666   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6667   emitLabel (lbl);
6668   emitcode ("clr", "a");
6669   emitLabel (tlbl);
6670 }
6671
6672 /*-----------------------------------------------------------------*/
6673 /* genCmpEq - generates code for equal to                          */
6674 /*-----------------------------------------------------------------*/
6675 static void
6676 genCmpEq (iCode * ic, iCode * ifx)
6677 {
6678   operand *left, *right, *result;
6679
6680   D (emitcode (";", "genCmpEq"));
6681
6682   AOP_OP_2 (ic);
6683   AOP_SET_LOCALS (ic);
6684
6685   /* if literal, literal on the right or
6686      if the right is in a pointer register and left
6687      is not */
6688   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6689       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6690     {
6691       operand *t = IC_RIGHT (ic);
6692       IC_RIGHT (ic) = IC_LEFT (ic);
6693       IC_LEFT (ic) = t;
6694     }
6695
6696   if (ifx &&                    /* !AOP_SIZE(result) */
6697       OP_SYMBOL (result) &&
6698       OP_SYMBOL (result)->regType == REG_CND)
6699     {
6700       symbol *tlbl;
6701       /* if they are both bit variables */
6702       if (AOP_TYPE (left) == AOP_CRY &&
6703           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6704         {
6705           if (AOP_TYPE (right) == AOP_LIT)
6706             {
6707               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6708               if (lit == 0L)
6709                 {
6710                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6711                   emitcode ("cpl", "c");
6712                 }
6713               else if (lit == 1L)
6714                 {
6715                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6716                 }
6717               else
6718                 {
6719                   emitcode ("clr", "c");
6720                 }
6721               /* AOP_TYPE(right) == AOP_CRY */
6722             }
6723           else
6724             {
6725               symbol *lbl = newiTempLabel (NULL);
6726               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6727               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6728               emitcode ("cpl", "c");
6729               emitLabel (lbl);
6730             }
6731           /* if true label then we jump if condition
6732              supplied is true */
6733           tlbl = newiTempLabel (NULL);
6734           if (IC_TRUE (ifx))
6735             {
6736               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6737               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6738             }
6739           else
6740             {
6741               emitcode ("jc", "!tlabel", tlbl->key + 100);
6742               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6743             }
6744           emitLabel (tlbl);
6745         }
6746       else
6747         {
6748           tlbl = newiTempLabel (NULL);
6749           gencjneshort (left, right, tlbl);
6750           if (IC_TRUE (ifx))
6751             {
6752               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6753               emitLabel (tlbl);
6754             }
6755           else
6756             {
6757               symbol *lbl = newiTempLabel (NULL);
6758               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6759               emitLabel (tlbl);
6760               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6761               emitLabel (lbl);
6762             }
6763         }
6764       /* mark the icode as generated */
6765       ifx->generated = 1;
6766
6767       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6768       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6769       return;
6770     }
6771
6772   /* if they are both bit variables */
6773   if (AOP_TYPE (left) == AOP_CRY &&
6774       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6775     {
6776       if (AOP_TYPE (right) == AOP_LIT)
6777         {
6778           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6779           if (lit == 0L)
6780             {
6781               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6782               emitcode ("cpl", "c");
6783             }
6784           else if (lit == 1L)
6785             {
6786               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6787             }
6788           else
6789             {
6790               emitcode ("clr", "c");
6791             }
6792           /* AOP_TYPE(right) == AOP_CRY */
6793         }
6794       else
6795         {
6796           symbol *lbl = newiTempLabel (NULL);
6797           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6798           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6799           emitcode ("cpl", "c");
6800           emitLabel (lbl);
6801         }
6802
6803       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6804       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6805
6806       aopOp (result, ic, TRUE, FALSE);
6807
6808       /* c = 1 if egal */
6809       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6810         {
6811           outBitC (result);
6812           goto release;
6813         }
6814       if (ifx)
6815         {
6816           genIfxJump (ifx, "c");
6817           goto release;
6818         }
6819       /* if the result is used in an arithmetic operation
6820          then put the result in place */
6821       outBitC (result);
6822     }
6823   else
6824     {
6825       gencjne (left, right, newiTempLabel (NULL));
6826
6827       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6829
6830       aopOp (result, ic, TRUE, FALSE);
6831
6832       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6833         {
6834           aopPut (result, "a", 0);
6835           goto release;
6836         }
6837       if (ifx)
6838         {
6839           genIfxJump (ifx, "a");
6840           goto release;
6841         }
6842       /* if the result is used in an arithmetic operation
6843          then put the result in place */
6844       if (AOP_TYPE (result) != AOP_CRY)
6845         outAcc (result);
6846       /* leave the result in acc */
6847     }
6848
6849 release:
6850   freeAsmop (result, NULL, ic, TRUE);
6851 }
6852
6853 /*-----------------------------------------------------------------*/
6854 /* ifxForOp - returns the icode containing the ifx for operand     */
6855 /*-----------------------------------------------------------------*/
6856 static iCode *
6857 ifxForOp (operand * op, iCode * ic)
6858 {
6859   /* if true symbol then needs to be assigned */
6860   if (IS_TRUE_SYMOP (op))
6861     return NULL;
6862
6863   /* if this has register type condition and
6864      the next instruction is ifx with the same operand
6865      and live to of the operand is upto the ifx only then */
6866   if (ic->next &&
6867       ic->next->op == IFX &&
6868       IC_COND (ic->next)->key == op->key &&
6869       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6870     return ic->next;
6871
6872   return NULL;
6873 }
6874
6875 /*-----------------------------------------------------------------*/
6876 /* hasInc - operand is incremented before any other use            */
6877 /*-----------------------------------------------------------------*/
6878 static iCode *
6879 hasInc (operand *op, iCode *ic, int osize)
6880 {
6881   sym_link *type = operandType(op);
6882   sym_link *retype = getSpec (type);
6883   iCode *lic = ic->next;
6884   int isize ;
6885
6886   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6887   if (!IS_SYMOP(op)) return NULL;
6888
6889   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6890   if (IS_AGGREGATE(type->next)) return NULL;
6891   if (osize != (isize = getSize(type->next))) return NULL;
6892
6893   while (lic) {
6894       /* if operand of the form op = op + <sizeof *op> */
6895       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6896           isOperandEqual(IC_RESULT(lic),op) &&
6897           isOperandLiteral(IC_RIGHT(lic)) &&
6898           operandLitValue(IC_RIGHT(lic)) == isize) {
6899           return lic;
6900       }
6901       /* if the operand used or deffed */
6902       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6903           return NULL;
6904       }
6905       /* if GOTO or IFX */
6906       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6907       lic = lic->next;
6908   }
6909   return NULL;
6910 }
6911
6912 /*-----------------------------------------------------------------*/
6913 /* genAndOp - for && operation                                     */
6914 /*-----------------------------------------------------------------*/
6915 static void
6916 genAndOp (iCode * ic)
6917 {
6918   operand *left, *right, *result;
6919   symbol *tlbl;
6920
6921   D (emitcode (";", "genAndOp"));
6922
6923   /* note here that && operations that are in an
6924      if statement are taken away by backPatchLabels
6925      only those used in arthmetic operations remain */
6926   AOP_OP_2 (ic);
6927   AOP_SET_LOCALS (ic);
6928
6929   /* if both are bit variables */
6930   if (AOP_TYPE (left) == AOP_CRY &&
6931       AOP_TYPE (right) == AOP_CRY)
6932     {
6933       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6934       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6935       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6936       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6937
6938       aopOp (result,ic,FALSE, FALSE);
6939       outBitC (result);
6940     }
6941   else
6942     {
6943       tlbl = newiTempLabel (NULL);
6944       toBoolean (left);
6945       emitcode ("jz", "!tlabel", tlbl->key + 100);
6946       toBoolean (right);
6947       emitLabel (tlbl);
6948       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6949       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6950
6951       aopOp (result,ic,FALSE, FALSE);
6952       outBitAcc (result);
6953     }
6954
6955     freeAsmop (result, NULL, ic, TRUE);
6956 }
6957
6958
6959 /*-----------------------------------------------------------------*/
6960 /* genOrOp - for || operation                                      */
6961 /*-----------------------------------------------------------------*/
6962 static void
6963 genOrOp (iCode * ic)
6964 {
6965   operand *left, *right, *result;
6966   symbol *tlbl;
6967
6968   D (emitcode (";", "genOrOp"));
6969
6970   /* note here that || operations that are in an
6971      if statement are taken away by backPatchLabels
6972      only those used in arthmetic operations remain */
6973   AOP_OP_2 (ic);
6974   AOP_SET_LOCALS (ic);
6975
6976   /* if both are bit variables */
6977   if (AOP_TYPE (left) == AOP_CRY &&
6978       AOP_TYPE (right) == AOP_CRY)
6979     {
6980       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6981       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6982       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6983       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6984
6985       aopOp (result,ic,FALSE, FALSE);
6986
6987       outBitC (result);
6988     }
6989   else
6990     {
6991       tlbl = newiTempLabel (NULL);
6992       toBoolean (left);
6993       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6994       toBoolean (right);
6995       emitLabel (tlbl);
6996       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6997       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6998
6999       aopOp (result,ic,FALSE, FALSE);
7000
7001       outBitAcc (result);
7002     }
7003
7004   freeAsmop (result, NULL, ic, TRUE);
7005 }
7006
7007 /*-----------------------------------------------------------------*/
7008 /* isLiteralBit - test if lit == 2^n                               */
7009 /*-----------------------------------------------------------------*/
7010 static int
7011 isLiteralBit (unsigned long lit)
7012 {
7013   unsigned long pw[32] =
7014   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7015    0x100L, 0x200L, 0x400L, 0x800L,
7016    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7017    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7018    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7019    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7020    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7021   int idx;
7022
7023   for (idx = 0; idx < 32; idx++)
7024     if (lit == pw[idx])
7025       return idx + 1;
7026   return 0;
7027 }
7028
7029 /*-----------------------------------------------------------------*/
7030 /* continueIfTrue -                                                */
7031 /*-----------------------------------------------------------------*/
7032 static void
7033 continueIfTrue (iCode * ic)
7034 {
7035   if (IC_TRUE (ic))
7036     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7037   ic->generated = 1;
7038 }
7039
7040 /*-----------------------------------------------------------------*/
7041 /* jmpIfTrue -                                                     */
7042 /*-----------------------------------------------------------------*/
7043 static void
7044 jumpIfTrue (iCode * ic)
7045 {
7046   if (!IC_TRUE (ic))
7047     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7048   ic->generated = 1;
7049 }
7050
7051 /*-----------------------------------------------------------------*/
7052 /* jmpTrueOrFalse -                                                */
7053 /*-----------------------------------------------------------------*/
7054 static void
7055 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7056 {
7057   // ugly but optimized by peephole
7058   if (IC_TRUE (ic))
7059     {
7060       symbol *nlbl = newiTempLabel (NULL);
7061       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7062       emitLabel (tlbl);
7063       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7064       emitLabel (nlbl);
7065     }
7066   else
7067     {
7068       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7069       emitLabel (tlbl);
7070     }
7071   ic->generated = 1;
7072 }
7073
7074 // Generate code to perform a bit-wise logic operation
7075 // on two operands in far space (assumed to already have been
7076 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7077 // in far space. This requires pushing the result on the stack
7078 // then popping it into the result.
7079 static void
7080 genFarFarLogicOp(iCode *ic, char *logicOp)
7081 {
7082       int size, resultSize, compSize;
7083       int offset = 0;
7084
7085       TR_AP("#5");
7086       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7087       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7088                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7089
7090       _startLazyDPSEvaluation();
7091       for (size = compSize; (size--); offset++)
7092       {
7093           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7094           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7095           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7096
7097           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7098           emitcode ("push", "acc");
7099       }
7100       _endLazyDPSEvaluation();
7101
7102       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7103       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7104       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7105
7106       resultSize = AOP_SIZE(IC_RESULT(ic));
7107
7108       ADJUST_PUSHED_RESULT(compSize, resultSize);
7109
7110       _startLazyDPSEvaluation();
7111       while (compSize--)
7112       {
7113           emitcode ("pop", "acc");
7114           aopPut (IC_RESULT (ic), "a", compSize);
7115       }
7116       _endLazyDPSEvaluation();
7117       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7118 }
7119
7120
7121 /*-----------------------------------------------------------------*/
7122 /* genAnd  - code for and                                          */
7123 /*-----------------------------------------------------------------*/
7124 static void
7125 genAnd (iCode * ic, iCode * ifx)
7126 {
7127   operand *left, *right, *result;
7128   int size, offset = 0;
7129   unsigned long lit = 0L;
7130   int bytelit = 0;
7131   char buffer[10];
7132   bool pushResult;
7133
7134   D (emitcode (";", "genAnd"));
7135
7136   AOP_OP_3_NOFATAL (ic, pushResult);
7137   AOP_SET_LOCALS (ic);
7138
7139   if (pushResult)
7140   {
7141       genFarFarLogicOp(ic, "anl");
7142       return;
7143   }
7144
7145 #ifdef DEBUG_TYPE
7146   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7147             AOP_TYPE (result),
7148             AOP_TYPE (left), AOP_TYPE (right));
7149   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7150             AOP_SIZE (result),
7151             AOP_SIZE (left), AOP_SIZE (right));
7152 #endif
7153
7154   /* if left is a literal & right is not then exchange them */
7155   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7156 #ifdef LOGIC_OPS_BROKEN
7157     ||  AOP_NEEDSACC (left)
7158 #endif
7159     )
7160     {
7161       operand *tmp = right;
7162       right = left;
7163       left = tmp;
7164     }
7165
7166   /* if result = right then exchange left and right */
7167   if (sameRegs (AOP (result), AOP (right)))
7168     {
7169       operand *tmp = right;
7170       right = left;
7171       left = tmp;
7172     }
7173
7174   /* if right is bit then exchange them */
7175   if (AOP_TYPE (right) == AOP_CRY &&
7176       AOP_TYPE (left) != AOP_CRY)
7177     {
7178       operand *tmp = right;
7179       right = left;
7180       left = tmp;
7181     }
7182   if (AOP_TYPE (right) == AOP_LIT)
7183     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7184
7185   size = AOP_SIZE (result);
7186
7187   // if(bit & yy)
7188   // result = bit & yy;
7189   if (AOP_TYPE (left) == AOP_CRY)
7190     {
7191       // c = bit & literal;
7192       if (AOP_TYPE (right) == AOP_LIT)
7193         {
7194           if (lit & 1)
7195             {
7196               if (size && sameRegs (AOP (result), AOP (left)))
7197                 // no change
7198                 goto release;
7199               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7200             }
7201           else
7202             {
7203               // bit(result) = 0;
7204               if (size && (AOP_TYPE (result) == AOP_CRY))
7205                 {
7206                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7207                   goto release;
7208                 }
7209               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7210                 {
7211                   jumpIfTrue (ifx);
7212                   goto release;
7213                 }
7214               emitcode ("clr", "c");
7215             }
7216         }
7217       else
7218         {
7219           if (AOP_TYPE (right) == AOP_CRY)
7220             {
7221               // c = bit & bit;
7222               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7223               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7224             }
7225           else
7226             {
7227               // c = bit & val;
7228               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7229               // c = lsb
7230               emitcode ("rrc", "a");
7231               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7232             }
7233         }
7234       // bit = c
7235       // val = c
7236       if (size)
7237         outBitC (result);
7238       // if(bit & ...)
7239       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7240         genIfxJump (ifx, "c");
7241       goto release;
7242     }
7243
7244   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7245   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7246   if ((AOP_TYPE (right) == AOP_LIT) &&
7247       (AOP_TYPE (result) == AOP_CRY) &&
7248       (AOP_TYPE (left) != AOP_CRY))
7249     {
7250       int posbit = isLiteralBit (lit);
7251       /* left &  2^n */
7252       if (posbit)
7253         {
7254           posbit--;
7255           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7256           // bit = left & 2^n
7257           if (size)
7258             {
7259               switch (posbit & 0x07)
7260                 {
7261                   case 0: emitcode ("rrc", "a");
7262                           break;
7263                   case 7: emitcode ("rlc", "a");
7264                           break;
7265                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7266                           break;
7267                 }
7268             }
7269           // if(left &  2^n)
7270           else
7271             {
7272               if (ifx)
7273                 {
7274                   SNPRINTF (buffer, sizeof(buffer),
7275                             "acc.%d", posbit & 0x07);
7276                   genIfxJump (ifx, buffer);
7277                 }
7278               else
7279                 {
7280                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7281                 }
7282               goto release;
7283             }
7284         }
7285       else
7286         {
7287           symbol *tlbl = newiTempLabel (NULL);
7288           int sizel = AOP_SIZE (left);
7289           if (size)
7290             emitcode ("setb", "c");
7291           while (sizel--)
7292             {
7293               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7294                 {
7295                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7296                   // byte ==  2^n ?
7297                   if ((posbit = isLiteralBit (bytelit)) != 0)
7298                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7299                   else
7300                     {
7301                       if (bytelit != 0x0FFL)
7302                         emitcode ("anl", "a,%s",
7303                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7304                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7305                     }
7306                 }
7307               offset++;
7308             }
7309           // bit = left & literal
7310           if (size)
7311             {
7312               emitcode ("clr", "c");
7313               emitLabel (tlbl);
7314             }
7315           // if(left & literal)
7316           else
7317             {
7318               if (ifx)
7319                 jmpTrueOrFalse (ifx, tlbl);
7320               else
7321                 emitLabel (tlbl);
7322               goto release;
7323             }
7324         }
7325       outBitC (result);
7326       goto release;
7327     }
7328
7329   /* if left is same as result */
7330   if (sameRegs (AOP (result), AOP (left)))
7331     {
7332       for (; size--; offset++)
7333         {
7334           if (AOP_TYPE (right) == AOP_LIT)
7335             {
7336               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7337               if (bytelit == 0x0FF)
7338                 {
7339                   /* dummy read of volatile operand */
7340                   if (isOperandVolatile (left, FALSE))
7341                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7342                   else
7343                     continue;
7344                 }
7345               else if (bytelit == 0)
7346                 {
7347                   aopPut (result, zero, offset);
7348                 }
7349               else if (IS_AOP_PREG (result))
7350                 {
7351                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7352                   emitcode ("anl", "a,%s",
7353                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7354                   aopPut (result, "a", offset);
7355                 }
7356               else
7357                 emitcode ("anl", "%s,%s",
7358                           aopGet (left, offset, FALSE, TRUE, NULL),
7359                           aopGet (right, offset, FALSE, FALSE, NULL));
7360             }
7361           else
7362             {
7363               if (AOP_TYPE (left) == AOP_ACC)
7364                 {
7365                   if (offset)
7366                     emitcode("mov", "a,b");
7367                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7368                 }
7369               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7370                 {
7371                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7372                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7373                   emitcode ("anl", "a,b");
7374                   aopPut (result, "a", offset);
7375                 }
7376               else if (aopGetUsesAcc (left, offset))
7377                 {
7378                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7379                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7380                   aopPut (result, "a", offset);
7381                 }
7382               else
7383                 {
7384                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7385                   if (IS_AOP_PREG (result))
7386                     {
7387                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7388                       aopPut (result, "a", offset);
7389                     }
7390                   else
7391                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7392                 }
7393             }
7394         }
7395     }
7396   else
7397     {
7398       // left & result in different registers
7399       if (AOP_TYPE (result) == AOP_CRY)
7400         {
7401           // result = bit
7402           // if(size), result in bit
7403           // if(!size && ifx), conditional oper: if(left & right)
7404           symbol *tlbl = newiTempLabel (NULL);
7405           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7406           if (size)
7407             emitcode ("setb", "c");
7408           while (sizer--)
7409             {
7410               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7411                   && AOP_TYPE(left)==AOP_ACC)
7412                 {
7413                   if (offset)
7414                     emitcode("mov", "a,b");
7415                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7416                 }
7417               else if (AOP_TYPE(left)==AOP_ACC)
7418                 {
7419                   if (!offset)
7420                     {
7421                       bool pushedB = pushB ();
7422                       emitcode("mov", "b,a");
7423                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7424                       emitcode("anl", "a,b");
7425                       popB (pushedB);
7426                     }
7427                   else
7428                     {
7429                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7430                       emitcode("anl", "a,b");
7431                     }
7432                 }
7433               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7434                 {
7435                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7436                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7437                   emitcode ("anl", "a,b");
7438                 }
7439               else if (aopGetUsesAcc (left, offset))
7440                 {
7441                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7442                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7443                 }
7444               else
7445                 {
7446                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7447                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7448                 }
7449
7450               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7451               offset++;
7452             }
7453           if (size)
7454             {
7455               CLRC;
7456               emitLabel (tlbl);
7457               outBitC (result);
7458             }
7459           else if (ifx)
7460             jmpTrueOrFalse (ifx, tlbl);
7461           else
7462             emitLabel (tlbl);
7463         }
7464       else
7465         {
7466           for (; (size--); offset++)
7467             {
7468               // normal case
7469               // result = left & right
7470               if (AOP_TYPE (right) == AOP_LIT)
7471                 {
7472                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7473                   if (bytelit == 0x0FF)
7474                     {
7475                       aopPut (result,
7476                               aopGet (left, offset, FALSE, FALSE, NULL),
7477                               offset);
7478                       continue;
7479                     }
7480                   else if (bytelit == 0)
7481                     {
7482                       /* dummy read of volatile operand */
7483                       if (isOperandVolatile (left, FALSE))
7484                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7485                       aopPut (result, zero, offset);
7486                       continue;
7487                     }
7488                   else if (AOP_TYPE (left) == AOP_ACC)
7489                     {
7490                       if (!offset)
7491                         {
7492                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7493                           aopPut (result, "a", offset);
7494                           continue;
7495                         }
7496                       else
7497                         {
7498                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7499                           aopPut (result, "b", offset);
7500                           continue;
7501                         }
7502                     }
7503                 }
7504               // faster than result <- left, anl result,right
7505               // and better if result is SFR
7506               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7507                   && AOP_TYPE(left)==AOP_ACC)
7508                 {
7509                   if (offset)
7510                     emitcode("mov", "a,b");
7511                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7512                 }
7513               else if (AOP_TYPE(left)==AOP_ACC)
7514                 {
7515                   if (!offset)
7516                     {
7517                       bool pushedB = pushB ();
7518                       emitcode("mov", "b,a");
7519                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7520                       emitcode("anl", "a,b");
7521                       popB (pushedB);
7522                     }
7523                   else
7524                     {
7525                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7526                       emitcode("anl", "a,b");
7527                     }
7528                 }
7529               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7530                 {
7531                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7532                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7533                   emitcode ("anl", "a,b");
7534                 }
7535               else if (aopGetUsesAcc (left, offset))
7536                 {
7537                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7538                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7539                 }
7540               else
7541                 {
7542                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7543                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7544                 }
7545               aopPut (result, "a", offset);
7546             }
7547         }
7548     }
7549
7550 release:
7551   freeAsmop (result, NULL, ic, TRUE);
7552   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7553   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7554 }
7555
7556 /*-----------------------------------------------------------------*/
7557 /* genOr  - code for or                                            */
7558 /*-----------------------------------------------------------------*/
7559 static void
7560 genOr (iCode * ic, iCode * ifx)
7561 {
7562   operand *left, *right, *result;
7563   int size, offset = 0;
7564   unsigned long lit = 0L;
7565   int bytelit = 0;
7566   bool     pushResult;
7567
7568   D (emitcode (";", "genOr"));
7569
7570   AOP_OP_3_NOFATAL (ic, pushResult);
7571   AOP_SET_LOCALS (ic);
7572
7573   if (pushResult)
7574   {
7575       genFarFarLogicOp(ic, "orl");
7576       return;
7577   }
7578
7579
7580 #ifdef DEBUG_TYPE
7581   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7582             AOP_TYPE (result),
7583             AOP_TYPE (left), AOP_TYPE (right));
7584   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7585             AOP_SIZE (result),
7586             AOP_SIZE (left), AOP_SIZE (right));
7587 #endif
7588
7589   /* if left is a literal & right is not then exchange them */
7590   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7591 #ifdef LOGIC_OPS_BROKEN
7592    || AOP_NEEDSACC (left) // I think this is a net loss now.
7593 #endif
7594       )
7595     {
7596       operand *tmp = right;
7597       right = left;
7598       left = tmp;
7599     }
7600
7601   /* if result = right then exchange them */
7602   if (sameRegs (AOP (result), AOP (right)))
7603     {
7604       operand *tmp = right;
7605       right = left;
7606       left = tmp;
7607     }
7608
7609   /* if right is bit then exchange them */
7610   if (AOP_TYPE (right) == AOP_CRY &&
7611       AOP_TYPE (left) != AOP_CRY)
7612     {
7613       operand *tmp = right;
7614       right = left;
7615       left = tmp;
7616     }
7617   if (AOP_TYPE (right) == AOP_LIT)
7618     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7619
7620   size = AOP_SIZE (result);
7621
7622   // if(bit | yy)
7623   // xx = bit | yy;
7624   if (AOP_TYPE (left) == AOP_CRY)
7625     {
7626       if (AOP_TYPE (right) == AOP_LIT)
7627         {
7628           // c = bit | literal;
7629           if (lit)
7630             {
7631               // lit != 0 => result = 1
7632               if (AOP_TYPE (result) == AOP_CRY)
7633                 {
7634                   if (size)
7635                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7636                   else if (ifx)
7637                     continueIfTrue (ifx);
7638                   goto release;
7639                 }
7640               emitcode ("setb", "c");
7641             }
7642           else
7643             {
7644               // lit == 0 => result = left
7645               if (size && sameRegs (AOP (result), AOP (left)))
7646                 goto release;
7647               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7648             }
7649         }
7650       else
7651         {
7652           if (AOP_TYPE (right) == AOP_CRY)
7653             {
7654               // c = bit | bit;
7655               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7656               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7657             }
7658           else
7659             {
7660               // c = bit | val;
7661               symbol *tlbl = newiTempLabel (NULL);
7662               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7663                 emitcode ("setb", "c");
7664               emitcode ("jb", "%s,!tlabel",
7665                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7666               toBoolean (right);
7667               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7668               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7669                 {
7670                   jmpTrueOrFalse (ifx, tlbl);
7671                   goto release;
7672                 }
7673               else
7674                 {
7675                   CLRC;
7676                   emitLabel (tlbl);
7677                 }
7678             }
7679         }
7680       // bit = c
7681       // val = c
7682       if (size)
7683         outBitC (result);
7684       // if(bit | ...)
7685       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7686            genIfxJump (ifx, "c");
7687       goto release;
7688     }
7689
7690   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7691   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7692   if ((AOP_TYPE (right) == AOP_LIT) &&
7693       (AOP_TYPE (result) == AOP_CRY) &&
7694       (AOP_TYPE (left) != AOP_CRY))
7695     {
7696       if (lit)
7697         {
7698           // result = 1
7699           if (size)
7700             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7701           else
7702             continueIfTrue (ifx);
7703           goto release;
7704         }
7705       else
7706         {
7707           // lit = 0, result = boolean(left)
7708           if (size)
7709             emitcode ("setb", "c");
7710           toBoolean (right);
7711           if (size)
7712             {
7713               symbol *tlbl = newiTempLabel (NULL);
7714               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7715               CLRC;
7716               emitLabel (tlbl);
7717             }
7718           else
7719             {
7720               genIfxJump (ifx, "a");
7721               goto release;
7722             }
7723         }
7724       outBitC (result);
7725       goto release;
7726     }
7727
7728   /* if left is same as result */
7729   if (sameRegs (AOP (result), AOP (left)))
7730     {
7731       for (; size--; offset++)
7732         {
7733           if (AOP_TYPE (right) == AOP_LIT)
7734             {
7735               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7736               if (bytelit == 0)
7737                 {
7738                   /* dummy read of volatile operand */
7739                   if (isOperandVolatile (left, FALSE))
7740                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7741                   else
7742                     continue;
7743                 }
7744               else if (bytelit == 0x0FF)
7745                 {
7746                   aopPut (result, "#0xFF", offset);
7747                 }
7748               else if (IS_AOP_PREG (left))
7749                 {
7750                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7751                   emitcode ("orl", "a,%s",
7752                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7753                   aopPut (result, "a", offset);
7754                 }
7755               else
7756                 {
7757                   emitcode ("orl", "%s,%s",
7758                             aopGet (left, offset, FALSE, TRUE, NULL),
7759                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7760                 }
7761             }
7762           else
7763             {
7764               if (AOP_TYPE (left) == AOP_ACC)
7765                 {
7766                   if (offset)
7767                     emitcode("mov", "a,b");
7768                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7769                 }
7770               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7771                 {
7772                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7773                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7774                   emitcode ("orl", "a,b");
7775                   aopPut (result, "a", offset);
7776                 }
7777               else if (aopGetUsesAcc (left, offset))
7778                 {
7779                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7780                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7781                   aopPut (result, "a", offset);
7782                 }
7783               else
7784                 {
7785                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7786                   if (IS_AOP_PREG (left))
7787                     {
7788                       emitcode ("orl", "a,%s",
7789                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7790                       aopPut (result, "a", offset);
7791                     }
7792                   else
7793                     {
7794                       emitcode ("orl", "%s,a",
7795                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7796                     }
7797                 }
7798             }
7799         }
7800     }
7801   else
7802     {
7803       // left & result in different registers
7804       if (AOP_TYPE (result) == AOP_CRY)
7805         {
7806           // result = bit
7807           // if(size), result in bit
7808           // if(!size && ifx), conditional oper: if(left | right)
7809           symbol *tlbl = newiTempLabel (NULL);
7810           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7811           if (size)
7812             emitcode ("setb", "c");
7813           while (sizer--)
7814             {
7815               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7816                   && AOP_TYPE(left)==AOP_ACC)
7817                 {
7818                   if (offset)
7819                     emitcode("mov", "a,b");
7820                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7821                 }
7822               else if (AOP_TYPE(left)==AOP_ACC)
7823                 {
7824                   if (!offset)
7825                     {
7826                       bool pushedB = pushB ();
7827                       emitcode("mov", "b,a");
7828                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7829                       emitcode("orl", "a,b");
7830                       popB (pushedB);
7831                     }
7832                   else
7833                     {
7834                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7835                       emitcode("orl", "a,b");
7836                     }
7837                 }
7838               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7839                 {
7840                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7841                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7842                   emitcode ("orl", "a,b");
7843                 }
7844               else if (aopGetUsesAcc (left, offset))
7845                 {
7846                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7847                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7848                 }
7849               else
7850                 {
7851                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7852                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7853               }
7854
7855               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7856               offset++;
7857             }
7858           if (size)
7859             {
7860               CLRC;
7861               emitLabel (tlbl);
7862               outBitC (result);
7863             }
7864           else if (ifx)
7865             jmpTrueOrFalse (ifx, tlbl);
7866           else
7867             emitLabel (tlbl);
7868         }
7869       else
7870         {
7871             _startLazyDPSEvaluation();
7872           for (; (size--); offset++)
7873             {
7874               // normal case
7875               // result = left | right
7876               if (AOP_TYPE (right) == AOP_LIT)
7877                 {
7878                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7879                   if (bytelit == 0)
7880                     {
7881                       aopPut (result,
7882                               aopGet (left, offset, FALSE, FALSE, NULL),
7883                               offset);
7884                       continue;
7885                     }
7886                   else if (bytelit == 0x0FF)
7887                     {
7888                       /* dummy read of volatile operand */
7889                       if (isOperandVolatile (left, FALSE))
7890                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7891                       aopPut (result, "#0xFF", offset);
7892                       continue;
7893                     }
7894                 }
7895               // faster than result <- left, orl result,right
7896               // and better if result is SFR
7897               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7898                   && AOP_TYPE(left)==AOP_ACC)
7899                 {
7900                   if (offset)
7901                     emitcode("mov", "a,b");
7902                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7903                 }
7904               else if (AOP_TYPE(left)==AOP_ACC)
7905                 {
7906                   if (!offset)
7907                     {
7908                       bool pushedB = pushB ();
7909                       emitcode("mov", "b,a");
7910                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7911                       emitcode("orl", "a,b");
7912                       popB (pushedB);
7913                     }
7914                   else
7915                     {
7916                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7917                       emitcode("orl", "a,b");
7918                     }
7919                 }
7920               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7921                 {
7922                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7923                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7924                   emitcode ("orl", "a,b");
7925                 }
7926               else if (aopGetUsesAcc (left, offset))
7927                 {
7928                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7929                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7930                 }
7931               else
7932                 {
7933                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7934                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7935                 }
7936               aopPut (result, "a", offset);
7937             }
7938             _endLazyDPSEvaluation();
7939         }
7940     }
7941
7942 release:
7943   freeAsmop (result, NULL, ic, TRUE);
7944   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7945   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7946 }
7947
7948 /*-----------------------------------------------------------------*/
7949 /* genXor - code for xclusive or                                   */
7950 /*-----------------------------------------------------------------*/
7951 static void
7952 genXor (iCode * ic, iCode * ifx)
7953 {
7954   operand *left, *right, *result;
7955   int size, offset = 0;
7956   unsigned long lit = 0L;
7957   int bytelit = 0;
7958   bool pushResult;
7959
7960   D (emitcode (";", "genXor"));
7961
7962   AOP_OP_3_NOFATAL (ic, pushResult);
7963   AOP_SET_LOCALS (ic);
7964
7965   if (pushResult)
7966   {
7967       genFarFarLogicOp(ic, "xrl");
7968       return;
7969   }
7970
7971 #ifdef DEBUG_TYPE
7972   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7973             AOP_TYPE (result),
7974             AOP_TYPE (left), AOP_TYPE (right));
7975   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7976             AOP_SIZE (result),
7977             AOP_SIZE (left), AOP_SIZE (right));
7978 #endif
7979
7980   /* if left is a literal & right is not ||
7981      if left needs acc & right does not */
7982   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7983 #ifdef LOGIC_OPS_BROKEN
7984       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7985 #endif
7986      )
7987     {
7988       operand *tmp = right;
7989       right = left;
7990       left = tmp;
7991     }
7992
7993   /* if result = right then exchange them */
7994   if (sameRegs (AOP (result), AOP (right)))
7995     {
7996       operand *tmp = right;
7997       right = left;
7998       left = tmp;
7999     }
8000
8001   /* if right is bit then exchange them */
8002   if (AOP_TYPE (right) == AOP_CRY &&
8003       AOP_TYPE (left) != AOP_CRY)
8004     {
8005       operand *tmp = right;
8006       right = left;
8007       left = tmp;
8008     }
8009   if (AOP_TYPE (right) == AOP_LIT)
8010     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8011
8012   size = AOP_SIZE (result);
8013
8014   // if(bit ^ yy)
8015   // xx = bit ^ yy;
8016   if (AOP_TYPE (left) == AOP_CRY)
8017     {
8018       if (AOP_TYPE (right) == AOP_LIT)
8019         {
8020           // c = bit & literal;
8021           if (lit >> 1)
8022             {
8023               // lit>>1  != 0 => result = 1
8024               if (AOP_TYPE (result) == AOP_CRY)
8025                 {
8026                   if (size)
8027                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8028                   else if (ifx)
8029                     continueIfTrue (ifx);
8030                   goto release;
8031                 }
8032               emitcode ("setb", "c");
8033             }
8034           else
8035             {
8036               // lit == (0 or 1)
8037               if (lit == 0)
8038                 {
8039                   // lit == 0, result = left
8040                   if (size && sameRegs (AOP (result), AOP (left)))
8041                     goto release;
8042                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8043                 }
8044               else
8045                 {
8046                   // lit == 1, result = not(left)
8047                   if (size && sameRegs (AOP (result), AOP (left)))
8048                     {
8049                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8050                       goto release;
8051                     }
8052                   else
8053                     {
8054                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8055                       emitcode ("cpl", "c");
8056                     }
8057                 }
8058             }
8059         }
8060       else
8061         {
8062           // right != literal
8063           symbol *tlbl = newiTempLabel (NULL);
8064           if (AOP_TYPE (right) == AOP_CRY)
8065             {
8066               // c = bit ^ bit;
8067               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8068             }
8069           else
8070             {
8071               int sizer = AOP_SIZE (right);
8072               // c = bit ^ val
8073               // if val>>1 != 0, result = 1
8074               emitcode ("setb", "c");
8075               while (sizer)
8076                 {
8077                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8078                   if (sizer == 1)
8079                     // test the msb of the lsb
8080                     emitcode ("anl", "a,#!constbyte",0xfe);
8081                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8082                   sizer--;
8083                 }
8084               // val = (0,1)
8085               emitcode ("rrc", "a");
8086             }
8087           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8088           emitcode ("cpl", "c");
8089           emitLabel (tlbl);
8090         }
8091       // bit = c
8092       // val = c
8093       if (size)
8094         outBitC (result);
8095       // if(bit | ...)
8096       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8097         genIfxJump (ifx, "c");
8098       goto release;
8099     }
8100
8101   /* if left is same as result */
8102   if (sameRegs (AOP (result), AOP (left)))
8103     {
8104       for (; size--; offset++)
8105         {
8106           if (AOP_TYPE (right) == AOP_LIT)
8107             {
8108               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8109               if (bytelit == 0)
8110                 {
8111                   /* dummy read of volatile operand */
8112                   if (isOperandVolatile (left, FALSE))
8113                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8114                   else
8115                     continue;
8116                 }
8117               else if (IS_AOP_PREG (left))
8118                 {
8119                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8120                   emitcode ("xrl", "a,%s",
8121                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8122                   aopPut (result, "a", offset);
8123                 }
8124               else
8125                 {
8126                   emitcode ("xrl", "%s,%s",
8127                             aopGet (left, offset, FALSE, TRUE, NULL),
8128                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8129                 }
8130             }
8131           else
8132             {
8133               if (AOP_TYPE (left) == AOP_ACC)
8134                 {
8135                   if (offset)
8136                     emitcode("mov", "a,b");
8137                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8138                 }
8139               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8140                 {
8141                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8142                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8143                   emitcode ("xrl", "a,b");
8144                   aopPut (result, "a", offset);
8145                 }
8146               else if (aopGetUsesAcc (left, offset))
8147                 {
8148                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8149                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8150                   aopPut (result, "a", offset);
8151                 }
8152               else
8153                 {
8154                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8155                   if (IS_AOP_PREG (left))
8156                     {
8157                       emitcode ("xrl", "a,%s",
8158                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8159                       aopPut (result, "a", offset);
8160                     }
8161                   else
8162                     emitcode ("xrl", "%s,a",
8163                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8164                 }
8165             }
8166         }
8167     }
8168   else
8169     {
8170       // left & result in different registers
8171       if (AOP_TYPE (result) == AOP_CRY)
8172         {
8173           // result = bit
8174           // if(size), result in bit
8175           // if(!size && ifx), conditional oper: if(left ^ right)
8176           symbol *tlbl = newiTempLabel (NULL);
8177           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8178
8179           if (size)
8180             emitcode ("setb", "c");
8181           while (sizer--)
8182             {
8183               if ((AOP_TYPE (right) == AOP_LIT) &&
8184                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8185                 {
8186                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8187                 }
8188               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8189                   && AOP_TYPE(left)==AOP_ACC)
8190                 {
8191                   if (offset)
8192                     emitcode("mov", "a,b");
8193                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8194                 }
8195               else if (AOP_TYPE(left)==AOP_ACC)
8196                 {
8197                   if (!offset)
8198                     {
8199                       bool pushedB = pushB ();
8200                       emitcode("mov", "b,a");
8201                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8202                       emitcode("xrl", "a,b");
8203                       popB (pushedB);
8204                     }
8205                   else
8206                     {
8207                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8208                       emitcode("xrl", "a,b");
8209                     }
8210                 }
8211               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8212                 {
8213                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8214                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8215                   emitcode ("xrl", "a,b");
8216                 }
8217               else if (aopGetUsesAcc (left, offset))
8218                 {
8219                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8220                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8221                 }
8222               else
8223                 {
8224                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8225                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8226                 }
8227
8228               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8229               offset++;
8230             }
8231           if (size)
8232             {
8233               CLRC;
8234               emitLabel (tlbl);
8235               outBitC (result);
8236             }
8237           else if (ifx)
8238             jmpTrueOrFalse (ifx, tlbl);
8239         }
8240       else
8241         {
8242         for (; (size--); offset++)
8243           {
8244             // normal case
8245             // result = left ^ right
8246             if (AOP_TYPE (right) == AOP_LIT)
8247               {
8248                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8249                 if (bytelit == 0)
8250                   {
8251                     aopPut (result,
8252                             aopGet (left, offset, FALSE, FALSE, NULL),
8253                             offset);
8254                     continue;
8255                   }
8256                 D (emitcode (";", "better literal XOR."));
8257                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8258                 emitcode ("xrl", "a, %s",
8259                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8260               }
8261             else
8262               {
8263                 // faster than result <- left, anl result,right
8264                 // and better if result is SFR
8265                 if (AOP_TYPE (left) == AOP_ACC)
8266                   {
8267                     emitcode ("xrl", "a,%s",
8268                               aopGet (right, offset,
8269                                       FALSE, FALSE, DP2_RESULT_REG));
8270                   }
8271                 else
8272                   {
8273                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8274                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8275                       {
8276                           emitcode("mov", "b,a");
8277                           rOp = "b";
8278                       }
8279
8280                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8281                       emitcode ("xrl", "a,%s", rOp);
8282                   }
8283               }
8284             aopPut (result, "a", offset);
8285           }
8286         }
8287     }
8288
8289 release:
8290   freeAsmop (result, NULL, ic, TRUE);
8291   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8292   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8293 }
8294
8295 /*-----------------------------------------------------------------*/
8296 /* genInline - write the inline code out                           */
8297 /*-----------------------------------------------------------------*/
8298 static void
8299 genInline (iCode * ic)
8300 {
8301   char *buffer, *bp, *bp1;
8302
8303   D (emitcode (";", "genInline"));
8304
8305   _G.inLine += (!options.asmpeep);
8306
8307   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8308
8309   /* emit each line as a code */
8310   while (*bp)
8311     {
8312       if (*bp == '\n')
8313         {
8314           *bp++ = '\0';
8315           emitcode (bp1, "");
8316           bp1 = bp;
8317         }
8318       else
8319         {
8320           /* Add \n for labels, not dirs such as c:\mydir */
8321           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8322             {
8323               bp++;
8324               *bp = '\0';
8325               bp++;
8326               emitcode (bp1, "");
8327               bp1 = bp;
8328             }
8329           else
8330             bp++;
8331         }
8332     }
8333   if (bp1 != bp)
8334     emitcode (bp1, "");
8335   /*     emitcode("",buffer); */
8336   _G.inLine -= (!options.asmpeep);
8337 }
8338
8339 /*-----------------------------------------------------------------*/
8340 /* genRRC - rotate right with carry                                */
8341 /*-----------------------------------------------------------------*/
8342 static void
8343 genRRC (iCode * ic)
8344 {
8345   operand *left, *result;
8346   int     size, offset;
8347   char *l;
8348
8349   D (emitcode (";", "genRRC"));
8350
8351   /* rotate right with carry */
8352   left = IC_LEFT (ic);
8353   result = IC_RESULT (ic);
8354   aopOp (left, ic, FALSE, FALSE);
8355   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8356
8357   /* move it to the result */
8358   size = AOP_SIZE (result);
8359   offset = size - 1;
8360   CLRC;
8361
8362   _startLazyDPSEvaluation ();
8363   while (size--)
8364     {
8365       l = aopGet (left, offset, FALSE, FALSE, NULL);
8366       MOVA (l);
8367       emitcode ("rrc", "a");
8368       if (AOP_SIZE (result) > 1)
8369         aopPut (result, "a", offset--);
8370     }
8371   _endLazyDPSEvaluation ();
8372
8373   /* now we need to put the carry into the
8374      highest order byte of the result */
8375   if (AOP_SIZE (result) > 1)
8376     {
8377       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8378       MOVA (l);
8379     }
8380   emitcode ("mov", "acc.7,c");
8381   aopPut (result, "a", AOP_SIZE (result) - 1);
8382   freeAsmop (result, NULL, ic, TRUE);
8383   freeAsmop (left, NULL, ic, TRUE);
8384 }
8385
8386 /*-----------------------------------------------------------------*/
8387 /* genRLC - generate code for rotate left with carry               */
8388 /*-----------------------------------------------------------------*/
8389 static void
8390 genRLC (iCode * ic)
8391 {
8392   operand *left, *result;
8393   int size, offset;
8394   char *l;
8395
8396   D (emitcode (";", "genRLC"));
8397
8398   /* rotate right with carry */
8399   left = IC_LEFT (ic);
8400   result = IC_RESULT (ic);
8401   aopOp (left, ic, FALSE, FALSE);
8402   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8403
8404   /* move it to the result */
8405   size = AOP_SIZE (result);
8406   offset = 0;
8407   if (size--)
8408     {
8409       l = aopGet (left, offset, FALSE, FALSE, NULL);
8410       MOVA (l);
8411       emitcode ("add", "a,acc");
8412       if (AOP_SIZE (result) > 1)
8413         {
8414           aopPut (result, "a", offset++);
8415         }
8416
8417       _startLazyDPSEvaluation ();
8418       while (size--)
8419         {
8420           l = aopGet (left, offset, FALSE, FALSE, NULL);
8421           MOVA (l);
8422           emitcode ("rlc", "a");
8423           if (AOP_SIZE (result) > 1)
8424             aopPut (result, "a", offset++);
8425         }
8426       _endLazyDPSEvaluation ();
8427     }
8428   /* now we need to put the carry into the
8429      highest order byte of the result */
8430   if (AOP_SIZE (result) > 1)
8431     {
8432       l = aopGet (result, 0, FALSE, FALSE, NULL);
8433       MOVA (l);
8434     }
8435   emitcode ("mov", "acc.0,c");
8436   aopPut (result, "a", 0);
8437   freeAsmop (result, NULL, ic, TRUE);
8438   freeAsmop (left, NULL, ic, TRUE);
8439 }
8440
8441 /*-----------------------------------------------------------------*/
8442 /* genGetHbit - generates code get highest order bit               */
8443 /*-----------------------------------------------------------------*/
8444 static void
8445 genGetHbit (iCode * ic)
8446 {
8447   operand *left, *result;
8448
8449   D (emitcode (";", "genGetHbit"));
8450
8451   left = IC_LEFT (ic);
8452   result = IC_RESULT (ic);
8453   aopOp (left, ic, FALSE, FALSE);
8454   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8455
8456   /* get the highest order byte into a */
8457   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8458   if (AOP_TYPE (result) == AOP_CRY)
8459     {
8460       emitcode ("rlc", "a");
8461       outBitC (result);
8462     }
8463   else
8464     {
8465       emitcode ("rl", "a");
8466       emitcode ("anl", "a,#1");
8467       outAcc (result);
8468     }
8469
8470
8471   freeAsmop (result, NULL, ic, TRUE);
8472   freeAsmop (left, NULL, ic, TRUE);
8473 }
8474
8475 /*-----------------------------------------------------------------*/
8476 /* genSwap - generates code to swap nibbles or bytes               */
8477 /*-----------------------------------------------------------------*/
8478 static void
8479 genSwap (iCode * ic)
8480 {
8481   operand *left, *result;
8482
8483   D(emitcode (";", "genSwap"));
8484
8485   left = IC_LEFT (ic);
8486   result = IC_RESULT (ic);
8487   aopOp (left, ic, FALSE, FALSE);
8488   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8489
8490   _startLazyDPSEvaluation ();
8491   switch (AOP_SIZE (left))
8492     {
8493     case 1: /* swap nibbles in byte */
8494       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8495       emitcode ("swap", "a");
8496       aopPut (result, "a", 0);
8497       break;
8498     case 2: /* swap bytes in word */
8499       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8500         {
8501           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8502           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8503           aopPut (result, "a", 1);
8504         }
8505       else if (operandsEqu (left, result))
8506         {
8507           char * reg = "a";
8508           bool pushedB = FALSE, leftInB = FALSE;
8509
8510           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8511           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8512             {
8513               pushedB = pushB ();
8514               emitcode ("mov", "b,a");
8515               reg = "b";
8516               leftInB = TRUE;
8517             }
8518           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8519           aopPut (result, reg, 1);
8520
8521           if (leftInB)
8522             popB (pushedB);
8523         }
8524       else
8525         {
8526           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8527           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8528         }
8529       break;
8530     default:
8531       wassertl(FALSE, "unsupported SWAP operand size");
8532     }
8533   _endLazyDPSEvaluation ();
8534
8535   freeAsmop (result, NULL, ic, TRUE);
8536   freeAsmop (left, NULL, ic, TRUE);
8537 }
8538
8539 /*-----------------------------------------------------------------*/
8540 /* AccRol - rotate left accumulator by known count                 */
8541 /*-----------------------------------------------------------------*/
8542 static void
8543 AccRol (int shCount)
8544 {
8545   shCount &= 0x0007;            // shCount : 0..7
8546
8547   switch (shCount)
8548     {
8549     case 0:
8550       break;
8551     case 1:
8552       emitcode ("rl", "a");
8553       break;
8554     case 2:
8555       emitcode ("rl", "a");
8556       emitcode ("rl", "a");
8557       break;
8558     case 3:
8559       emitcode ("swap", "a");
8560       emitcode ("rr", "a");
8561       break;
8562     case 4:
8563       emitcode ("swap", "a");
8564       break;
8565     case 5:
8566       emitcode ("swap", "a");
8567       emitcode ("rl", "a");
8568       break;
8569     case 6:
8570       emitcode ("rr", "a");
8571       emitcode ("rr", "a");
8572       break;
8573     case 7:
8574       emitcode ("rr", "a");
8575       break;
8576     }
8577 }
8578
8579 /*-----------------------------------------------------------------*/
8580 /* AccLsh - left shift accumulator by known count                  */
8581 /*-----------------------------------------------------------------*/
8582 static void
8583 AccLsh (int shCount)
8584 {
8585   if (shCount != 0)
8586     {
8587       if (shCount == 1)
8588         emitcode ("add", "a,acc");
8589       else if (shCount == 2)
8590         {
8591           emitcode ("add", "a,acc");
8592           emitcode ("add", "a,acc");
8593         }
8594       else
8595         {
8596           /* rotate left accumulator */
8597           AccRol (shCount);
8598           /* and kill the lower order bits */
8599           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8600         }
8601     }
8602 }
8603
8604 /*-----------------------------------------------------------------*/
8605 /* AccRsh - right shift accumulator by known count                 */
8606 /*-----------------------------------------------------------------*/
8607 static void
8608 AccRsh (int shCount)
8609 {
8610   if (shCount != 0)
8611     {
8612       if (shCount == 1)
8613         {
8614           CLRC;
8615           emitcode ("rrc", "a");
8616         }
8617       else
8618         {
8619           /* rotate right accumulator */
8620           AccRol (8 - shCount);
8621           /* and kill the higher order bits */
8622           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8623         }
8624     }
8625 }
8626
8627 #ifdef BETTER_LITERAL_SHIFT
8628 /*-----------------------------------------------------------------*/
8629 /* AccSRsh - signed right shift accumulator by known count                 */
8630 /*-----------------------------------------------------------------*/
8631 static void
8632 AccSRsh (int shCount)
8633 {
8634   symbol *tlbl;
8635   if (shCount != 0)
8636     {
8637       if (shCount == 1)
8638         {
8639           emitcode ("mov", "c,acc.7");
8640           emitcode ("rrc", "a");
8641         }
8642       else if (shCount == 2)
8643         {
8644           emitcode ("mov", "c,acc.7");
8645           emitcode ("rrc", "a");
8646           emitcode ("mov", "c,acc.7");
8647           emitcode ("rrc", "a");
8648         }
8649       else
8650         {
8651           tlbl = newiTempLabel (NULL);
8652           /* rotate right accumulator */
8653           AccRol (8 - shCount);
8654           /* and kill the higher order bits */
8655           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8656           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8657           emitcode ("orl", "a,#!constbyte",
8658                     (unsigned char) ~SRMask[shCount]);
8659           emitLabel (tlbl);
8660         }
8661     }
8662 }
8663 #endif
8664
8665 #ifdef BETTER_LITERAL_SHIFT
8666 /*-----------------------------------------------------------------*/
8667 /* shiftR1Left2Result - shift right one byte from left to result   */
8668 /*-----------------------------------------------------------------*/
8669 static void
8670 shiftR1Left2Result (operand * left, int offl,
8671                     operand * result, int offr,
8672                     int shCount, int sign)
8673 {
8674   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8675   /* shift right accumulator */
8676   if (sign)
8677     AccSRsh (shCount);
8678   else
8679     AccRsh (shCount);
8680   aopPut (result, "a", offr);
8681 }
8682 #endif
8683
8684 #ifdef BETTER_LITERAL_SHIFT
8685 /*-----------------------------------------------------------------*/
8686 /* shiftL1Left2Result - shift left one byte from left to result    */
8687 /*-----------------------------------------------------------------*/
8688 static void
8689 shiftL1Left2Result (operand * left, int offl,
8690                     operand * result, int offr, int shCount)
8691 {
8692   char *l;
8693   l = aopGet (left, offl, FALSE, FALSE, NULL);
8694   MOVA (l);
8695   /* shift left accumulator */
8696   AccLsh (shCount);
8697   aopPut (result, "a", offr);
8698 }
8699 #endif
8700
8701 #ifdef BETTER_LITERAL_SHIFT
8702 /*-----------------------------------------------------------------*/
8703 /* movLeft2Result - move byte from left to result                  */
8704 /*-----------------------------------------------------------------*/
8705 static void
8706 movLeft2Result (operand * left, int offl,
8707                 operand * result, int offr, int sign)
8708 {
8709   char *l;
8710   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8711   {
8712       l = aopGet (left, offl, FALSE, FALSE, NULL);
8713
8714       if (*l == '@' && (IS_AOP_PREG (result)))
8715       {
8716           emitcode ("mov", "a,%s", l);
8717           aopPut (result, "a", offr);
8718       }
8719       else
8720       {
8721           if (!sign)
8722             {
8723               aopPut (result, l, offr);
8724             }
8725           else
8726             {
8727               /* MSB sign in acc.7 ! */
8728               if (getDataSize (left) == offl + 1)
8729                 {
8730                   MOVA (l);
8731                   aopPut (result, "a", offr);
8732                 }
8733             }
8734       }
8735   }
8736 }
8737 #endif
8738
8739 #ifdef BETTER_LITERAL_SHIFT
8740 /*-----------------------------------------------------------------*/
8741 /* AccAXRrl1 - right rotate a:x by 1                               */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 AccAXRrl1 (char *x)
8745 {
8746   emitcode ("mov", "c,acc.0");
8747   emitcode ("xch", "a,%s", x);
8748   emitcode ("rrc", "a");
8749   emitcode ("xch", "a,%s", x);
8750   emitcode ("rrc", "a");
8751 }
8752 #endif
8753
8754 #ifdef BETTER_LITERAL_SHIFT
8755 //REMOVE ME!!!
8756 /*-----------------------------------------------------------------*/
8757 /* AccAXLrl1 - left rotate a:x by 1                                */
8758 /*-----------------------------------------------------------------*/
8759 static void
8760 AccAXLrl1 (char *x)
8761 {
8762   emitcode ("mov", "c,acc.7");
8763   emitcode ("xch", "a,%s", x);
8764   emitcode ("rlc", "a");
8765   emitcode ("xch", "a,%s", x);
8766   emitcode ("rlc", "a");
8767 }
8768 #endif
8769
8770 #ifdef BETTER_LITERAL_SHIFT
8771 /*-----------------------------------------------------------------*/
8772 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8773 /*-----------------------------------------------------------------*/
8774 static void
8775 AccAXRsh1 (char *x)
8776 {
8777   emitcode ("rrc", "a");
8778   emitcode ("xch", "a,%s", x);
8779   emitcode ("rrc", "a");
8780   emitcode ("xch", "a,%s", x);
8781 }
8782 #endif
8783
8784 #ifdef BETTER_LITERAL_SHIFT
8785 /*-----------------------------------------------------------------*/
8786 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8787 /*-----------------------------------------------------------------*/
8788 static void
8789 AccAXLsh1 (char *x)
8790 {
8791   emitcode ("xch", "a,%s", x);
8792   emitcode ("add", "a,acc");
8793   emitcode ("xch", "a,%s", x);
8794   emitcode ("rlc", "a");
8795 }
8796 #endif
8797
8798 #ifdef BETTER_LITERAL_SHIFT
8799 /*-----------------------------------------------------------------*/
8800 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8801 /*-----------------------------------------------------------------*/
8802 static void
8803 AccAXLsh (char *x, int shCount)
8804 {
8805   switch (shCount)
8806     {
8807     case 0:
8808       break;
8809     case 1:
8810       AccAXLsh1 (x);
8811       break;
8812     case 2:
8813       AccAXLsh1 (x);
8814       AccAXLsh1 (x);
8815       break;
8816     case 3:
8817     case 4:
8818     case 5:                             // AAAAABBB:CCCCCDDD
8819
8820       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8821
8822       emitcode ("anl", "a,#!constbyte",
8823                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8824
8825       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8826
8827       AccRol (shCount);                 // DDDCCCCC:BBB00000
8828
8829       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8830
8831       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8832
8833       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8834
8835       emitcode ("anl", "a,#!constbyte",
8836                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8837
8838       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8839
8840       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8841
8842       break;
8843     case 6:                             // AAAAAABB:CCCCCCDD
8844       emitcode ("anl", "a,#!constbyte",
8845                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8846 #if 1
8847       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8848       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8849       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8850 #else
8851       emitcode ("mov", "c,acc.0");      // c = B
8852       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8853       emitcode("rrc","a");
8854       emitcode("xch","a,%s", x);
8855       emitcode("rrc","a");
8856       emitcode("mov","c,acc.0"); //<< get correct bit
8857       emitcode("xch","a,%s", x);
8858
8859       emitcode("rrc","a");
8860       emitcode("xch","a,%s", x);
8861       emitcode("rrc","a");
8862       emitcode("xch","a,%s", x);
8863 #endif
8864       break;
8865     case 7:                             // a:x <<= 7
8866
8867       emitcode ("anl", "a,#!constbyte",
8868                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8869
8870       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8871
8872       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8873
8874       break;
8875     default:
8876       break;
8877     }
8878 }
8879 #endif
8880
8881 #ifdef BETTER_LITERAL_SHIFT
8882 //REMOVE ME!!!
8883 /*-----------------------------------------------------------------*/
8884 /* AccAXRsh - right shift a:x known count (0..7)                   */
8885 /*-----------------------------------------------------------------*/
8886 static void
8887 AccAXRsh (char *x, int shCount)
8888 {
8889   switch (shCount)
8890     {
8891     case 0:
8892       break;
8893     case 1:
8894       CLRC;
8895       AccAXRsh1 (x);                    // 0->a:x
8896
8897       break;
8898     case 2:
8899       CLRC;
8900       AccAXRsh1 (x);                    // 0->a:x
8901
8902       CLRC;
8903       AccAXRsh1 (x);                    // 0->a:x
8904
8905       break;
8906     case 3:
8907     case 4:
8908     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8909
8910       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8911
8912       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8913
8914       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8915
8916       emitcode ("anl", "a,#!constbyte",
8917                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8918
8919       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8920
8921       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8922
8923       emitcode ("anl", "a,#!constbyte",
8924                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8925
8926       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8927
8928       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8929
8930       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8931
8932       break;
8933     case 6:                             // AABBBBBB:CCDDDDDD
8934
8935       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8936       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8937
8938       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8939
8940       emitcode ("anl", "a,#!constbyte",
8941                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8942
8943       break;
8944     case 7:                             // ABBBBBBB:CDDDDDDD
8945
8946       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8947
8948       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8949
8950       emitcode ("anl", "a,#!constbyte",
8951                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8952
8953       break;
8954     default:
8955       break;
8956     }
8957 }
8958 #endif
8959
8960 #ifdef BETTER_LITERAL_SHIFT
8961 /*-----------------------------------------------------------------*/
8962 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8963 /*-----------------------------------------------------------------*/
8964 static void
8965 AccAXRshS (char *x, int shCount)
8966 {
8967   symbol *tlbl;
8968   switch (shCount)
8969     {
8970     case 0:
8971       break;
8972     case 1:
8973       emitcode ("mov", "c,acc.7");
8974       AccAXRsh1 (x);                    // s->a:x
8975
8976       break;
8977     case 2:
8978       emitcode ("mov", "c,acc.7");
8979       AccAXRsh1 (x);                    // s->a:x
8980
8981       emitcode ("mov", "c,acc.7");
8982       AccAXRsh1 (x);                    // s->a:x
8983
8984       break;
8985     case 3:
8986     case 4:
8987     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8988
8989       tlbl = newiTempLabel (NULL);
8990       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8991
8992       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8993
8994       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8995
8996       emitcode ("anl", "a,#!constbyte",
8997                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8998
8999       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9000
9001       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9002
9003       emitcode ("anl", "a,#!constbyte",
9004                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9005
9006       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9007
9008       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9009
9010       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9011
9012       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9013       emitcode ("orl", "a,#!constbyte",
9014                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9015
9016       emitLabel (tlbl);
9017       break;                            // SSSSAAAA:BBBCCCCC
9018
9019     case 6:                             // AABBBBBB:CCDDDDDD
9020
9021       tlbl = newiTempLabel (NULL);
9022
9023       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9024       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9025
9026       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9027
9028       emitcode ("anl", "a,#!constbyte",
9029                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9030
9031       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9032       emitcode ("orl", "a,#!constbyte",
9033                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9034
9035       emitLabel (tlbl);
9036       break;
9037     case 7:                             // ABBBBBBB:CDDDDDDD
9038
9039       tlbl = newiTempLabel (NULL);
9040
9041       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9042
9043       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9044
9045       emitcode ("anl", "a,#!constbyte",
9046                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9047
9048       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9049       emitcode ("orl", "a,#!constbyte",
9050                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9051
9052       emitLabel (tlbl);
9053       break;
9054     default:
9055       break;
9056     }
9057 }
9058 #endif
9059
9060 #ifdef BETTER_LITERAL_SHIFT
9061 static void
9062 _loadLeftIntoAx(char    **lsb,
9063                 operand *left,
9064                 operand *result,
9065                 int     offl,
9066                 int     offr)
9067 {
9068   // Get the initial value from left into a pair of registers.
9069   // MSB must be in A, LSB can be any register.
9070   //
9071   // If the result is held in registers, it is an optimization
9072   // if the LSB can be held in the register which will hold the,
9073   // result LSB since this saves us from having to copy it into
9074   // the result following AccAXLsh.
9075   //
9076   // If the result is addressed indirectly, this is not a gain.
9077   if (AOP_NEEDSACC(result))
9078   {
9079        char *leftByte;
9080
9081        _startLazyDPSEvaluation();
9082       if (AOP_TYPE(left) == AOP_DPTR2)
9083        {
9084            // Get MSB in A.
9085            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9086            // get LSB in DP2_RESULT_REG.
9087            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9088            assert(!strcmp(leftByte, DP2_RESULT_REG));
9089        }
9090        else
9091        {
9092            // get LSB into DP2_RESULT_REG
9093            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9094            if (strcmp(leftByte, DP2_RESULT_REG))
9095            {
9096                TR_AP("#7");
9097                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9098            }
9099            // And MSB in A.
9100            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9101            assert(strcmp(leftByte, DP2_RESULT_REG));
9102            MOVA (leftByte);
9103        }
9104        _endLazyDPSEvaluation();
9105        *lsb = DP2_RESULT_REG;
9106   }
9107   else
9108   {
9109       if (sameRegs (AOP (result), AOP (left)) &&
9110         ((offl + MSB16) == offr))
9111       {
9112           /* don't crash result[offr] */
9113           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9114           emitcode ("xch", "a,%s",
9115                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9116       }
9117       else
9118       {
9119           movLeft2Result (left, offl, result, offr, 0);
9120           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9121       }
9122       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9123       assert(strcmp(*lsb,"a"));
9124   }
9125 }
9126
9127 static void
9128 _storeAxResults(char    *lsb,
9129                 operand *result,
9130                 int     offr)
9131 {
9132   _startLazyDPSEvaluation();
9133   if (AOP_NEEDSACC(result))
9134   {
9135       /* We have to explicitly update the result LSB.
9136        */
9137       emitcode ("xch","a,%s", lsb);
9138       aopPut (result, "a", offr);
9139       emitcode ("mov","a,%s", lsb);
9140   }
9141   if (getDataSize (result) > 1)
9142   {
9143       aopPut (result, "a", offr + MSB16);
9144   }
9145   _endLazyDPSEvaluation();
9146 }
9147
9148 /*-----------------------------------------------------------------*/
9149 /* shiftL2Left2Result - shift left two bytes from left to result   */
9150 /*-----------------------------------------------------------------*/
9151 static void
9152 shiftL2Left2Result (operand * left, int offl,
9153                     operand * result, int offr, int shCount)
9154 {
9155   char *lsb;
9156
9157   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9158
9159   AccAXLsh (lsb, shCount);
9160
9161   _storeAxResults(lsb, result, offr);
9162 }
9163 #endif
9164
9165 #ifdef BETTER_LITERAL_SHIFT
9166 /*-----------------------------------------------------------------*/
9167 /* shiftR2Left2Result - shift right two bytes from left to result  */
9168 /*-----------------------------------------------------------------*/
9169 static void
9170 shiftR2Left2Result (operand * left, int offl,
9171                     operand * result, int offr,
9172                     int shCount, int sign)
9173 {
9174   char *lsb;
9175
9176   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9177
9178   /* a:x >> shCount (x = lsb(result)) */
9179   if (sign)
9180   {
9181      AccAXRshS(lsb, shCount);
9182   }
9183   else
9184   {
9185     AccAXRsh(lsb, shCount);
9186   }
9187
9188   _storeAxResults(lsb, result, offr);
9189 }
9190 #endif
9191
9192 /*-----------------------------------------------------------------*/
9193 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9194 /*-----------------------------------------------------------------*/
9195 static void
9196 shiftLLeftOrResult (operand * left, int offl,
9197                     operand * result, int offr, int shCount)
9198 {
9199   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9200   /* shift left accumulator */
9201   AccLsh (shCount);
9202   /* or with result */
9203   emitcode ("orl", "a,%s",
9204             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9205   /* back to result */
9206   aopPut (result, "a", offr);
9207 }
9208
9209 #if 0
9210 //REMOVE ME!!!
9211 /*-----------------------------------------------------------------*/
9212 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9213 /*-----------------------------------------------------------------*/
9214 static void
9215 shiftRLeftOrResult (operand * left, int offl,
9216                     operand * result, int offr, int shCount)
9217 {
9218   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9219   /* shift right accumulator */
9220   AccRsh (shCount);
9221   /* or with result */
9222   emitcode ("orl", "a,%s",
9223             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9224   /* back to result */
9225   aopPut (result, "a", offr);
9226 }
9227 #endif
9228
9229 #ifdef BETTER_LITERAL_SHIFT
9230 /*-----------------------------------------------------------------*/
9231 /* genlshOne - left shift a one byte quantity by known count       */
9232 /*-----------------------------------------------------------------*/
9233 static void
9234 genlshOne (operand * result, operand * left, int shCount)
9235 {
9236   D (emitcode (";", "genlshOne"));
9237
9238   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9239 }
9240 #endif
9241
9242 #ifdef BETTER_LITERAL_SHIFT
9243 /*-----------------------------------------------------------------*/
9244 /* genlshTwo - left shift two bytes by known amount != 0           */
9245 /*-----------------------------------------------------------------*/
9246 static void
9247 genlshTwo (operand * result, operand * left, int shCount)
9248 {
9249   int size;
9250
9251   D (emitcode (";", "genlshTwo"));
9252
9253   size = getDataSize (result);
9254
9255   /* if shCount >= 8 */
9256   if (shCount >= 8)
9257   {
9258       shCount -= 8;
9259
9260       _startLazyDPSEvaluation();
9261
9262       if (size > 1)
9263         {
9264           if (shCount)
9265           {
9266             _endLazyDPSEvaluation();
9267             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9268             aopPut (result, zero, LSB);
9269           }
9270           else
9271           {
9272             movLeft2Result (left, LSB, result, MSB16, 0);
9273             aopPut (result, zero, LSB);
9274             _endLazyDPSEvaluation();
9275           }
9276         }
9277         else
9278         {
9279           aopPut (result, zero, LSB);
9280           _endLazyDPSEvaluation();
9281         }
9282   }
9283
9284   /*  1 <= shCount <= 7 */
9285   else
9286     {
9287       if (size == 1)
9288         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9289       else
9290         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9291     }
9292 }
9293 #endif
9294
9295 #if 0
9296 //REMOVE ME!!!
9297 /*-----------------------------------------------------------------*/
9298 /* shiftLLong - shift left one long from left to result            */
9299 /* offl = LSB or MSB16                                             */
9300 /*-----------------------------------------------------------------*/
9301 static void
9302 shiftLLong (operand * left, operand * result, int offr)
9303 {
9304   char *l;
9305   int size = AOP_SIZE (result);
9306
9307   if (size >= LSB + offr)
9308     {
9309       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9310       MOVA (l);
9311       emitcode ("add", "a,acc");
9312       if (sameRegs (AOP (left), AOP (result)) &&
9313           size >= MSB16 + offr && offr != LSB)
9314         emitcode ("xch", "a,%s",
9315                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9316       else
9317         aopPut (result, "a", LSB + offr);
9318     }
9319
9320   if (size >= MSB16 + offr)
9321     {
9322       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9323         {
9324           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9325           MOVA (l);
9326         }
9327       emitcode ("rlc", "a");
9328       if (sameRegs (AOP (left), AOP (result)) &&
9329           size >= MSB24 + offr && offr != LSB)
9330         emitcode ("xch", "a,%s",
9331                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9332       else
9333         aopPut (result, "a", MSB16 + offr);
9334     }
9335
9336   if (size >= MSB24 + offr)
9337     {
9338       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9339         {
9340           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9341           MOVA (l);
9342         }
9343       emitcode ("rlc", "a");
9344       if (sameRegs (AOP (left), AOP (result)) &&
9345           size >= MSB32 + offr && offr != LSB)
9346         emitcode ("xch", "a,%s",
9347                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9348       else
9349         aopPut (result, "a", MSB24 + offr);
9350     }
9351
9352   if (size > MSB32 + offr)
9353     {
9354       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9355         {
9356           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9357           MOVA (l);
9358         }
9359       emitcode ("rlc", "a");
9360       aopPut (result, "a", MSB32 + offr);
9361     }
9362   if (offr != LSB)
9363     aopPut (result, zero, LSB);
9364 }
9365 #endif
9366
9367 #if 0
9368 //REMOVE ME!!!
9369 /*-----------------------------------------------------------------*/
9370 /* genlshFour - shift four byte by a known amount != 0             */
9371 /*-----------------------------------------------------------------*/
9372 static void
9373 genlshFour (operand * result, operand * left, int shCount)
9374 {
9375   int size;
9376
9377   D (emitcode (";", "genlshFour"));
9378
9379   size = AOP_SIZE (result);
9380
9381   /* if shifting more that 3 bytes */
9382   if (shCount >= 24)
9383     {
9384       shCount -= 24;
9385       if (shCount)
9386         /* lowest order of left goes to the highest
9387            order of the destination */
9388         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9389       else
9390         movLeft2Result (left, LSB, result, MSB32, 0);
9391       aopPut (result, zero, LSB);
9392       aopPut (result, zero, MSB16);
9393       aopPut (result, zero, MSB24);
9394       return;
9395     }
9396
9397   /* more than two bytes */
9398   else if (shCount >= 16)
9399     {
9400       /* lower order two bytes goes to higher order two bytes */
9401       shCount -= 16;
9402       /* if some more remaining */
9403       if (shCount)
9404         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9405       else
9406         {
9407           movLeft2Result (left, MSB16, result, MSB32, 0);
9408           movLeft2Result (left, LSB, result, MSB24, 0);
9409         }
9410       aopPut (result, zero, MSB16);
9411       aopPut (result, zero, LSB);
9412       return;
9413     }
9414
9415   /* if more than 1 byte */
9416   else if (shCount >= 8)
9417     {
9418       /* lower order three bytes goes to higher order  three bytes */
9419       shCount -= 8;
9420       if (size == 2)
9421         {
9422           if (shCount)
9423             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9424           else
9425             movLeft2Result (left, LSB, result, MSB16, 0);
9426         }
9427       else
9428         {                       /* size = 4 */
9429           if (shCount == 0)
9430             {
9431               movLeft2Result (left, MSB24, result, MSB32, 0);
9432               movLeft2Result (left, MSB16, result, MSB24, 0);
9433               movLeft2Result (left, LSB, result, MSB16, 0);
9434               aopPut (result, zero, LSB);
9435             }
9436           else if (shCount == 1)
9437             shiftLLong (left, result, MSB16);
9438           else
9439             {
9440               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9441               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9442               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9443               aopPut (result, zero, LSB);
9444             }
9445         }
9446     }
9447
9448   /* 1 <= shCount <= 7 */
9449   else if (shCount <= 2)
9450     {
9451       shiftLLong (left, result, LSB);
9452       if (shCount == 2)
9453         shiftLLong (result, result, LSB);
9454     }
9455   /* 3 <= shCount <= 7, optimize */
9456   else
9457     {
9458       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9459       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9460       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9461     }
9462 }
9463 #endif
9464
9465 #ifdef BETTER_LITERAL_SHIFT
9466 /*-----------------------------------------------------------------*/
9467 /* genLeftShiftLiteral - left shifting by known count              */
9468 /*-----------------------------------------------------------------*/
9469 static bool
9470 genLeftShiftLiteral (operand * left,
9471                      operand * right,
9472                      operand * result,
9473                      iCode * ic)
9474 {
9475   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9476   int size;
9477
9478   size = getSize (operandType (result));
9479
9480   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9481
9482   /* We only handle certain easy cases so far. */
9483   if ((shCount != 0)
9484    && (shCount < (size * 8))
9485    && (size != 1)
9486    && (size != 2))
9487   {
9488       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9489       return FALSE;
9490   }
9491
9492   freeAsmop (right, NULL, ic, TRUE);
9493
9494   aopOp(left, ic, FALSE, FALSE);
9495   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9496
9497 #if 0 // debug spew
9498   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9499   {
9500         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9501         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9502         {
9503            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9504         }
9505   }
9506   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9507   {
9508         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9509         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9510         {
9511            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9512         }
9513   }
9514 #endif
9515
9516 #if VIEW_SIZE
9517   emitcode ("; shift left ", "result %d, left %d", size,
9518             AOP_SIZE (left));
9519 #endif
9520
9521   /* I suppose that the left size >= result size */
9522   if (shCount == 0)
9523   {
9524         _startLazyDPSEvaluation();
9525         while (size--)
9526         {
9527           movLeft2Result (left, size, result, size, 0);
9528         }
9529         _endLazyDPSEvaluation();
9530   }
9531   else if (shCount >= (size * 8))
9532   {
9533     _startLazyDPSEvaluation();
9534     while (size--)
9535     {
9536       aopPut (result, zero, size);
9537     }
9538     _endLazyDPSEvaluation();
9539   }
9540   else
9541   {
9542       switch (size)
9543         {
9544         case 1:
9545           genlshOne (result, left, shCount);
9546           break;
9547
9548         case 2:
9549           genlshTwo (result, left, shCount);
9550           break;
9551 #if 0
9552         case 4:
9553           genlshFour (result, left, shCount);
9554           break;
9555 #endif
9556         default:
9557           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9558                   "*** ack! mystery literal shift!\n");
9559           break;
9560         }
9561     }
9562   freeAsmop (result, NULL, ic, TRUE);
9563   freeAsmop (left, NULL, ic, TRUE);
9564   return TRUE;
9565 }
9566 #endif
9567
9568 /*-----------------------------------------------------------------*/
9569 /* genLeftShift - generates code for left shifting                 */
9570 /*-----------------------------------------------------------------*/
9571 static void
9572 genLeftShift (iCode * ic)
9573 {
9574   operand *left, *right, *result;
9575   int size, offset;
9576   char *l;
9577   symbol *tlbl, *tlbl1;
9578   bool pushedB;
9579
9580   D (emitcode (";", "genLeftShift"));
9581
9582   right = IC_RIGHT (ic);
9583   left = IC_LEFT (ic);
9584   result = IC_RESULT (ic);
9585
9586   aopOp (right, ic, FALSE, FALSE);
9587
9588
9589 #ifdef BETTER_LITERAL_SHIFT
9590   /* if the shift count is known then do it
9591      as efficiently as possible */
9592   if (AOP_TYPE (right) == AOP_LIT)
9593     {
9594       if (genLeftShiftLiteral (left, right, result, ic))
9595       {
9596         return;
9597       }
9598     }
9599 #endif
9600
9601   /* shift count is unknown then we have to form
9602      a loop get the loop count in B : Note: we take
9603      only the lower order byte since shifting
9604      more that 32 bits make no sense anyway, ( the
9605      largest size of an object can be only 32 bits ) */
9606
9607   pushedB = pushB ();
9608   if (AOP_TYPE (right) == AOP_LIT)
9609   {
9610       /* Really should be handled by genLeftShiftLiteral,
9611        * but since I'm too lazy to fix that today, at least we can make
9612        * some small improvement.
9613        */
9614        emitcode("mov", "b,#!constbyte",
9615                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9616   }
9617   else
9618   {
9619       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9620       emitcode ("inc", "b");
9621   }
9622   freeAsmop (right, NULL, ic, TRUE);
9623   aopOp (left, ic, FALSE, FALSE);
9624   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9625
9626   /* now move the left to the result if they are not the same */
9627   if (!sameRegs (AOP (left), AOP (result)) &&
9628       AOP_SIZE (result) > 1)
9629     {
9630
9631       size = AOP_SIZE (result);
9632       offset = 0;
9633       _startLazyDPSEvaluation ();
9634       while (size--)
9635         {
9636           l = aopGet (left, offset, FALSE, TRUE, NULL);
9637           if (*l == '@' && (IS_AOP_PREG (result)))
9638             {
9639
9640               emitcode ("mov", "a,%s", l);
9641               aopPut (result, "a", offset);
9642             }
9643           else
9644             aopPut (result, l, offset);
9645           offset++;
9646         }
9647       _endLazyDPSEvaluation ();
9648     }
9649
9650   tlbl = newiTempLabel (NULL);
9651   size = AOP_SIZE (result);
9652   offset = 0;
9653   tlbl1 = newiTempLabel (NULL);
9654
9655   /* if it is only one byte then */
9656   if (size == 1)
9657     {
9658       symbol *tlbl1 = newiTempLabel (NULL);
9659
9660       l = aopGet (left, 0, FALSE, FALSE, NULL);
9661       MOVA (l);
9662       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9663       emitLabel (tlbl);
9664       emitcode ("add", "a,acc");
9665       emitLabel (tlbl1);
9666       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9667       popB (pushedB);
9668       aopPut (result, "a", 0);
9669       goto release;
9670     }
9671
9672   reAdjustPreg (AOP (result));
9673
9674   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9675   emitLabel (tlbl);
9676   l = aopGet (result, offset, FALSE, FALSE, NULL);
9677   MOVA (l);
9678   emitcode ("add", "a,acc");
9679   aopPut (result, "a", offset++);
9680   _startLazyDPSEvaluation ();
9681   while (--size)
9682     {
9683       l = aopGet (result, offset, FALSE, FALSE, NULL);
9684       MOVA (l);
9685       emitcode ("rlc", "a");
9686       aopPut (result, "a", offset++);
9687     }
9688   _endLazyDPSEvaluation ();
9689   reAdjustPreg (AOP (result));
9690
9691   emitLabel (tlbl1);
9692   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9693   popB (pushedB);
9694 release:
9695   freeAsmop (result, NULL, ic, TRUE);
9696   freeAsmop (left, NULL, ic, TRUE);
9697 }
9698
9699 #ifdef BETTER_LITERAL_SHIFT
9700 /*-----------------------------------------------------------------*/
9701 /* genrshOne - right shift a one byte quantity by known count      */
9702 /*-----------------------------------------------------------------*/
9703 static void
9704 genrshOne (operand * result, operand * left,
9705            int shCount, int sign)
9706 {
9707   D (emitcode (";", "genrshOne"));
9708
9709   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9710 }
9711 #endif
9712
9713 #ifdef BETTER_LITERAL_SHIFT
9714 /*-----------------------------------------------------------------*/
9715 /* genrshTwo - right shift two bytes by known amount != 0          */
9716 /*-----------------------------------------------------------------*/
9717 static void
9718 genrshTwo (operand * result, operand * left,
9719            int shCount, int sign)
9720 {
9721   D (emitcode (";", "genrshTwo"));
9722
9723   /* if shCount >= 8 */
9724   if (shCount >= 8)
9725     {
9726       shCount -= 8;
9727       _startLazyDPSEvaluation();
9728       if (shCount)
9729         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9730       else
9731         movLeft2Result (left, MSB16, result, LSB, sign);
9732       addSign (result, MSB16, sign);
9733       _endLazyDPSEvaluation();
9734     }
9735
9736   /*  1 <= shCount <= 7 */
9737   else
9738     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9739 }
9740 #endif
9741
9742 /*-----------------------------------------------------------------*/
9743 /* shiftRLong - shift right one long from left to result           */
9744 /* offl = LSB or MSB16                                             */
9745 /*-----------------------------------------------------------------*/
9746 static void
9747 shiftRLong (operand * left, int offl,
9748             operand * result, int sign)
9749 {
9750   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9751
9752   if (overlapping && offl>1)
9753     {
9754       // we are in big trouble, but this shouldn't happen
9755       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9756     }
9757
9758   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9759
9760   if (offl==MSB16)
9761     {
9762       // shift is > 8
9763       if (sign)
9764         {
9765           emitcode ("rlc", "a");
9766           emitcode ("subb", "a,acc");
9767           emitcode ("xch", "a,%s",
9768                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9769         }
9770       else
9771         {
9772           aopPut (result, zero, MSB32);
9773         }
9774     }
9775
9776   if (!sign)
9777     {
9778       emitcode ("clr", "c");
9779     }
9780   else
9781     {
9782       emitcode ("mov", "c,acc.7");
9783     }
9784
9785   emitcode ("rrc", "a");
9786
9787   if (overlapping && offl==MSB16)
9788     {
9789       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9790     }
9791   else
9792     {
9793       aopPut (result, "a", MSB32 - offl);
9794       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9795     }
9796
9797   emitcode ("rrc", "a");
9798
9799   if (overlapping && offl==MSB16)
9800     {
9801       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9802     }
9803   else
9804     {
9805       aopPut (result, "a", MSB24 - offl);
9806       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9807     }
9808
9809   emitcode ("rrc", "a");
9810   if (offl != LSB)
9811     {
9812       aopPut (result, "a", MSB16 - offl);
9813     }
9814   else
9815     {
9816       if (overlapping && offl==MSB16)
9817         {
9818           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9819         }
9820       else
9821         {
9822           aopPut (result, "a", MSB16 - offl);
9823           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9824         }
9825       emitcode ("rrc", "a");
9826       aopPut (result, "a", LSB);
9827     }
9828 }
9829
9830 /*-----------------------------------------------------------------*/
9831 /* genrshFour - shift four byte by a known amount != 0             */
9832 /*-----------------------------------------------------------------*/
9833 static void
9834 genrshFour (operand * result, operand * left,
9835             int shCount, int sign)
9836 {
9837   D (emitcode (";", "genrshFour"));
9838
9839   /* if shifting more that 3 bytes */
9840   if (shCount >= 24)
9841     {
9842       shCount -= 24;
9843       _startLazyDPSEvaluation();
9844       if (shCount)
9845         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9846       else
9847         movLeft2Result (left, MSB32, result, LSB, sign);
9848       addSign (result, MSB16, sign);
9849       _endLazyDPSEvaluation();
9850     }
9851   else if (shCount >= 16)
9852     {
9853       shCount -= 16;
9854       _startLazyDPSEvaluation();
9855       if (shCount)
9856         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9857       else
9858         {
9859           movLeft2Result (left, MSB24, result, LSB, 0);
9860           movLeft2Result (left, MSB32, result, MSB16, sign);
9861         }
9862       addSign (result, MSB24, sign);
9863       _endLazyDPSEvaluation();
9864     }
9865   else if (shCount >= 8)
9866     {
9867       shCount -= 8;
9868       _startLazyDPSEvaluation();
9869       if (shCount == 1)
9870         {
9871           shiftRLong (left, MSB16, result, sign);
9872         }
9873       else if (shCount == 0)
9874         {
9875           movLeft2Result (left, MSB16, result, LSB, 0);
9876           movLeft2Result (left, MSB24, result, MSB16, 0);
9877           movLeft2Result (left, MSB32, result, MSB24, sign);
9878           addSign (result, MSB32, sign);
9879         }
9880       else
9881         {
9882           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9883           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9884           /* the last shift is signed */
9885           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9886           addSign (result, MSB32, sign);
9887         }
9888         _endLazyDPSEvaluation();
9889     }
9890   else
9891     {
9892       /* 1 <= shCount <= 7 */
9893       if (shCount <= 2)
9894         {
9895           shiftRLong (left, LSB, result, sign);
9896           if (shCount == 2)
9897             shiftRLong (result, LSB, result, sign);
9898         }
9899       else
9900         {
9901           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9902           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9903           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9904         }
9905     }
9906 }
9907
9908 #ifdef BETTER_LITERAL_SHIFT
9909 /*-----------------------------------------------------------------*/
9910 /* genRightShiftLiteral - right shifting by known count            */
9911 /*-----------------------------------------------------------------*/
9912 static bool
9913 genRightShiftLiteral (operand * left,
9914                       operand * right,
9915                       operand * result,
9916                       iCode * ic,
9917                       int sign)
9918 {
9919   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9920   int size;
9921
9922   size = getSize (operandType (result));
9923
9924   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9925
9926   /* We only handle certain easy cases so far. */
9927   if ((shCount != 0)
9928    && (shCount < (size * 8))
9929    && (size != 1)
9930    && (size != 2)
9931    && (size != 4))
9932   {
9933       D(emitcode (";", "genRightShiftLiteral wimping out"););
9934       return FALSE;
9935   }
9936
9937   freeAsmop (right, NULL, ic, TRUE);
9938
9939   aopOp (left, ic, FALSE, FALSE);
9940   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9941
9942 #if VIEW_SIZE
9943   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9944             AOP_SIZE (left));
9945 #endif
9946
9947   /* test the LEFT size !!! */
9948
9949   /* I suppose that the left size >= result size */
9950   if (shCount == 0)
9951   {
9952       size = getDataSize (result);
9953       _startLazyDPSEvaluation();
9954       while (size--)
9955         movLeft2Result (left, size, result, size, 0);
9956       _endLazyDPSEvaluation();
9957   }
9958   else if (shCount >= (size * 8))
9959     {
9960       if (sign)
9961         {
9962           /* get sign in acc.7 */
9963           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9964         }
9965       addSign (result, LSB, sign);
9966     }
9967   else
9968     {
9969       switch (size)
9970         {
9971         case 1:
9972           genrshOne (result, left, shCount, sign);
9973           break;
9974
9975         case 2:
9976           genrshTwo (result, left, shCount, sign);
9977           break;
9978 #if 1
9979         case 4:
9980           genrshFour (result, left, shCount, sign);
9981           break;
9982 #endif
9983         default:
9984           break;
9985         }
9986     }
9987   freeAsmop (result, NULL, ic, TRUE);
9988   freeAsmop (left, NULL, ic, TRUE);
9989
9990   return TRUE;
9991 }
9992 #endif
9993
9994 /*-----------------------------------------------------------------*/
9995 /* genSignedRightShift - right shift of signed number              */
9996 /*-----------------------------------------------------------------*/
9997 static void
9998 genSignedRightShift (iCode * ic)
9999 {
10000   operand *right, *left, *result;
10001   int size, offset;
10002   char *l;
10003   symbol *tlbl, *tlbl1;
10004   bool pushedB;
10005
10006   D (emitcode (";", "genSignedRightShift"));
10007
10008   /* we do it the hard way put the shift count in b
10009      and loop thru preserving the sign */
10010
10011   right = IC_RIGHT (ic);
10012   left = IC_LEFT (ic);
10013   result = IC_RESULT (ic);
10014
10015   aopOp (right, ic, FALSE, FALSE);
10016
10017 #ifdef BETTER_LITERAL_SHIFT
10018   if (AOP_TYPE (right) == AOP_LIT)
10019     {
10020       if (genRightShiftLiteral (left, right, result, ic, 1))
10021       {
10022         return;
10023       }
10024     }
10025 #endif
10026   /* shift count is unknown then we have to form
10027      a loop get the loop count in B : Note: we take
10028      only the lower order byte since shifting
10029      more that 32 bits make no sense anyway, ( the
10030      largest size of an object can be only 32 bits ) */
10031
10032   pushedB = pushB ();
10033   if (AOP_TYPE (right) == AOP_LIT)
10034   {
10035       /* Really should be handled by genRightShiftLiteral,
10036        * but since I'm too lazy to fix that today, at least we can make
10037        * some small improvement.
10038        */
10039        emitcode("mov", "b,#!constbyte",
10040                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10041   }
10042   else
10043   {
10044         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10045         emitcode ("inc", "b");
10046   }
10047   freeAsmop (right, NULL, ic, TRUE);
10048   aopOp (left, ic, FALSE, FALSE);
10049   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10050
10051   /* now move the left to the result if they are not the
10052      same */
10053   if (!sameRegs (AOP (left), AOP (result)) &&
10054       AOP_SIZE (result) > 1)
10055     {
10056
10057       size = AOP_SIZE (result);
10058       offset = 0;
10059       _startLazyDPSEvaluation ();
10060       while (size--)
10061         {
10062           l = aopGet (left, offset, FALSE, TRUE, NULL);
10063           if (*l == '@' && IS_AOP_PREG (result))
10064             {
10065
10066               emitcode ("mov", "a,%s", l);
10067               aopPut (result, "a", offset);
10068             }
10069           else
10070             aopPut (result, l, offset);
10071           offset++;
10072         }
10073       _endLazyDPSEvaluation ();
10074     }
10075
10076   /* mov the highest order bit to OVR */
10077   tlbl = newiTempLabel (NULL);
10078   tlbl1 = newiTempLabel (NULL);
10079
10080   size = AOP_SIZE (result);
10081   offset = size - 1;
10082   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10083   emitcode ("rlc", "a");
10084   emitcode ("mov", "ov,c");
10085   /* if it is only one byte then */
10086   if (size == 1)
10087     {
10088       l = aopGet (left, 0, FALSE, FALSE, NULL);
10089       MOVA (l);
10090       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10091       emitLabel (tlbl);
10092       emitcode ("mov", "c,ov");
10093       emitcode ("rrc", "a");
10094       emitLabel (tlbl1);
10095       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10096       popB (pushedB);
10097       aopPut (result, "a", 0);
10098       goto release;
10099     }
10100
10101   reAdjustPreg (AOP (result));
10102   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10103   emitLabel (tlbl);
10104   emitcode ("mov", "c,ov");
10105   _startLazyDPSEvaluation ();
10106   while (size--)
10107     {
10108       l = aopGet (result, offset, FALSE, FALSE, NULL);
10109       MOVA (l);
10110       emitcode ("rrc", "a");
10111       aopPut (result, "a", offset--);
10112     }
10113   _endLazyDPSEvaluation ();
10114   reAdjustPreg (AOP (result));
10115   emitLabel (tlbl1);
10116   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10117   popB (pushedB);
10118
10119 release:
10120   freeAsmop (result, NULL, ic, TRUE);
10121   freeAsmop (left, NULL, ic, TRUE);
10122 }
10123
10124 /*-----------------------------------------------------------------*/
10125 /* genRightShift - generate code for right shifting                */
10126 /*-----------------------------------------------------------------*/
10127 static void
10128 genRightShift (iCode * ic)
10129 {
10130   operand *right, *left, *result;
10131   sym_link *letype;
10132   int size, offset;
10133   char *l;
10134   symbol *tlbl, *tlbl1;
10135   bool pushedB;
10136
10137   D (emitcode (";", "genRightShift"));
10138
10139   /* if signed then we do it the hard way preserve the
10140      sign bit moving it inwards */
10141   letype = getSpec (operandType (IC_LEFT (ic)));
10142
10143   if (!SPEC_USIGN (letype))
10144     {
10145       genSignedRightShift (ic);
10146       return;
10147     }
10148
10149   /* signed & unsigned types are treated the same : i.e. the
10150      signed is NOT propagated inwards : quoting from the
10151      ANSI - standard : "for E1 >> E2, is equivalent to division
10152      by 2**E2 if unsigned or if it has a non-negative value,
10153      otherwise the result is implementation defined ", MY definition
10154      is that the sign does not get propagated */
10155
10156   right = IC_RIGHT (ic);
10157   left = IC_LEFT (ic);
10158   result = IC_RESULT (ic);
10159
10160   aopOp (right, ic, FALSE, FALSE);
10161
10162 #ifdef BETTER_LITERAL_SHIFT
10163   /* if the shift count is known then do it
10164      as efficiently as possible */
10165   if (AOP_TYPE (right) == AOP_LIT)
10166     {
10167       if (genRightShiftLiteral (left, right, result, ic, 0))
10168       {
10169         return;
10170       }
10171     }
10172 #endif
10173
10174   /* shift count is unknown then we have to form
10175      a loop get the loop count in B : Note: we take
10176      only the lower order byte since shifting
10177      more that 32 bits make no sense anyway, ( the
10178      largest size of an object can be only 32 bits ) */
10179
10180   pushedB = pushB ();
10181   if (AOP_TYPE (right) == AOP_LIT)
10182   {
10183       /* Really should be handled by genRightShiftLiteral,
10184        * but since I'm too lazy to fix that today, at least we can make
10185        * some small improvement.
10186        */
10187        emitcode("mov", "b,#!constbyte",
10188                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10189   }
10190   else
10191   {
10192       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10193       emitcode ("inc", "b");
10194   }
10195   freeAsmop (right, NULL, ic, TRUE);
10196   aopOp (left, ic, FALSE, FALSE);
10197   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10198
10199   /* now move the left to the result if they are not the
10200      same */
10201   if (!sameRegs (AOP (left), AOP (result)) &&
10202       AOP_SIZE (result) > 1)
10203     {
10204       size = AOP_SIZE (result);
10205       offset = 0;
10206       _startLazyDPSEvaluation ();
10207       while (size--)
10208         {
10209           l = aopGet (left, offset, FALSE, TRUE, NULL);
10210           if (*l == '@' && IS_AOP_PREG (result))
10211             {
10212
10213               emitcode ("mov", "a,%s", l);
10214               aopPut (result, "a", offset);
10215             }
10216           else
10217             aopPut (result, l, offset);
10218           offset++;
10219         }
10220       _endLazyDPSEvaluation ();
10221     }
10222
10223   tlbl = newiTempLabel (NULL);
10224   tlbl1 = newiTempLabel (NULL);
10225   size = AOP_SIZE (result);
10226   offset = size - 1;
10227
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       CLRC;
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   CLRC;
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
10259   emitLabel (tlbl1);
10260   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10261   popB (pushedB);
10262
10263 release:
10264   freeAsmop (result, NULL, ic, TRUE);
10265   freeAsmop (left, NULL, ic, TRUE);
10266 }
10267
10268 /*-----------------------------------------------------------------*/
10269 /* emitPtrByteGet - emits code to get a byte into A through a      */
10270 /*                  pointer register (R0, R1, or DPTR). The        */
10271 /*                  original value of A can be preserved in B.     */
10272 /*-----------------------------------------------------------------*/
10273 static void
10274 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10275 {
10276   switch (p_type)
10277     {
10278     case IPOINTER:
10279     case POINTER:
10280       if (preserveAinB)
10281         emitcode ("mov", "b,a");
10282       emitcode ("mov", "a,@%s", rname);
10283       break;
10284
10285     case PPOINTER:
10286       if (preserveAinB)
10287         emitcode ("mov", "b,a");
10288       emitcode ("movx", "a,@%s", rname);
10289       break;
10290
10291     case FPOINTER:
10292       if (preserveAinB)
10293         emitcode ("mov", "b,a");
10294       emitcode ("movx", "a,@dptr");
10295       break;
10296
10297     case CPOINTER:
10298       if (preserveAinB)
10299         emitcode ("mov", "b,a");
10300       emitcode ("clr", "a");
10301       emitcode ("movc", "a,@a+dptr");
10302       break;
10303
10304     case GPOINTER:
10305       if (preserveAinB)
10306         {
10307           emitcode ("push", "b");
10308           emitcode ("push", "acc");
10309         }
10310       emitcode ("lcall", "__gptrget");
10311       if (preserveAinB)
10312         emitcode ("pop", "b");
10313       break;
10314     }
10315 }
10316
10317 /*-----------------------------------------------------------------*/
10318 /* emitPtrByteSet - emits code to set a byte from src through a    */
10319 /*                  pointer register (R0, R1, or DPTR).            */
10320 /*-----------------------------------------------------------------*/
10321 static void
10322 emitPtrByteSet (char *rname, int p_type, char *src)
10323 {
10324   switch (p_type)
10325     {
10326     case IPOINTER:
10327     case POINTER:
10328       if (*src=='@')
10329         {
10330           MOVA (src);
10331           emitcode ("mov", "@%s,a", rname);
10332         }
10333       else
10334         emitcode ("mov", "@%s,%s", rname, src);
10335       break;
10336
10337     case PPOINTER:
10338       MOVA (src);
10339       emitcode ("movx", "@%s,a", rname);
10340       break;
10341
10342     case FPOINTER:
10343       MOVA (src);
10344       emitcode ("movx", "@dptr,a");
10345       break;
10346
10347     case GPOINTER:
10348       MOVA (src);
10349       emitcode ("lcall", "__gptrput");
10350       break;
10351     }
10352 }
10353
10354 /*-----------------------------------------------------------------*/
10355 /* genUnpackBits - generates code for unpacking bits               */
10356 /*-----------------------------------------------------------------*/
10357 static void
10358 genUnpackBits (operand * result, char *rname, int ptype)
10359 {
10360   int offset = 0;       /* result byte offset */
10361   int rsize;            /* result size */
10362   int rlen = 0;         /* remaining bitfield length */
10363   sym_link *etype;      /* bitfield type information */
10364   int blen;             /* bitfield length */
10365   int bstr;             /* bitfield starting bit within byte */
10366
10367   D(emitcode (";", "genUnpackBits"));
10368
10369   etype = getSpec (operandType (result));
10370   rsize = getSize (operandType (result));
10371   blen = SPEC_BLEN (etype);
10372   bstr = SPEC_BSTR (etype);
10373
10374   /* If the bitfield length is less than a byte */
10375   if (blen < 8)
10376     {
10377       emitPtrByteGet (rname, ptype, FALSE);
10378       AccRol (8 - bstr);
10379       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10380       if (!SPEC_USIGN (etype))
10381         {
10382           /* signed bitfield */
10383           symbol *tlbl = newiTempLabel (NULL);
10384
10385           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10386           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10387           emitLabel (tlbl);
10388         }
10389       aopPut (result, "a", offset++);
10390       goto finish;
10391     }
10392
10393   /* Bit field did not fit in a byte. Copy all
10394      but the partial byte at the end.  */
10395   for (rlen=blen;rlen>=8;rlen-=8)
10396     {
10397       emitPtrByteGet (rname, ptype, FALSE);
10398       aopPut (result, "a", offset++);
10399       if (rlen>8)
10400         emitcode ("inc", "%s", rname);
10401     }
10402
10403   /* Handle the partial byte at the end */
10404   if (rlen)
10405     {
10406       emitPtrByteGet (rname, ptype, FALSE);
10407       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10408       if (!SPEC_USIGN (etype))
10409         {
10410           /* signed bitfield */
10411           symbol *tlbl = newiTempLabel (NULL);
10412
10413           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10414           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10415           emitLabel (tlbl);
10416         }
10417       aopPut (result, "a", offset++);
10418     }
10419
10420 finish:
10421   if (offset < rsize)
10422     {
10423       char *source;
10424
10425       if (SPEC_USIGN (etype))
10426         source = zero;
10427       else
10428         {
10429           /* signed bitfield: sign extension with 0x00 or 0xff */
10430           emitcode ("rlc", "a");
10431           emitcode ("subb", "a,acc");
10432
10433           source = "a";
10434         }
10435       rsize -= offset;
10436       while (rsize--)
10437         aopPut (result, source, offset++);
10438     }
10439 }
10440
10441
10442 /*-----------------------------------------------------------------*/
10443 /* genDataPointerGet - generates code when ptr offset is known     */
10444 /*-----------------------------------------------------------------*/
10445 static void
10446 genDataPointerGet (operand * left,
10447                    operand * result,
10448                    iCode * ic)
10449 {
10450   char *l;
10451   char buffer[256];
10452   int size, offset = 0;
10453   aopOp (result, ic, TRUE, FALSE);
10454
10455   /* get the string representation of the name */
10456   l = aopGet (left, 0, FALSE, TRUE, NULL);
10457   size = AOP_SIZE (result);
10458   _startLazyDPSEvaluation ();
10459   while (size--)
10460     {
10461         if (offset)
10462         {
10463             SNPRINTF (buffer, sizeof(buffer),
10464                       "(%s + %d)", l + 1, offset);
10465         }
10466         else
10467         {
10468             SNPRINTF (buffer, sizeof(buffer),
10469                       "%s", l + 1);
10470         }
10471       aopPut (result, buffer, offset++);
10472     }
10473   _endLazyDPSEvaluation ();
10474
10475   freeAsmop (result, NULL, ic, TRUE);
10476   freeAsmop (left, NULL, ic, TRUE);
10477 }
10478
10479 /*-----------------------------------------------------------------*/
10480 /* genNearPointerGet - emitcode for near pointer fetch             */
10481 /*-----------------------------------------------------------------*/
10482 static void
10483 genNearPointerGet (operand * left,
10484                    operand * result,
10485                    iCode * ic,
10486                    iCode *pi)
10487 {
10488   asmop *aop = NULL;
10489   regs *preg;
10490   char *rname;
10491   sym_link *rtype, *retype, *letype;
10492   sym_link *ltype = operandType (left);
10493   char buffer[80];
10494
10495   rtype = operandType (result);
10496   retype = getSpec (rtype);
10497   letype = getSpec (ltype);
10498
10499   aopOp (left, ic, FALSE, FALSE);
10500
10501   /* if left is rematerialisable and
10502      result is not bitfield variable type and
10503      the left is pointer to data space i.e
10504      lower 128 bytes of space */
10505   if (AOP_TYPE (left) == AOP_IMMD &&
10506       !IS_BITFIELD (retype) &&
10507       !IS_BITFIELD (letype) &&
10508       DCL_TYPE (ltype) == POINTER)
10509     {
10510       genDataPointerGet (left, result, ic);
10511       return;
10512     }
10513
10514   /* if the value is already in a pointer register
10515      then don't need anything more */
10516   if (!AOP_INPREG (AOP (left)))
10517     {
10518       /* otherwise get a free pointer register */
10519       aop = newAsmop (0);
10520       preg = getFreePtr (ic, &aop, FALSE);
10521       emitcode ("mov", "%s,%s",
10522                 preg->name,
10523                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10524       rname = preg->name;
10525     }
10526   else
10527     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10528
10529   freeAsmop (left, NULL, ic, TRUE);
10530   aopOp (result, ic, FALSE, FALSE);
10531
10532   /* if bitfield then unpack the bits */
10533   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10534     genUnpackBits (result, rname, POINTER);
10535   else
10536     {
10537       /* we have can just get the values */
10538       int size = AOP_SIZE (result);
10539       int offset = 0;
10540
10541       while (size--)
10542         {
10543           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10544             {
10545
10546               emitcode ("mov", "a,@%s", rname);
10547               aopPut (result, "a", offset);
10548             }
10549           else
10550             {
10551               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10552               aopPut (result, buffer, offset);
10553             }
10554           offset++;
10555           if (size || pi)
10556             emitcode ("inc", "%s", rname);
10557         }
10558     }
10559
10560   /* now some housekeeping stuff */
10561   if (aop)      /* we had to allocate for this iCode */
10562     {
10563       if (pi) { /* post increment present */
10564         aopPut (left, rname, 0);
10565       }
10566       freeAsmop (NULL, aop, ic, TRUE);
10567     }
10568   else
10569     {
10570       /* we did not allocate which means left
10571          already in a pointer register, then
10572          if size > 0 && this could be used again
10573          we have to point it back to where it
10574          belongs */
10575       if (AOP_SIZE (result) > 1 &&
10576           !OP_SYMBOL (left)->remat &&
10577           (OP_SYMBOL (left)->liveTo > ic->seq ||
10578            ic->depth) &&
10579           !pi)
10580         {
10581           int size = AOP_SIZE (result) - 1;
10582           while (size--)
10583             emitcode ("dec", "%s", rname);
10584         }
10585     }
10586
10587   /* done */
10588   freeAsmop (result, NULL, ic, TRUE);
10589   if (pi) pi->generated = 1;
10590 }
10591
10592 /*-----------------------------------------------------------------*/
10593 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10594 /*-----------------------------------------------------------------*/
10595 static void
10596 genPagedPointerGet (operand * left,
10597                     operand * result,
10598                     iCode * ic,
10599                     iCode * pi)
10600 {
10601   asmop *aop = NULL;
10602   regs *preg;
10603   char *rname;
10604   sym_link *rtype, *retype, *letype;
10605
10606   rtype = operandType (result);
10607   retype = getSpec (rtype);
10608   letype = getSpec (operandType (left));
10609   aopOp (left, ic, FALSE, FALSE);
10610
10611   /* if the value is already in a pointer register
10612      then don't need anything more */
10613   if (!AOP_INPREG (AOP (left)))
10614     {
10615       /* otherwise get a free pointer register */
10616       aop = newAsmop (0);
10617       preg = getFreePtr (ic, &aop, FALSE);
10618       emitcode ("mov", "%s,%s",
10619                 preg->name,
10620                 aopGet (left, 0, FALSE, TRUE, NULL));
10621       rname = preg->name;
10622     }
10623   else
10624     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10625
10626   freeAsmop (left, NULL, ic, TRUE);
10627   aopOp (result, ic, FALSE, FALSE);
10628
10629   /* if bitfield then unpack the bits */
10630   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10631     genUnpackBits (result, rname, PPOINTER);
10632   else
10633     {
10634       /* we have can just get the values */
10635       int size = AOP_SIZE (result);
10636       int offset = 0;
10637
10638       while (size--)
10639         {
10640
10641           emitcode ("movx", "a,@%s", rname);
10642           aopPut (result, "a", offset);
10643
10644           offset++;
10645
10646           if (size || pi)
10647             emitcode ("inc", "%s", rname);
10648         }
10649     }
10650
10651   /* now some housekeeping stuff */
10652   if (aop)      /* we had to allocate for this iCode */
10653     {
10654       if (pi)
10655         aopPut (left, rname, 0);
10656       freeAsmop (NULL, aop, ic, TRUE);
10657     }
10658   else
10659     {
10660       /* we did not allocate which means left
10661          already in a pointer register, then
10662          if size > 0 && this could be used again
10663          we have to point it back to where it
10664          belongs */
10665       if (AOP_SIZE (result) > 1 &&
10666           !OP_SYMBOL (left)->remat &&
10667           (OP_SYMBOL (left)->liveTo > ic->seq ||
10668            ic->depth) &&
10669           !pi)
10670         {
10671           int size = AOP_SIZE (result) - 1;
10672           while (size--)
10673             emitcode ("dec", "%s", rname);
10674         }
10675     }
10676
10677   /* done */
10678   freeAsmop (result, NULL, ic, TRUE);
10679   if (pi) pi->generated = 1;
10680 }
10681
10682 /*-----------------------------------------------------------------*/
10683 /* genFarPointerGet - get value from far space                     */
10684 /*-----------------------------------------------------------------*/
10685 static void
10686 genFarPointerGet (operand * left,
10687                   operand * result, iCode * ic, iCode *pi)
10688 {
10689   int size, offset, dopi=1;
10690   sym_link *retype = getSpec (operandType (result));
10691   sym_link *letype = getSpec (operandType (left));
10692   D (emitcode (";", "genFarPointerGet"););
10693
10694   aopOp (left, ic, FALSE, FALSE);
10695
10696   /* if the operand is already in dptr
10697      then we do nothing else we move the value to dptr */
10698   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10699     {
10700       /* if this is rematerializable */
10701       if (AOP_TYPE (left) == AOP_IMMD)
10702         {
10703           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10704         }
10705       else
10706         {
10707           /* we need to get it byte by byte */
10708           _startLazyDPSEvaluation ();
10709           if (AOP_TYPE (left) != AOP_DPTR)
10710             {
10711               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10712               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10713               if (options.model == MODEL_FLAT24)
10714                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10715             }
10716           else
10717             {
10718               /* We need to generate a load to DPTR indirect through DPTR. */
10719               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10720               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10721               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10722               if (options.model == MODEL_FLAT24)
10723                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10724               emitcode ("pop", "dph");
10725               emitcode ("pop", "dpl");
10726               dopi =0;
10727             }
10728           _endLazyDPSEvaluation ();
10729         }
10730     }
10731   /* so dptr now contains the address */
10732   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10733
10734   /* if bit then unpack */
10735   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10736       if (AOP_INDPTRn(left)) {
10737           genSetDPTR(AOP(left)->aopu.dptr);
10738       }
10739       genUnpackBits (result, "dptr", FPOINTER);
10740       if (AOP_INDPTRn(left)) {
10741           genSetDPTR(0);
10742       }
10743   } else
10744     {
10745       size = AOP_SIZE (result);
10746       offset = 0;
10747
10748       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10749           while (size--) {
10750               genSetDPTR(AOP(left)->aopu.dptr);
10751               emitcode ("movx", "a,@dptr");
10752               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10753                   emitcode ("inc", "dptr");
10754               genSetDPTR (0);
10755               aopPut (result, "a", offset++);
10756           }
10757       } else {
10758           _startLazyDPSEvaluation ();
10759           while (size--) {
10760               if (AOP_INDPTRn(left)) {
10761                   genSetDPTR(AOP(left)->aopu.dptr);
10762               } else {
10763                   genSetDPTR (0);
10764               }
10765               _flushLazyDPS ();
10766
10767               emitcode ("movx", "a,@dptr");
10768               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10769                   emitcode ("inc", "dptr");
10770
10771               aopPut (result, "a", offset++);
10772           }
10773           _endLazyDPSEvaluation ();
10774       }
10775     }
10776   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10777       if (!AOP_INDPTRn(left)) {
10778           _startLazyDPSEvaluation ();
10779           aopPut (left, "dpl", 0);
10780           aopPut (left, "dph", 1);
10781           if (options.model == MODEL_FLAT24)
10782               aopPut (left, "dpx", 2);
10783           _endLazyDPSEvaluation ();
10784       }
10785     pi->generated = 1;
10786   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10787              AOP_SIZE(result) > 1 &&
10788              IS_SYMOP(left) &&
10789              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10790
10791       size = AOP_SIZE (result) - 1;
10792       if (AOP_INDPTRn(left)) {
10793           genSetDPTR(AOP(left)->aopu.dptr);
10794       }
10795       while (size--) emitcode ("lcall","__decdptr");
10796       if (AOP_INDPTRn(left)) {
10797           genSetDPTR(0);
10798       }
10799   }
10800
10801   freeAsmop (result, NULL, ic, TRUE);
10802   freeAsmop (left, NULL, ic, TRUE);
10803 }
10804
10805 /*-----------------------------------------------------------------*/
10806 /* genCodePointerGet - get value from code space                   */
10807 /*-----------------------------------------------------------------*/
10808 static void
10809 genCodePointerGet (operand * left,
10810                     operand * result, iCode * ic, iCode *pi)
10811 {
10812   int size, offset, dopi=1;
10813   sym_link *retype = getSpec (operandType (result));
10814
10815   aopOp (left, ic, FALSE, FALSE);
10816
10817   /* if the operand is already in dptr
10818      then we do nothing else we move the value to dptr */
10819   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10820     {
10821       /* if this is rematerializable */
10822       if (AOP_TYPE (left) == AOP_IMMD)
10823         {
10824           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10825         }
10826       else
10827         {                       /* we need to get it byte by byte */
10828           _startLazyDPSEvaluation ();
10829           if (AOP_TYPE (left) != AOP_DPTR)
10830             {
10831               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10832               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10833               if (options.model == MODEL_FLAT24)
10834                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10835             }
10836           else
10837             {
10838               /* We need to generate a load to DPTR indirect through DPTR. */
10839               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10840               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10841               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10842               if (options.model == MODEL_FLAT24)
10843                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10844               emitcode ("pop", "dph");
10845               emitcode ("pop", "dpl");
10846               dopi=0;
10847             }
10848           _endLazyDPSEvaluation ();
10849         }
10850     }
10851   /* so dptr now contains the address */
10852   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10853
10854   /* if bit then unpack */
10855   if (IS_BITFIELD (retype)) {
10856       if (AOP_INDPTRn(left)) {
10857           genSetDPTR(AOP(left)->aopu.dptr);
10858       }
10859       genUnpackBits (result, "dptr", CPOINTER);
10860       if (AOP_INDPTRn(left)) {
10861           genSetDPTR(0);
10862       }
10863   } else
10864     {
10865       size = AOP_SIZE (result);
10866       offset = 0;
10867       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10868           while (size--) {
10869               genSetDPTR(AOP(left)->aopu.dptr);
10870               emitcode ("clr", "a");
10871               emitcode ("movc", "a,@a+dptr");
10872               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10873                   emitcode ("inc", "dptr");
10874               genSetDPTR (0);
10875               aopPut (result, "a", offset++);
10876           }
10877       } else {
10878           _startLazyDPSEvaluation ();
10879           while (size--)
10880               {
10881                   if (AOP_INDPTRn(left)) {
10882                       genSetDPTR(AOP(left)->aopu.dptr);
10883                   } else {
10884                       genSetDPTR (0);
10885                   }
10886                   _flushLazyDPS ();
10887
10888                   emitcode ("clr", "a");
10889                   emitcode ("movc", "a,@a+dptr");
10890                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10891                       emitcode ("inc", "dptr");
10892                   aopPut (result, "a", offset++);
10893               }
10894           _endLazyDPSEvaluation ();
10895       }
10896     }
10897   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10898       if (!AOP_INDPTRn(left)) {
10899           _startLazyDPSEvaluation ();
10900
10901           aopPut (left, "dpl", 0);
10902           aopPut (left, "dph", 1);
10903           if (options.model == MODEL_FLAT24)
10904               aopPut (left, "dpx", 2);
10905
10906           _endLazyDPSEvaluation ();
10907       }
10908       pi->generated = 1;
10909   } else if (IS_SYMOP(left) &&
10910              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10911              AOP_SIZE(result) > 1 &&
10912              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10913
10914       size = AOP_SIZE (result) - 1;
10915       if (AOP_INDPTRn(left)) {
10916           genSetDPTR(AOP(left)->aopu.dptr);
10917       }
10918       while (size--) emitcode ("lcall","__decdptr");
10919       if (AOP_INDPTRn(left)) {
10920           genSetDPTR(0);
10921       }
10922   }
10923
10924   freeAsmop (result, NULL, ic, TRUE);
10925   freeAsmop (left, NULL, ic, TRUE);
10926 }
10927
10928 /*-----------------------------------------------------------------*/
10929 /* genGenPointerGet - get value from generic pointer space         */
10930 /*-----------------------------------------------------------------*/
10931 static void
10932 genGenPointerGet (operand * left,
10933                   operand * result, iCode * ic, iCode * pi)
10934 {
10935   int size, offset;
10936   bool pushedB;
10937   sym_link *retype = getSpec (operandType (result));
10938   sym_link *letype = getSpec (operandType (left));
10939
10940   D (emitcode (";", "genGenPointerGet"));
10941
10942   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10943
10944   pushedB = pushB ();
10945   /* if the operand is already in dptr
10946      then we do nothing else we move the value to dptr */
10947   if (AOP_TYPE (left) != AOP_STR)
10948     {
10949       /* if this is rematerializable */
10950       if (AOP_TYPE (left) == AOP_IMMD)
10951         {
10952           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10953           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10954             {
10955               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10956             }
10957           else
10958             {
10959               emitcode ("mov", "b,#%d", pointerCode (retype));
10960             }
10961         }
10962       else
10963         {                       /* we need to get it byte by byte */
10964           _startLazyDPSEvaluation ();
10965           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10966           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10967           if (options.model == MODEL_FLAT24) {
10968               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10969               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10970           } else {
10971               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10972           }
10973           _endLazyDPSEvaluation ();
10974         }
10975     }
10976
10977   /* so dptr-b now contains the address */
10978   aopOp (result, ic, FALSE, TRUE);
10979
10980   /* if bit then unpack */
10981   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10982   {
10983     genUnpackBits (result, "dptr", GPOINTER);
10984   }
10985   else
10986     {
10987         size = AOP_SIZE (result);
10988         offset = 0;
10989
10990         while (size--)
10991         {
10992             if (size)
10993             {
10994                 // Get two bytes at a time, results in _AP & A.
10995                 // dptr will be incremented ONCE by __gptrgetWord.
10996                 //
10997                 // Note: any change here must be coordinated
10998                 // with the implementation of __gptrgetWord
10999                 // in device/lib/_gptrget.c
11000                 emitcode ("lcall", "__gptrgetWord");
11001                 aopPut (result, "a", offset++);
11002                 aopPut (result, DP2_RESULT_REG, offset++);
11003                 size--;
11004             }
11005             else
11006             {
11007                 // Only one byte to get.
11008                 emitcode ("lcall", "__gptrget");
11009                 aopPut (result, "a", offset++);
11010             }
11011
11012             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11013             {
11014                 emitcode ("inc", "dptr");
11015             }
11016         }
11017     }
11018
11019   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11020     _startLazyDPSEvaluation ();
11021
11022     aopPut (left, "dpl", 0);
11023     aopPut (left, "dph", 1);
11024     if (options.model == MODEL_FLAT24) {
11025         aopPut (left, "dpx", 2);
11026         aopPut (left, "b", 3);
11027     } else  aopPut (left, "b", 2);
11028
11029     _endLazyDPSEvaluation ();
11030
11031     pi->generated = 1;
11032   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11033              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11034
11035       size = AOP_SIZE (result) - 1;
11036       while (size--) emitcode ("lcall","__decdptr");
11037   }
11038   popB (pushedB);
11039
11040   freeAsmop (result, NULL, ic, TRUE);
11041   freeAsmop (left, NULL, ic, TRUE);
11042 }
11043
11044 /*-----------------------------------------------------------------*/
11045 /* genPointerGet - generate code for pointer get                   */
11046 /*-----------------------------------------------------------------*/
11047 static void
11048 genPointerGet (iCode * ic, iCode *pi)
11049 {
11050   operand *left, *result;
11051   sym_link *type, *etype;
11052   int p_type;
11053
11054   D (emitcode (";", "genPointerGet"));
11055
11056   left = IC_LEFT (ic);
11057   result = IC_RESULT (ic);
11058
11059   /* depending on the type of pointer we need to
11060      move it to the correct pointer register */
11061   type = operandType (left);
11062   etype = getSpec (type);
11063   /* if left is of type of pointer then it is simple */
11064   if (IS_PTR (type) && !IS_FUNC (type->next))
11065     p_type = DCL_TYPE (type);
11066   else
11067     {
11068       /* we have to go by the storage class */
11069       p_type = PTR_TYPE (SPEC_OCLS (etype));
11070     }
11071
11072   /* special case when cast remat */
11073   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11074       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11075     {
11076       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11077       type = operandType (left);
11078       p_type = DCL_TYPE (type);
11079     }
11080   /* now that we have the pointer type we assign
11081      the pointer values */
11082   switch (p_type)
11083     {
11084
11085     case POINTER:
11086     case IPOINTER:
11087       genNearPointerGet (left, result, ic, pi);
11088       break;
11089
11090     case PPOINTER:
11091       genPagedPointerGet (left, result, ic, pi);
11092       break;
11093
11094     case FPOINTER:
11095       genFarPointerGet (left, result, ic, pi);
11096       break;
11097
11098     case CPOINTER:
11099       genCodePointerGet (left, result, ic, pi);
11100       break;
11101
11102     case GPOINTER:
11103       genGenPointerGet (left, result, ic, pi);
11104       break;
11105     }
11106 }
11107
11108
11109 /*-----------------------------------------------------------------*/
11110 /* genPackBits - generates code for packed bit storage             */
11111 /*-----------------------------------------------------------------*/
11112 static void
11113 genPackBits (sym_link * etype,
11114              operand * right,
11115              char *rname, int p_type)
11116 {
11117   int offset = 0;       /* source byte offset */
11118   int rlen = 0;         /* remaining bitfield length */
11119   int blen;             /* bitfield length */
11120   int bstr;             /* bitfield starting bit within byte */
11121   int litval;           /* source literal value (if AOP_LIT) */
11122   unsigned char mask;   /* bitmask within current byte */
11123
11124   D(emitcode (";", "genPackBits"));
11125
11126   blen = SPEC_BLEN (etype);
11127   bstr = SPEC_BSTR (etype);
11128
11129   /* If the bitfield length is less than a byte */
11130   if (blen < 8)
11131     {
11132       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11133               (unsigned char) (0xFF >> (8 - bstr)));
11134
11135       if (AOP_TYPE (right) == AOP_LIT)
11136         {
11137           /* Case with a bitfield length <8 and literal source
11138           */
11139           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11140           litval <<= bstr;
11141           litval &= (~mask) & 0xff;
11142           emitPtrByteGet (rname, p_type, FALSE);
11143           if ((mask|litval)!=0xff)
11144             emitcode ("anl","a,#!constbyte", mask);
11145           if (litval)
11146             emitcode ("orl","a,#!constbyte", litval);
11147         }
11148       else
11149         {
11150           if ((blen==1) && (p_type!=GPOINTER))
11151             {
11152               /* Case with a bitfield length == 1 and no generic pointer
11153               */
11154               if (AOP_TYPE (right) == AOP_CRY)
11155                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11156               else
11157                 {
11158                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11159                   emitcode ("rrc","a");
11160                 }
11161               emitPtrByteGet (rname, p_type, FALSE);
11162               emitcode ("mov","acc.%d,c",bstr);
11163             }
11164           else
11165             {
11166               bool pushedB;
11167               /* Case with a bitfield length < 8 and arbitrary source
11168               */
11169               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11170               /* shift and mask source value */
11171               AccLsh (bstr);
11172               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11173
11174               pushedB = pushB ();
11175               /* transfer A to B and get next byte */
11176               emitPtrByteGet (rname, p_type, TRUE);
11177
11178               emitcode ("anl", "a,#!constbyte", mask);
11179               emitcode ("orl", "a,b");
11180               if (p_type == GPOINTER)
11181                 emitcode ("pop", "b");
11182
11183               popB (pushedB);
11184            }
11185         }
11186
11187       emitPtrByteSet (rname, p_type, "a");
11188       return;
11189     }
11190
11191   /* Bit length is greater than 7 bits. In this case, copy  */
11192   /* all except the partial byte at the end                 */
11193   for (rlen=blen;rlen>=8;rlen-=8)
11194     {
11195       emitPtrByteSet (rname, p_type,
11196                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11197       if (rlen>8)
11198         emitcode ("inc", "%s", rname);
11199     }
11200
11201   /* If there was a partial byte at the end */
11202   if (rlen)
11203     {
11204       mask = (((unsigned char) -1 << rlen) & 0xff);
11205
11206       if (AOP_TYPE (right) == AOP_LIT)
11207         {
11208           /* Case with partial byte and literal source
11209           */
11210           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11211           litval >>= (blen-rlen);
11212           litval &= (~mask) & 0xff;
11213           emitPtrByteGet (rname, p_type, FALSE);
11214           if ((mask|litval)!=0xff)
11215             emitcode ("anl","a,#!constbyte", mask);
11216           if (litval)
11217             emitcode ("orl","a,#!constbyte", litval);
11218         }
11219       else
11220         {
11221           bool pushedB;
11222           /* Case with partial byte and arbitrary source
11223           */
11224           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11225           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11226
11227           pushedB = pushB ();
11228           /* transfer A to B and get next byte */
11229           emitPtrByteGet (rname, p_type, TRUE);
11230
11231           emitcode ("anl", "a,#!constbyte", mask);
11232           emitcode ("orl", "a,b");
11233           if (p_type == GPOINTER)
11234             emitcode ("pop", "b");
11235
11236           popB (pushedB);
11237         }
11238       emitPtrByteSet (rname, p_type, "a");
11239     }
11240 }
11241
11242
11243 /*-----------------------------------------------------------------*/
11244 /* genDataPointerSet - remat pointer to data space                 */
11245 /*-----------------------------------------------------------------*/
11246 static void
11247 genDataPointerSet (operand * right,
11248                    operand * result,
11249                    iCode * ic)
11250 {
11251   int size, offset = 0;
11252   char *l, buffer[256];
11253
11254   D (emitcode (";", "genDataPointerSet"));
11255
11256   aopOp (right, ic, FALSE, FALSE);
11257
11258   l = aopGet (result, 0, FALSE, TRUE, NULL);
11259   size = AOP_SIZE (right);
11260   while (size--)
11261     {
11262       if (offset)
11263           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11264       else
11265           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11266       emitcode ("mov", "%s,%s", buffer,
11267                 aopGet (right, offset++, FALSE, FALSE, NULL));
11268     }
11269
11270   freeAsmop (result, NULL, ic, TRUE);
11271   freeAsmop (right, NULL, ic, TRUE);
11272 }
11273
11274 /*-----------------------------------------------------------------*/
11275 /* genNearPointerSet - emitcode for near pointer put                */
11276 /*-----------------------------------------------------------------*/
11277 static void
11278 genNearPointerSet (operand * right,
11279                    operand * result,
11280                    iCode * ic,
11281                    iCode * pi)
11282 {
11283   asmop *aop = NULL;
11284   char *rname, *l;
11285   sym_link *retype, *letype;
11286   sym_link *ptype = operandType (result);
11287
11288   D (emitcode (";", "genNearPointerSet"));
11289
11290   retype = getSpec (operandType (right));
11291   letype = getSpec (ptype);
11292
11293   aopOp (result, ic, FALSE, FALSE);
11294
11295   /* if the result is rematerializable &
11296      in data space & not a bit variable */
11297   if (AOP_TYPE (result) == AOP_IMMD &&
11298       DCL_TYPE (ptype) == POINTER &&
11299       !IS_BITVAR (retype) &&
11300       !IS_BITVAR (letype))
11301     {
11302       genDataPointerSet (right, result, ic);
11303       return;
11304     }
11305
11306   /* if the value is already in a pointer register
11307      then don't need anything more */
11308   if (!AOP_INPREG (AOP (result)))
11309     {
11310       /* otherwise get a free pointer register */
11311       regs *preg;
11312
11313       aop = newAsmop (0);
11314       preg = getFreePtr (ic, &aop, FALSE);
11315       emitcode ("mov", "%s,%s",
11316                 preg->name,
11317                 aopGet (result, 0, FALSE, TRUE, NULL));
11318       rname = preg->name;
11319     }
11320   else
11321     {
11322       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11323     }
11324
11325   aopOp (right, ic, FALSE, FALSE);
11326
11327   /* if bitfield then unpack the bits */
11328   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11329     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11330   else
11331     {
11332       /* we can just get the values */
11333       int size = AOP_SIZE (right);
11334       int offset = 0;
11335
11336       while (size--)
11337         {
11338           l = aopGet (right, offset, FALSE, TRUE, NULL);
11339           if ((*l == '@') || (strcmp (l, "acc") == 0))
11340             {
11341               MOVA (l);
11342               emitcode ("mov", "@%s,a", rname);
11343             }
11344           else
11345             emitcode ("mov", "@%s,%s", rname, l);
11346           if (size || pi)
11347             emitcode ("inc", "%s", rname);
11348           offset++;
11349         }
11350     }
11351
11352   /* now some housekeeping stuff */
11353   if (aop)      /* we had to allocate for this iCode */
11354     {
11355       if (pi)
11356         aopPut (result, rname, 0);
11357       freeAsmop (NULL, aop, ic, TRUE);
11358     }
11359   else
11360     {
11361       /* we did not allocate which means left
11362          already in a pointer register, then
11363          if size > 0 && this could be used again
11364          we have to point it back to where it
11365          belongs */
11366       if (AOP_SIZE (right) > 1 &&
11367           !OP_SYMBOL (result)->remat &&
11368           (OP_SYMBOL (result)->liveTo > ic->seq ||
11369            ic->depth) &&
11370           !pi)
11371         {
11372           int size = AOP_SIZE (right) - 1;
11373           while (size--)
11374             emitcode ("dec", "%s", rname);
11375         }
11376     }
11377
11378   /* done */
11379   if (pi) pi->generated = 1;
11380   freeAsmop (result, NULL, ic, TRUE);
11381   freeAsmop (right, NULL, ic, TRUE);
11382 }
11383
11384 /*-----------------------------------------------------------------*/
11385 /* genPagedPointerSet - emitcode for Paged pointer put             */
11386 /*-----------------------------------------------------------------*/
11387 static void
11388 genPagedPointerSet (operand * right,
11389                     operand * result,
11390                     iCode * ic,
11391                     iCode *pi)
11392 {
11393   asmop *aop = NULL;
11394   char *rname, *l;
11395   sym_link *retype, *letype;
11396
11397   D (emitcode (";", "genPagedPointerSet"));
11398
11399   retype = getSpec (operandType (right));
11400   letype = getSpec (operandType (result));
11401
11402   aopOp (result, ic, FALSE, FALSE);
11403
11404   /* if the value is already in a pointer register
11405      then don't need anything more */
11406   if (!AOP_INPREG (AOP (result)))
11407     {
11408       /* otherwise get a free pointer register */
11409       regs *preg;
11410
11411       aop = newAsmop (0);
11412       preg = getFreePtr (ic, &aop, FALSE);
11413       emitcode ("mov", "%s,%s",
11414                 preg->name,
11415                 aopGet (result, 0, FALSE, TRUE, NULL));
11416       rname = preg->name;
11417     }
11418   else
11419     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11420
11421   aopOp (right, ic, FALSE, FALSE);
11422
11423   /* if bitfield then unpack the bits */
11424   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11425     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11426   else
11427     {
11428       /* we have can just get the values */
11429       int size = AOP_SIZE (right);
11430       int offset = 0;
11431
11432       while (size--)
11433         {
11434           l = aopGet (right, offset, FALSE, TRUE, NULL);
11435           MOVA (l);
11436           emitcode ("movx", "@%s,a", rname);
11437
11438           if (size || pi)
11439             emitcode ("inc", "%s", rname);
11440
11441           offset++;
11442         }
11443     }
11444
11445   /* now some housekeeping stuff */
11446   if (aop)
11447     {
11448       if (pi)
11449         aopPut (result, rname, 0);
11450       /* we had to allocate for this iCode */
11451       freeAsmop (NULL, aop, ic, TRUE);
11452     }
11453   else
11454     {
11455       /* we did not allocate which means left
11456          already in a pointer register, then
11457          if size > 0 && this could be used again
11458          we have to point it back to where it
11459          belongs */
11460       if (AOP_SIZE (right) > 1 &&
11461           !OP_SYMBOL (result)->remat &&
11462           (OP_SYMBOL (result)->liveTo > ic->seq ||
11463            ic->depth) &&
11464           !pi)
11465         {
11466           int size = AOP_SIZE (right) - 1;
11467           while (size--)
11468             emitcode ("dec", "%s", rname);
11469         }
11470     }
11471
11472   /* done */
11473   if (pi) pi->generated = 1;
11474   freeAsmop (result, NULL, ic, TRUE);
11475   freeAsmop (right, NULL, ic, TRUE);
11476 }
11477
11478 /*-----------------------------------------------------------------*/
11479 /* genFarPointerSet - set value from far space                     */
11480 /*-----------------------------------------------------------------*/
11481 static void
11482 genFarPointerSet (operand * right,
11483                   operand * result, iCode * ic, iCode *pi)
11484 {
11485   int size, offset, dopi=1;
11486   sym_link *retype = getSpec (operandType (right));
11487   sym_link *letype = getSpec (operandType (result));
11488
11489   aopOp (result, ic, FALSE, FALSE);
11490
11491   /* if the operand is already in dptr
11492      then we do nothing else we move the value to dptr */
11493   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11494     {
11495       /* if this is remateriazable */
11496       if (AOP_TYPE (result) == AOP_IMMD)
11497         emitcode ("mov", "dptr,%s",
11498                   aopGet (result, 0, TRUE, FALSE, NULL));
11499       else
11500         {
11501           /* we need to get it byte by byte */
11502           _startLazyDPSEvaluation ();
11503           if (AOP_TYPE (result) != AOP_DPTR)
11504             {
11505               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11506               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11507               if (options.model == MODEL_FLAT24)
11508                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11509             }
11510           else
11511             {
11512               /* We need to generate a load to DPTR indirect through DPTR. */
11513               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11514
11515               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11516               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11517               if (options.model == MODEL_FLAT24)
11518                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11519               emitcode ("pop", "dph");
11520               emitcode ("pop", "dpl");
11521               dopi=0;
11522             }
11523           _endLazyDPSEvaluation ();
11524         }
11525     }
11526   /* so dptr now contains the address */
11527   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11528
11529   /* if bit then unpack */
11530   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11531   {
11532       if (AOP_INDPTRn(result)) {
11533           genSetDPTR(AOP(result)->aopu.dptr);
11534       }
11535       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11536       if (AOP_INDPTRn(result)) {
11537           genSetDPTR(0);
11538       }
11539   } else {
11540       size = AOP_SIZE (right);
11541       offset = 0;
11542       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11543           while (size--) {
11544               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11545
11546               genSetDPTR(AOP(result)->aopu.dptr);
11547               emitcode ("movx", "@dptr,a");
11548               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11549                   emitcode ("inc", "dptr");
11550               genSetDPTR (0);
11551           }
11552       } else {
11553           _startLazyDPSEvaluation ();
11554           while (size--) {
11555               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11556
11557               if (AOP_INDPTRn(result)) {
11558                   genSetDPTR(AOP(result)->aopu.dptr);
11559               } else {
11560                   genSetDPTR (0);
11561               }
11562               _flushLazyDPS ();
11563
11564               emitcode ("movx", "@dptr,a");
11565               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11566                   emitcode ("inc", "dptr");
11567           }
11568           _endLazyDPSEvaluation ();
11569       }
11570   }
11571
11572   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11573       if (!AOP_INDPTRn(result)) {
11574           _startLazyDPSEvaluation ();
11575
11576           aopPut (result,"dpl",0);
11577           aopPut (result,"dph",1);
11578           if (options.model == MODEL_FLAT24)
11579               aopPut (result,"dpx",2);
11580
11581           _endLazyDPSEvaluation ();
11582       }
11583       pi->generated=1;
11584   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11585              AOP_SIZE(right) > 1 &&
11586              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11587
11588       size = AOP_SIZE (right) - 1;
11589       if (AOP_INDPTRn(result)) {
11590           genSetDPTR(AOP(result)->aopu.dptr);
11591       }
11592       while (size--) emitcode ("lcall","__decdptr");
11593       if (AOP_INDPTRn(result)) {
11594           genSetDPTR(0);
11595       }
11596   }
11597   freeAsmop (result, NULL, ic, TRUE);
11598   freeAsmop (right, NULL, ic, TRUE);
11599 }
11600
11601 /*-----------------------------------------------------------------*/
11602 /* genGenPointerSet - set value from generic pointer space         */
11603 /*-----------------------------------------------------------------*/
11604 static void
11605 genGenPointerSet (operand * right,
11606                   operand * result, iCode * ic, iCode *pi)
11607 {
11608   int size, offset;
11609   bool pushedB;
11610   sym_link *retype = getSpec (operandType (right));
11611   sym_link *letype = getSpec (operandType (result));
11612
11613   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11614
11615   pushedB = pushB ();
11616   /* if the operand is already in dptr
11617      then we do nothing else we move the value to dptr */
11618   if (AOP_TYPE (result) != AOP_STR)
11619     {
11620       _startLazyDPSEvaluation ();
11621       /* if this is remateriazable */
11622       if (AOP_TYPE (result) == AOP_IMMD)
11623         {
11624           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11625           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11626           {
11627               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11628           }
11629           else
11630           {
11631               emitcode ("mov",
11632                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11633           }
11634         }
11635       else
11636         {                       /* we need to get it byte by byte */
11637           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11638           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11639           if (options.model == MODEL_FLAT24) {
11640             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11641             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11642           } else {
11643             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11644           }
11645         }
11646       _endLazyDPSEvaluation ();
11647     }
11648   /* so dptr + b now contains the address */
11649   aopOp (right, ic, FALSE, TRUE);
11650
11651   /* if bit then unpack */
11652   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11653     {
11654         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11655     }
11656   else
11657     {
11658         size = AOP_SIZE (right);
11659         offset = 0;
11660
11661         _startLazyDPSEvaluation ();
11662         while (size--)
11663         {
11664             if (size)
11665             {
11666                 // Set two bytes at a time, passed in _AP & A.
11667                 // dptr will be incremented ONCE by __gptrputWord.
11668                 //
11669                 // Note: any change here must be coordinated
11670                 // with the implementation of __gptrputWord
11671                 // in device/lib/_gptrput.c
11672                 emitcode("mov", "_ap, %s",
11673                          aopGet (right, offset++, FALSE, FALSE, NULL));
11674                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11675
11676                 genSetDPTR (0);
11677                 _flushLazyDPS ();
11678                 emitcode ("lcall", "__gptrputWord");
11679                 size--;
11680             }
11681             else
11682             {
11683                 // Only one byte to put.
11684                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11685
11686                 genSetDPTR (0);
11687                 _flushLazyDPS ();
11688                 emitcode ("lcall", "__gptrput");
11689             }
11690
11691             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11692             {
11693                 emitcode ("inc", "dptr");
11694             }
11695         }
11696         _endLazyDPSEvaluation ();
11697     }
11698
11699   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11700       _startLazyDPSEvaluation ();
11701
11702       aopPut (result, "dpl",0);
11703       aopPut (result, "dph",1);
11704       if (options.model == MODEL_FLAT24) {
11705           aopPut (result, "dpx",2);
11706           aopPut (result, "b",3);
11707       } else {
11708           aopPut (result, "b",2);
11709       }
11710       _endLazyDPSEvaluation ();
11711
11712       pi->generated=1;
11713   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11714              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11715
11716       size = AOP_SIZE (right) - 1;
11717       while (size--) emitcode ("lcall","__decdptr");
11718   }
11719   popB (pushedB);
11720
11721   freeAsmop (result, NULL, ic, TRUE);
11722   freeAsmop (right, NULL, ic, TRUE);
11723 }
11724
11725 /*-----------------------------------------------------------------*/
11726 /* genPointerSet - stores the value into a pointer location        */
11727 /*-----------------------------------------------------------------*/
11728 static void
11729 genPointerSet (iCode * ic, iCode *pi)
11730 {
11731   operand *right, *result;
11732   sym_link *type, *etype;
11733   int p_type;
11734
11735   D (emitcode (";", "genPointerSet"));
11736
11737   right = IC_RIGHT (ic);
11738   result = IC_RESULT (ic);
11739
11740   /* depending on the type of pointer we need to
11741      move it to the correct pointer register */
11742   type = operandType (result);
11743   etype = getSpec (type);
11744   /* if left is of type of pointer then it is simple */
11745   if (IS_PTR (type) && !IS_FUNC (type->next))
11746     {
11747       p_type = DCL_TYPE (type);
11748     }
11749   else
11750     {
11751       /* we have to go by the storage class */
11752       p_type = PTR_TYPE (SPEC_OCLS (etype));
11753     }
11754
11755   /* special case when cast remat */
11756   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11757       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11758           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11759           type = operandType (result);
11760           p_type = DCL_TYPE (type);
11761   }
11762
11763   /* now that we have the pointer type we assign
11764      the pointer values */
11765   switch (p_type)
11766     {
11767
11768     case POINTER:
11769     case IPOINTER:
11770       genNearPointerSet (right, result, ic, pi);
11771       break;
11772
11773     case PPOINTER:
11774       genPagedPointerSet (right, result, ic, pi);
11775       break;
11776
11777     case FPOINTER:
11778       genFarPointerSet (right, result, ic, pi);
11779       break;
11780
11781     case GPOINTER:
11782       genGenPointerSet (right, result, ic, pi);
11783       break;
11784
11785     default:
11786       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11787               "genPointerSet: illegal pointer type");
11788     }
11789 }
11790
11791 /*-----------------------------------------------------------------*/
11792 /* genIfx - generate code for Ifx statement                        */
11793 /*-----------------------------------------------------------------*/
11794 static void
11795 genIfx (iCode * ic, iCode * popIc)
11796 {
11797   operand *cond = IC_COND (ic);
11798   int isbit = 0;
11799   char *dup = NULL;
11800
11801   D (emitcode (";", "genIfx"));
11802
11803   aopOp (cond, ic, FALSE, FALSE);
11804
11805   /* get the value into acc */
11806   if (AOP_TYPE (cond) != AOP_CRY)
11807     {
11808       toBoolean (cond);
11809     }
11810   else
11811     {
11812       isbit = 1;
11813       if (AOP(cond)->aopu.aop_dir)
11814         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11815     }
11816
11817   /* the result is now in the accumulator or a directly addressable bit */
11818   freeAsmop (cond, NULL, ic, TRUE);
11819
11820   /* if there was something to be popped then do it */
11821   if (popIc)
11822     genIpop (popIc);
11823
11824   /* if the condition is a bit variable */
11825   if (isbit && dup)
11826     genIfxJump (ic, dup);
11827   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11828     genIfxJump (ic, SPIL_LOC (cond)->rname);
11829   else if (isbit && !IS_ITEMP (cond))
11830     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11831   else
11832     genIfxJump (ic, "a");
11833
11834   ic->generated = 1;
11835 }
11836
11837 /*-----------------------------------------------------------------*/
11838 /* genAddrOf - generates code for address of                       */
11839 /*-----------------------------------------------------------------*/
11840 static void
11841 genAddrOf (iCode * ic)
11842 {
11843   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11844   int size, offset;
11845
11846   D (emitcode (";", "genAddrOf"));
11847
11848   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11849
11850   /* if the operand is on the stack then we
11851      need to get the stack offset of this
11852      variable */
11853   if (sym->onStack)
11854   {
11855
11856       /* if 10 bit stack */
11857       if (options.stack10bit) {
11858           char buff[10];
11859           int  offset;
11860
11861           tsprintf(buff, sizeof(buff),
11862                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11863           /* if it has an offset then we need to compute it */
11864 /*        emitcode ("subb", "a,#!constbyte", */
11865 /*                  -((sym->stack < 0) ? */
11866 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11867 /*                    ((short) sym->stack)) & 0xff); */
11868 /*        emitcode ("mov","b,a"); */
11869 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11870 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11871 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11872           if (sym->stack) {
11873               emitcode ("mov", "a,_bpx");
11874               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11875                                              ((char) (sym->stack - _G.nRegsSaved)) :
11876                                              ((char) sym->stack )) & 0xff);
11877               emitcode ("mov", "b,a");
11878               emitcode ("mov", "a,_bpx+1");
11879
11880               offset = (((sym->stack < 0) ?
11881                          ((short) (sym->stack - _G.nRegsSaved)) :
11882                          ((short) sym->stack )) >> 8) & 0xff;
11883
11884               emitcode ("addc","a,#!constbyte", offset);
11885
11886               aopPut (IC_RESULT (ic), "b", 0);
11887               aopPut (IC_RESULT (ic), "a", 1);
11888               aopPut (IC_RESULT (ic), buff, 2);
11889           } else {
11890               /* we can just move _bp */
11891               aopPut (IC_RESULT (ic), "_bpx", 0);
11892               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11893               aopPut (IC_RESULT (ic), buff, 2);
11894           }
11895       } else {
11896           /* if it has an offset then we need to compute it */
11897           if (sym->stack)
11898             {
11899               emitcode ("mov", "a,_bp");
11900               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11901               aopPut (IC_RESULT (ic), "a", 0);
11902             }
11903           else
11904             {
11905               /* we can just move _bp */
11906               aopPut (IC_RESULT (ic), "_bp", 0);
11907             }
11908           /* fill the result with zero */
11909           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11910
11911
11912           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11913               fprintf (stderr,
11914                        "*** warning: pointer to stack var truncated.\n");
11915           }
11916
11917           offset = 1;
11918           while (size--)
11919             {
11920               aopPut (IC_RESULT (ic), zero, offset++);
11921             }
11922       }
11923       goto release;
11924   }
11925
11926   /* object not on stack then we need the name */
11927   size = AOP_SIZE (IC_RESULT (ic));
11928   offset = 0;
11929
11930   while (size--)
11931     {
11932       char s[SDCC_NAME_MAX];
11933       if (offset) {
11934           switch (offset) {
11935           case 1:
11936               tsprintf(s, sizeof(s), "#!his",sym->rname);
11937               break;
11938           case 2:
11939               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11940               break;
11941           case 3:
11942               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11943               break;
11944           default: /* should not need this (just in case) */
11945               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11946                        sym->rname,
11947                        offset * 8);
11948           }
11949       }
11950       else
11951       {
11952           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11953       }
11954
11955       aopPut (IC_RESULT (ic), s, offset++);
11956     }
11957
11958 release:
11959   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11960
11961 }
11962
11963 #if 0 // obsolete, and buggy for != xdata
11964 /*-----------------------------------------------------------------*/
11965 /* genArrayInit - generates code for address of                       */
11966 /*-----------------------------------------------------------------*/
11967 static void
11968 genArrayInit (iCode * ic)
11969 {
11970     literalList *iLoop;
11971     int         ix, count;
11972     int         elementSize = 0, eIndex;
11973     unsigned    val, lastVal;
11974     sym_link    *type;
11975     operand     *left=IC_LEFT(ic);
11976
11977     D (emitcode (";", "genArrayInit"));
11978
11979     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11980
11981     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11982     {
11983         // Load immediate value into DPTR.
11984         emitcode("mov", "dptr, %s",
11985              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11986     }
11987     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11988     {
11989 #if 0
11990       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11991               "Unexpected operand to genArrayInit.\n");
11992       exit(1);
11993 #else
11994       // a regression because of SDCCcse.c:1.52
11995       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11996       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11997       if (options.model == MODEL_FLAT24)
11998         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11999 #endif
12000     }
12001
12002     type = operandType(IC_LEFT(ic));
12003
12004     if (type && type->next)
12005     {
12006         elementSize = getSize(type->next);
12007     }
12008     else
12009     {
12010         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12011                                 "can't determine element size in genArrayInit.\n");
12012         exit(1);
12013     }
12014
12015     iLoop = IC_ARRAYILIST(ic);
12016     lastVal = 0xffff;
12017
12018     while (iLoop)
12019     {
12020         bool firstpass = TRUE;
12021
12022         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12023                  iLoop->count, (int)iLoop->literalValue, elementSize);
12024
12025         ix = iLoop->count;
12026
12027         while (ix)
12028         {
12029             symbol *tlbl = NULL;
12030
12031             count = ix > 256 ? 256 : ix;
12032
12033             if (count > 1)
12034             {
12035                 tlbl = newiTempLabel (NULL);
12036                 if (firstpass || (count & 0xff))
12037                 {
12038                     emitcode("mov", "b, #!constbyte", count & 0xff);
12039                 }
12040
12041                 emitLabel (tlbl);
12042             }
12043
12044             firstpass = FALSE;
12045
12046             for (eIndex = 0; eIndex < elementSize; eIndex++)
12047             {
12048                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12049                 if (val != lastVal)
12050                 {
12051                     emitcode("mov", "a, #!constbyte", val);
12052                     lastVal = val;
12053                 }
12054
12055                 emitcode("movx", "@dptr, a");
12056                 emitcode("inc", "dptr");
12057             }
12058
12059             if (count > 1)
12060             {
12061                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12062             }
12063
12064             ix -= count;
12065         }
12066
12067         iLoop = iLoop->next;
12068     }
12069
12070     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12071 }
12072 #endif
12073
12074 /*-----------------------------------------------------------------*/
12075 /* genFarFarAssign - assignment when both are in far space         */
12076 /*-----------------------------------------------------------------*/
12077 static void
12078 genFarFarAssign (operand * result, operand * right, iCode * ic)
12079 {
12080   int size = AOP_SIZE (right);
12081   int offset = 0;
12082   symbol *rSym = NULL;
12083
12084   if (size == 1)
12085   {
12086       /* quick & easy case. */
12087       D (emitcode(";","genFarFarAssign (1 byte case)"));
12088       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12089       freeAsmop (right, NULL, ic, FALSE);
12090       /* now assign DPTR to result */
12091       _G.accInUse++;
12092       aopOp(result, ic, FALSE, FALSE);
12093       _G.accInUse--;
12094       aopPut (result, "a", 0);
12095       freeAsmop(result, NULL, ic, FALSE);
12096       return;
12097   }
12098
12099   /* See if we've got an underlying symbol to abuse. */
12100   if (IS_SYMOP(result) && OP_SYMBOL(result))
12101   {
12102       if (IS_TRUE_SYMOP(result))
12103       {
12104           rSym = OP_SYMBOL(result);
12105       }
12106       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12107       {
12108           rSym = OP_SYMBOL(result)->usl.spillLoc;
12109       }
12110   }
12111
12112   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12113   {
12114       /* We can use the '390 auto-toggle feature to good effect here. */
12115
12116       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12117       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12118       emitcode ("mov", "dptr,#%s", rSym->rname);
12119       /* DP2 = result, DP1 = right, DP1 is current. */
12120       while (size)
12121       {
12122           emitcode("movx", "a,@dptr");
12123           emitcode("movx", "@dptr,a");
12124           if (--size)
12125           {
12126                emitcode("inc", "dptr");
12127                emitcode("inc", "dptr");
12128           }
12129       }
12130       emitcode("mov", "dps,#0");
12131       freeAsmop (right, NULL, ic, FALSE);
12132 #if 0
12133 some alternative code for processors without auto-toggle
12134 no time to test now, so later well put in...kpb
12135         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12136         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12137         emitcode ("mov", "dptr,#%s", rSym->rname);
12138         /* DP2 = result, DP1 = right, DP1 is current. */
12139         while (size)
12140         {
12141           --size;
12142           emitcode("movx", "a,@dptr");
12143           if (size)
12144             emitcode("inc", "dptr");
12145           emitcode("inc", "dps");
12146           emitcode("movx", "@dptr,a");
12147           if (size)
12148             emitcode("inc", "dptr");
12149           emitcode("inc", "dps");
12150         }
12151         emitcode("mov", "dps,#0");
12152         freeAsmop (right, NULL, ic, FALSE);
12153 #endif
12154   }
12155   else
12156   {
12157       D (emitcode (";", "genFarFarAssign"));
12158       aopOp (result, ic, TRUE, TRUE);
12159
12160       _startLazyDPSEvaluation ();
12161
12162       while (size--)
12163         {
12164           aopPut (result,
12165                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12166           offset++;
12167         }
12168       _endLazyDPSEvaluation ();
12169       freeAsmop (result, NULL, ic, FALSE);
12170       freeAsmop (right, NULL, ic, FALSE);
12171   }
12172 }
12173
12174 /*-----------------------------------------------------------------*/
12175 /* genAssign - generate code for assignment                        */
12176 /*-----------------------------------------------------------------*/
12177 static void
12178 genAssign (iCode * ic)
12179 {
12180   operand *result, *right;
12181   int size, offset;
12182   unsigned long lit = 0L;
12183
12184   D (emitcode (";", "genAssign"));
12185
12186   result = IC_RESULT (ic);
12187   right = IC_RIGHT (ic);
12188
12189   /* if they are the same */
12190   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12191     return;
12192
12193   aopOp (right, ic, FALSE, FALSE);
12194
12195   emitcode (";", "genAssign: resultIsFar = %s",
12196             isOperandInFarSpace (result) ?
12197             "TRUE" : "FALSE");
12198
12199   /* special case both in far space */
12200   if ((AOP_TYPE (right) == AOP_DPTR ||
12201        AOP_TYPE (right) == AOP_DPTR2) &&
12202   /* IS_TRUE_SYMOP(result)       && */
12203       isOperandInFarSpace (result))
12204     {
12205       genFarFarAssign (result, right, ic);
12206       return;
12207     }
12208
12209   aopOp (result, ic, TRUE, FALSE);
12210
12211   /* if they are the same registers */
12212   if (sameRegs (AOP (right), AOP (result)))
12213     goto release;
12214
12215   /* if the result is a bit */
12216   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12217     {
12218       /* if the right size is a literal then
12219          we know what the value is */
12220       if (AOP_TYPE (right) == AOP_LIT)
12221         {
12222           if (((int) operandLitValue (right)))
12223             aopPut (result, one, 0);
12224           else
12225             aopPut (result, zero, 0);
12226           goto release;
12227         }
12228
12229       /* the right is also a bit variable */
12230       if (AOP_TYPE (right) == AOP_CRY)
12231         {
12232           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12233           aopPut (result, "c", 0);
12234           goto release;
12235         }
12236
12237       /* we need to or */
12238       toBoolean (right);
12239       aopPut (result, "a", 0);
12240       goto release;
12241     }
12242
12243   /* bit variables done */
12244   /* general case */
12245   size = AOP_SIZE (result);
12246   offset = 0;
12247   if (AOP_TYPE (right) == AOP_LIT)
12248     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12249
12250   if ((size > 1) &&
12251       (AOP_TYPE (result) != AOP_REG) &&
12252       (AOP_TYPE (right) == AOP_LIT) &&
12253       !IS_FLOAT (operandType (right)))
12254     {
12255       _startLazyDPSEvaluation ();
12256       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12257         {
12258           aopPut (result,
12259                   aopGet (right, offset, FALSE, FALSE, NULL),
12260                   offset);
12261           offset++;
12262           size--;
12263         }
12264       /* And now fill the rest with zeros. */
12265       if (size)
12266         {
12267           emitcode ("clr", "a");
12268         }
12269       while (size--)
12270         {
12271           aopPut (result, "a", offset++);
12272         }
12273       _endLazyDPSEvaluation ();
12274     }
12275   else
12276     {
12277       _startLazyDPSEvaluation ();
12278       while (size--)
12279         {
12280           aopPut (result,
12281                   aopGet (right, offset, FALSE, FALSE, NULL),
12282                   offset);
12283           offset++;
12284         }
12285       _endLazyDPSEvaluation ();
12286     }
12287
12288 release:
12289   freeAsmop (result, NULL, ic, TRUE);
12290   freeAsmop (right, NULL, ic, TRUE);
12291 }
12292
12293 /*-----------------------------------------------------------------*/
12294 /* genJumpTab - generates code for jump table                      */
12295 /*-----------------------------------------------------------------*/
12296 static void
12297 genJumpTab (iCode * ic)
12298 {
12299   symbol *jtab;
12300   char *l;
12301
12302   D (emitcode (";", "genJumpTab"));
12303
12304   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12305   /* get the condition into accumulator */
12306   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12307   MOVA (l);
12308   /* multiply by four! */
12309   emitcode ("add", "a,acc");
12310   emitcode ("add", "a,acc");
12311   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12312
12313   jtab = newiTempLabel (NULL);
12314   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12315   emitcode ("jmp", "@a+dptr");
12316   emitLabel (jtab);
12317   /* now generate the jump labels */
12318   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12319        jtab = setNextItem (IC_JTLABELS (ic)))
12320     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12321
12322 }
12323
12324 /*-----------------------------------------------------------------*/
12325 /* genCast - gen code for casting                                  */
12326 /*-----------------------------------------------------------------*/
12327 static void
12328 genCast (iCode * ic)
12329 {
12330   operand *result = IC_RESULT (ic);
12331   sym_link *ctype = operandType (IC_LEFT (ic));
12332   sym_link *rtype = operandType (IC_RIGHT (ic));
12333   operand *right = IC_RIGHT (ic);
12334   int size, offset;
12335
12336   D (emitcode (";", "genCast"));
12337
12338   /* if they are equivalent then do nothing */
12339   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12340     return;
12341
12342   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12343   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12344
12345   /* if the result is a bit (and not a bitfield) */
12346   if (IS_BIT (OP_SYMBOL (result)->type))
12347     {
12348       /* if the right size is a literal then
12349          we know what the value is */
12350       if (AOP_TYPE (right) == AOP_LIT)
12351         {
12352           if (((int) operandLitValue (right)))
12353             aopPut (result, one, 0);
12354           else
12355             aopPut (result, zero, 0);
12356
12357           goto release;
12358         }
12359
12360       /* the right is also a bit variable */
12361       if (AOP_TYPE (right) == AOP_CRY)
12362         {
12363           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12364           aopPut (result, "c", 0);
12365           goto release;
12366         }
12367
12368       /* we need to or */
12369       toBoolean (right);
12370       aopPut (result, "a", 0);
12371       goto release;
12372     }
12373
12374   /* if they are the same size : or less */
12375   if (AOP_SIZE (result) <= AOP_SIZE (right))
12376     {
12377
12378       /* if they are in the same place */
12379       if (sameRegs (AOP (right), AOP (result)))
12380         goto release;
12381
12382       /* if they in different places then copy */
12383       size = AOP_SIZE (result);
12384       offset = 0;
12385       _startLazyDPSEvaluation ();
12386       while (size--)
12387         {
12388           aopPut (result,
12389                   aopGet (right, offset, FALSE, FALSE, NULL),
12390                   offset);
12391           offset++;
12392         }
12393       _endLazyDPSEvaluation ();
12394       goto release;
12395     }
12396
12397   /* if the result is of type pointer */
12398   if (IS_PTR (ctype))
12399     {
12400
12401       int p_type;
12402       sym_link *type = operandType (right);
12403
12404       /* pointer to generic pointer */
12405       if (IS_GENPTR (ctype))
12406         {
12407           if (IS_PTR (type))
12408             {
12409               p_type = DCL_TYPE (type);
12410             }
12411           else
12412             {
12413 #if OLD_CAST_BEHAVIOR
12414               /* KV: we are converting a non-pointer type to
12415                * a generic pointer. This (ifdef'd out) code
12416                * says that the resulting generic pointer
12417                * should have the same class as the storage
12418                * location of the non-pointer variable.
12419                *
12420                * For example, converting an int (which happens
12421                * to be stored in DATA space) to a pointer results
12422                * in a DATA generic pointer; if the original int
12423                * in XDATA space, so will be the resulting pointer.
12424                *
12425                * I don't like that behavior, and thus this change:
12426                * all such conversions will be forced to XDATA and
12427                * throw a warning. If you want some non-XDATA
12428                * type, or you want to suppress the warning, you
12429                * must go through an intermediate cast, like so:
12430                *
12431                * char _generic *gp = (char _xdata *)(intVar);
12432                */
12433               sym_link *etype = getSpec (type);
12434
12435               /* we have to go by the storage class */
12436               if (SPEC_OCLS (etype) != generic)
12437                 {
12438                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12439                 }
12440               else
12441 #endif
12442                 {
12443                   /* Converting unknown class (i.e. register variable)
12444                    * to generic pointer. This is not good, but
12445                    * we'll make a guess (and throw a warning).
12446                    */
12447                   p_type = FPOINTER;
12448                   werror (W_INT_TO_GEN_PTR_CAST);
12449                 }
12450             }
12451
12452           /* the first two bytes are known */
12453           size = GPTRSIZE - 1;
12454           offset = 0;
12455           _startLazyDPSEvaluation ();
12456           while (size--)
12457             {
12458               aopPut (result,
12459                       aopGet (right, offset, FALSE, FALSE, NULL),
12460                       offset);
12461               offset++;
12462             }
12463           _endLazyDPSEvaluation ();
12464
12465           /* the last byte depending on type */
12466             {
12467                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12468                 char gpValStr[10];
12469
12470                 if (gpVal == -1)
12471                 {
12472                     // pointerTypeToGPByte will have bitched.
12473                     exit(1);
12474                 }
12475
12476                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12477                 aopPut (result, gpValStr, GPTRSIZE - 1);
12478             }
12479           goto release;
12480         }
12481
12482       /* just copy the pointers */
12483       size = AOP_SIZE (result);
12484       offset = 0;
12485       _startLazyDPSEvaluation ();
12486       while (size--)
12487         {
12488           aopPut (result,
12489                   aopGet (right, offset, FALSE, FALSE, NULL),
12490                   offset);
12491           offset++;
12492         }
12493       _endLazyDPSEvaluation ();
12494       goto release;
12495     }
12496
12497   /* so we now know that the size of destination is greater
12498      than the size of the source */
12499   /* we move to result for the size of source */
12500   size = AOP_SIZE (right);
12501   offset = 0;
12502   _startLazyDPSEvaluation ();
12503   while (size--)
12504     {
12505       aopPut (result,
12506               aopGet (right, offset, FALSE, FALSE, NULL),
12507               offset);
12508       offset++;
12509     }
12510   _endLazyDPSEvaluation ();
12511
12512   /* now depending on the sign of the source && destination */
12513   size = AOP_SIZE (result) - AOP_SIZE (right);
12514   /* if unsigned or not an integral type */
12515   /* also, if the source is a bit, we don't need to sign extend, because
12516    * it can't possibly have set the sign bit.
12517    */
12518   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12519     {
12520       while (size--)
12521         {
12522           aopPut (result, zero, offset++);
12523         }
12524     }
12525   else
12526     {
12527       /* we need to extend the sign :{ */
12528       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12529                         FALSE, FALSE, NULL));
12530       emitcode ("rlc", "a");
12531       emitcode ("subb", "a,acc");
12532       while (size--)
12533         aopPut (result, "a", offset++);
12534     }
12535
12536   /* we are done hurray !!!! */
12537
12538 release:
12539   freeAsmop (right, NULL, ic, TRUE);
12540   freeAsmop (result, NULL, ic, TRUE);
12541
12542 }
12543
12544 /*-----------------------------------------------------------------*/
12545 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12546 /*-----------------------------------------------------------------*/
12547 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12548 {
12549     operand *from , *to , *count;
12550     symbol *lbl;
12551     bitVect *rsave;
12552     int i;
12553
12554     /* we know it has to be 3 parameters */
12555     assert (nparms == 3);
12556
12557     rsave = newBitVect(16);
12558     /* save DPTR if it needs to be saved */
12559     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12560             if (bitVectBitValue(ic->rMask,i))
12561                     rsave = bitVectSetBit(rsave,i);
12562     }
12563     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12564                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12565     savermask(rsave);
12566
12567     to = parms[0];
12568     from = parms[1];
12569     count = parms[2];
12570
12571     aopOp (from, ic->next, FALSE, FALSE);
12572
12573     /* get from into DPTR1 */
12574     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12575     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12576     if (options.model == MODEL_FLAT24) {
12577         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12578     }
12579
12580     freeAsmop (from, NULL, ic, FALSE);
12581     aopOp (to, ic, FALSE, FALSE);
12582     /* get "to" into DPTR */
12583     /* if the operand is already in dptr
12584        then we do nothing else we move the value to dptr */
12585     if (AOP_TYPE (to) != AOP_STR) {
12586         /* if already in DPTR then we need to push */
12587         if (AOP_TYPE(to) == AOP_DPTR) {
12588             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12589             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12590             if (options.model == MODEL_FLAT24)
12591                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12592             emitcode ("pop", "dph");
12593             emitcode ("pop", "dpl");
12594         } else {
12595             _startLazyDPSEvaluation ();
12596             /* if this is remateriazable */
12597             if (AOP_TYPE (to) == AOP_IMMD) {
12598                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12599             } else {                    /* we need to get it byte by byte */
12600                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12601                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12602                 if (options.model == MODEL_FLAT24) {
12603                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12604                 }
12605             }
12606             _endLazyDPSEvaluation ();
12607         }
12608     }
12609     freeAsmop (to, NULL, ic, FALSE);
12610     _G.dptrInUse = _G.dptr1InUse = 1;
12611     aopOp (count, ic->next->next, FALSE,FALSE);
12612     lbl =newiTempLabel(NULL);
12613
12614     /* now for the actual copy */
12615     if (AOP_TYPE(count) == AOP_LIT &&
12616         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12617         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12618         if (fromc) {
12619             emitcode ("lcall","__bi_memcpyc2x_s");
12620         } else {
12621             emitcode ("lcall","__bi_memcpyx2x_s");
12622         }
12623         freeAsmop (count, NULL, ic, FALSE);
12624     } else {
12625         symbol *lbl1 = newiTempLabel(NULL);
12626
12627         emitcode (";"," Auto increment but no djnz");
12628         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12629         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12630         freeAsmop (count, NULL, ic, FALSE);
12631         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12632         emitLabel (lbl);
12633         if (fromc) {
12634             emitcode ("clr","a");
12635             emitcode ("movc", "a,@a+dptr");
12636         } else
12637             emitcode ("movx", "a,@dptr");
12638         emitcode ("movx", "@dptr,a");
12639         emitcode ("inc", "dptr");
12640         emitcode ("inc", "dptr");
12641         emitcode ("mov","a,b");
12642         emitcode ("orl","a,_ap");
12643         emitcode ("jz","!tlabel",lbl1->key+100);
12644         emitcode ("mov","a,_ap");
12645         emitcode ("add","a,#!constbyte",0xFF);
12646         emitcode ("mov","_ap,a");
12647         emitcode ("mov","a,b");
12648         emitcode ("addc","a,#!constbyte",0xFF);
12649         emitcode ("mov","b,a");
12650         emitcode ("sjmp","!tlabel",lbl->key+100);
12651         emitLabel (lbl1);
12652     }
12653     emitcode ("mov", "dps,#0");
12654     _G.dptrInUse = _G.dptr1InUse = 0;
12655     unsavermask(rsave);
12656
12657 }
12658
12659 /*-----------------------------------------------------------------*/
12660 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12661 /*-----------------------------------------------------------------*/
12662 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12663 {
12664     operand *from , *to , *count;
12665     symbol *lbl,*lbl2;
12666     bitVect *rsave;
12667     int i;
12668
12669     /* we know it has to be 3 parameters */
12670     assert (nparms == 3);
12671
12672     rsave = newBitVect(16);
12673     /* save DPTR if it needs to be saved */
12674     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12675             if (bitVectBitValue(ic->rMask,i))
12676                     rsave = bitVectSetBit(rsave,i);
12677     }
12678     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12679                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12680     savermask(rsave);
12681
12682     to = parms[0];
12683     from = parms[1];
12684     count = parms[2];
12685
12686     aopOp (from, ic->next, FALSE, FALSE);
12687
12688     /* get from into DPTR1 */
12689     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12690     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12691     if (options.model == MODEL_FLAT24) {
12692         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12693     }
12694
12695     freeAsmop (from, NULL, ic, FALSE);
12696     aopOp (to, ic, FALSE, FALSE);
12697     /* get "to" into DPTR */
12698     /* if the operand is already in dptr
12699        then we do nothing else we move the value to dptr */
12700     if (AOP_TYPE (to) != AOP_STR) {
12701         /* if already in DPTR then we need to push */
12702         if (AOP_TYPE(to) == AOP_DPTR) {
12703             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12704             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12705             if (options.model == MODEL_FLAT24)
12706                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12707             emitcode ("pop", "dph");
12708             emitcode ("pop", "dpl");
12709         } else {
12710             _startLazyDPSEvaluation ();
12711             /* if this is remateriazable */
12712             if (AOP_TYPE (to) == AOP_IMMD) {
12713                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12714             } else {                    /* we need to get it byte by byte */
12715                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12716                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12717                 if (options.model == MODEL_FLAT24) {
12718                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12719                 }
12720             }
12721             _endLazyDPSEvaluation ();
12722         }
12723     }
12724     freeAsmop (to, NULL, ic, FALSE);
12725     _G.dptrInUse = _G.dptr1InUse = 1;
12726     aopOp (count, ic->next->next, FALSE,FALSE);
12727     lbl =newiTempLabel(NULL);
12728     lbl2 =newiTempLabel(NULL);
12729
12730     /* now for the actual compare */
12731     if (AOP_TYPE(count) == AOP_LIT &&
12732         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12733         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12734         if (fromc)
12735             emitcode("lcall","__bi_memcmpc2x_s");
12736         else
12737             emitcode("lcall","__bi_memcmpx2x_s");
12738         freeAsmop (count, NULL, ic, FALSE);
12739         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12740         aopPut(IC_RESULT(ic),"a",0);
12741         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12742     } else {
12743         symbol *lbl1 = newiTempLabel(NULL);
12744
12745         emitcode("push","ar0");
12746         emitcode (";"," Auto increment but no djnz");
12747         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12748         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12749         freeAsmop (count, NULL, ic, FALSE);
12750         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12751         emitLabel (lbl);
12752         if (fromc) {
12753             emitcode ("clr","a");
12754             emitcode ("movc", "a,@a+dptr");
12755         } else
12756             emitcode ("movx", "a,@dptr");
12757         emitcode ("mov","r0,a");
12758         emitcode ("movx", "a,@dptr");
12759         emitcode ("clr","c");
12760         emitcode ("subb","a,r0");
12761         emitcode ("jnz","!tlabel",lbl2->key+100);
12762         emitcode ("inc", "dptr");
12763         emitcode ("inc", "dptr");
12764         emitcode ("mov","a,b");
12765         emitcode ("orl","a,_ap");
12766         emitcode ("jz","!tlabel",lbl1->key+100);
12767         emitcode ("mov","a,_ap");
12768         emitcode ("add","a,#!constbyte",0xFF);
12769         emitcode ("mov","_ap,a");
12770         emitcode ("mov","a,b");
12771         emitcode ("addc","a,#!constbyte",0xFF);
12772         emitcode ("mov","b,a");
12773         emitcode ("sjmp","!tlabel",lbl->key+100);
12774         emitLabel (lbl1);
12775         emitcode ("clr","a");
12776         emitLabel (lbl2);
12777         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12778         aopPut(IC_RESULT(ic),"a",0);
12779         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12780         emitcode("pop","ar0");
12781         emitcode ("mov", "dps,#0");
12782     }
12783     _G.dptrInUse = _G.dptr1InUse = 0;
12784     unsavermask(rsave);
12785
12786 }
12787
12788 /*-----------------------------------------------------------------*/
12789 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12790 /* port, first parameter output area second parameter pointer to   */
12791 /* port third parameter count                                      */
12792 /*-----------------------------------------------------------------*/
12793 static void genInp( iCode *ic, int nparms, operand **parms)
12794 {
12795     operand *from , *to , *count;
12796     symbol *lbl;
12797     bitVect *rsave;
12798     int i;
12799
12800     /* we know it has to be 3 parameters */
12801     assert (nparms == 3);
12802
12803     rsave = newBitVect(16);
12804     /* save DPTR if it needs to be saved */
12805     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12806             if (bitVectBitValue(ic->rMask,i))
12807                     rsave = bitVectSetBit(rsave,i);
12808     }
12809     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12810                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12811     savermask(rsave);
12812
12813     to = parms[0];
12814     from = parms[1];
12815     count = parms[2];
12816
12817     aopOp (from, ic->next, FALSE, FALSE);
12818
12819     /* get from into DPTR1 */
12820     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12821     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12822     if (options.model == MODEL_FLAT24) {
12823         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12824     }
12825
12826     freeAsmop (from, NULL, ic, FALSE);
12827     aopOp (to, ic, FALSE, FALSE);
12828     /* get "to" into DPTR */
12829     /* if the operand is already in dptr
12830        then we do nothing else we move the value to dptr */
12831     if (AOP_TYPE (to) != AOP_STR) {
12832         /* if already in DPTR then we need to push */
12833         if (AOP_TYPE(to) == AOP_DPTR) {
12834             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12835             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12836             if (options.model == MODEL_FLAT24)
12837                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12838             emitcode ("pop", "dph");
12839             emitcode ("pop", "dpl");
12840         } else {
12841             _startLazyDPSEvaluation ();
12842             /* if this is remateriazable */
12843             if (AOP_TYPE (to) == AOP_IMMD) {
12844                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12845             } else {                    /* we need to get it byte by byte */
12846                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12847                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12848                 if (options.model == MODEL_FLAT24) {
12849                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12850                 }
12851             }
12852             _endLazyDPSEvaluation ();
12853         }
12854     }
12855     freeAsmop (to, NULL, ic, FALSE);
12856
12857     _G.dptrInUse = _G.dptr1InUse = 1;
12858     aopOp (count, ic->next->next, FALSE,FALSE);
12859     lbl =newiTempLabel(NULL);
12860
12861     /* now for the actual copy */
12862     if (AOP_TYPE(count) == AOP_LIT &&
12863         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12864         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12865         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12866         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12867         freeAsmop (count, NULL, ic, FALSE);
12868         emitLabel (lbl);
12869         emitcode ("movx", "a,@dptr");   /* read data from port */
12870         emitcode ("dec","dps");         /* switch to DPTR */
12871         emitcode ("movx", "@dptr,a");   /* save into location */
12872         emitcode ("inc", "dptr");       /* point to next area */
12873         emitcode ("inc","dps");         /* switch to DPTR2 */
12874         emitcode ("djnz","b,!tlabel",lbl->key+100);
12875     } else {
12876         symbol *lbl1 = newiTempLabel(NULL);
12877
12878         emitcode (";"," Auto increment but no djnz");
12879         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12880         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12881         freeAsmop (count, NULL, ic, FALSE);
12882         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12883         emitLabel (lbl);
12884         emitcode ("movx", "a,@dptr");
12885         emitcode ("dec","dps");         /* switch to DPTR */
12886         emitcode ("movx", "@dptr,a");
12887         emitcode ("inc", "dptr");
12888         emitcode ("inc","dps");         /* switch to DPTR2 */
12889 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12890 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12891         emitcode ("mov","a,b");
12892         emitcode ("orl","a,_ap");
12893         emitcode ("jz","!tlabel",lbl1->key+100);
12894         emitcode ("mov","a,_ap");
12895         emitcode ("add","a,#!constbyte",0xFF);
12896         emitcode ("mov","_ap,a");
12897         emitcode ("mov","a,b");
12898         emitcode ("addc","a,#!constbyte",0xFF);
12899         emitcode ("mov","b,a");
12900         emitcode ("sjmp","!tlabel",lbl->key+100);
12901         emitLabel (lbl1);
12902     }
12903     emitcode ("mov", "dps,#0");
12904     _G.dptrInUse = _G.dptr1InUse = 0;
12905     unsavermask(rsave);
12906
12907 }
12908
12909 /*-----------------------------------------------------------------*/
12910 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12911 /* port, first parameter output area second parameter pointer to   */
12912 /* port third parameter count                                      */
12913 /*-----------------------------------------------------------------*/
12914 static void genOutp( iCode *ic, int nparms, operand **parms)
12915 {
12916     operand *from , *to , *count;
12917     symbol *lbl;
12918     bitVect *rsave;
12919     int i;
12920
12921     /* we know it has to be 3 parameters */
12922     assert (nparms == 3);
12923
12924     rsave = newBitVect(16);
12925     /* save DPTR if it needs to be saved */
12926     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12927             if (bitVectBitValue(ic->rMask,i))
12928                     rsave = bitVectSetBit(rsave,i);
12929     }
12930     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12931                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12932     savermask(rsave);
12933
12934     to = parms[0];
12935     from = parms[1];
12936     count = parms[2];
12937
12938     aopOp (from, ic->next, FALSE, FALSE);
12939
12940     /* get from into DPTR1 */
12941     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12942     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12943     if (options.model == MODEL_FLAT24) {
12944         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12945     }
12946
12947     freeAsmop (from, NULL, ic, FALSE);
12948     aopOp (to, ic, FALSE, FALSE);
12949     /* get "to" into DPTR */
12950     /* if the operand is already in dptr
12951        then we do nothing else we move the value to dptr */
12952     if (AOP_TYPE (to) != AOP_STR) {
12953         /* if already in DPTR then we need to push */
12954         if (AOP_TYPE(to) == AOP_DPTR) {
12955             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12956             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12957             if (options.model == MODEL_FLAT24)
12958                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12959             emitcode ("pop", "dph");
12960             emitcode ("pop", "dpl");
12961         } else {
12962             _startLazyDPSEvaluation ();
12963             /* if this is remateriazable */
12964             if (AOP_TYPE (to) == AOP_IMMD) {
12965                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12966             } else {                    /* we need to get it byte by byte */
12967                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12968                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12969                 if (options.model == MODEL_FLAT24) {
12970                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12971                 }
12972             }
12973             _endLazyDPSEvaluation ();
12974         }
12975     }
12976     freeAsmop (to, NULL, ic, FALSE);
12977
12978     _G.dptrInUse = _G.dptr1InUse = 1;
12979     aopOp (count, ic->next->next, FALSE,FALSE);
12980     lbl =newiTempLabel(NULL);
12981
12982     /* now for the actual copy */
12983     if (AOP_TYPE(count) == AOP_LIT &&
12984         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12985         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12986         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12987         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12988         emitLabel (lbl);
12989         emitcode ("movx", "a,@dptr");   /* read data from port */
12990         emitcode ("inc","dps");         /* switch to DPTR2 */
12991         emitcode ("movx", "@dptr,a");   /* save into location */
12992         emitcode ("inc", "dptr");       /* point to next area */
12993         emitcode ("dec","dps");         /* switch to DPTR */
12994         emitcode ("djnz","b,!tlabel",lbl->key+100);
12995         freeAsmop (count, NULL, ic, FALSE);
12996     } else {
12997         symbol *lbl1 = newiTempLabel(NULL);
12998
12999         emitcode (";"," Auto increment but no djnz");
13000         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13001         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13002         freeAsmop (count, NULL, ic, FALSE);
13003         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13004         emitLabel (lbl);
13005         emitcode ("movx", "a,@dptr");
13006         emitcode ("inc", "dptr");
13007         emitcode ("inc","dps");         /* switch to DPTR2 */
13008         emitcode ("movx", "@dptr,a");
13009         emitcode ("dec","dps");         /* switch to DPTR */
13010         emitcode ("mov","a,b");
13011         emitcode ("orl","a,_ap");
13012         emitcode ("jz","!tlabel",lbl1->key+100);
13013         emitcode ("mov","a,_ap");
13014         emitcode ("add","a,#!constbyte",0xFF);
13015         emitcode ("mov","_ap,a");
13016         emitcode ("mov","a,b");
13017         emitcode ("addc","a,#!constbyte",0xFF);
13018         emitcode ("mov","b,a");
13019         emitcode ("sjmp","!tlabel",lbl->key+100);
13020         emitLabel (lbl1);
13021     }
13022     emitcode ("mov", "dps,#0");
13023     _G.dptrInUse = _G.dptr1InUse = 0;
13024     unsavermask(rsave);
13025
13026 }
13027
13028 /*-----------------------------------------------------------------*/
13029 /* genSwapW - swap lower & high order bytes                        */
13030 /*-----------------------------------------------------------------*/
13031 static void genSwapW(iCode *ic, int nparms, operand **parms)
13032 {
13033     operand *dest;
13034     operand *src;
13035     assert (nparms==1);
13036
13037     src = parms[0];
13038     dest=IC_RESULT(ic);
13039
13040     assert(getSize(operandType(src))==2);
13041
13042     aopOp (src, ic, FALSE, FALSE);
13043     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13044     _G.accInUse++;
13045     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13046     _G.accInUse--;
13047     freeAsmop (src, NULL, ic, FALSE);
13048
13049     aopOp (dest,ic, FALSE, FALSE);
13050     aopPut(dest,"b",0);
13051     aopPut(dest,"a",1);
13052     freeAsmop (dest, NULL, ic, FALSE);
13053 }
13054
13055 /*-----------------------------------------------------------------*/
13056 /* genMemsetX - gencode for memSetX data                           */
13057 /*-----------------------------------------------------------------*/
13058 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13059 {
13060     operand *to , *val , *count;
13061     symbol *lbl;
13062     char *l;
13063     int i;
13064     bitVect *rsave;
13065
13066     /* we know it has to be 3 parameters */
13067     assert (nparms == 3);
13068
13069     to = parms[0];
13070     val = parms[1];
13071     count = parms[2];
13072
13073     /* save DPTR if it needs to be saved */
13074     rsave = newBitVect(16);
13075     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13076             if (bitVectBitValue(ic->rMask,i))
13077                     rsave = bitVectSetBit(rsave,i);
13078     }
13079     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13080                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13081     savermask(rsave);
13082
13083     aopOp (to, ic, FALSE, FALSE);
13084     /* get "to" into DPTR */
13085     /* if the operand is already in dptr
13086        then we do nothing else we move the value to dptr */
13087     if (AOP_TYPE (to) != AOP_STR) {
13088         /* if already in DPTR then we need to push */
13089         if (AOP_TYPE(to) == AOP_DPTR) {
13090             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13091             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13092             if (options.model == MODEL_FLAT24)
13093                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13094             emitcode ("pop", "dph");
13095             emitcode ("pop", "dpl");
13096         } else {
13097             _startLazyDPSEvaluation ();
13098             /* if this is remateriazable */
13099             if (AOP_TYPE (to) == AOP_IMMD) {
13100                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13101             } else {                    /* we need to get it byte by byte */
13102                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13103                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13104                 if (options.model == MODEL_FLAT24) {
13105                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13106                 }
13107             }
13108             _endLazyDPSEvaluation ();
13109         }
13110     }
13111     freeAsmop (to, NULL, ic, FALSE);
13112
13113     aopOp (val, ic->next->next, FALSE,FALSE);
13114     aopOp (count, ic->next->next, FALSE,FALSE);
13115     lbl =newiTempLabel(NULL);
13116     /* now for the actual copy */
13117     if (AOP_TYPE(count) == AOP_LIT &&
13118         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13119         l = aopGet(val, 0, FALSE, FALSE, NULL);
13120         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13121         MOVA(l);
13122         emitLabel (lbl);
13123         emitcode ("movx", "@dptr,a");
13124         emitcode ("inc", "dptr");
13125         emitcode ("djnz","b,!tlabel",lbl->key+100);
13126     } else {
13127         symbol *lbl1 = newiTempLabel(NULL);
13128
13129         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13130         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13131         emitLabel (lbl);
13132         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13133         emitcode ("movx", "@dptr,a");
13134         emitcode ("inc", "dptr");
13135         emitcode ("mov","a,b");
13136         emitcode ("orl","a,_ap");
13137         emitcode ("jz","!tlabel",lbl1->key+100);
13138         emitcode ("mov","a,_ap");
13139         emitcode ("add","a,#!constbyte",0xFF);
13140         emitcode ("mov","_ap,a");
13141         emitcode ("mov","a,b");
13142         emitcode ("addc","a,#!constbyte",0xFF);
13143         emitcode ("mov","b,a");
13144         emitcode ("sjmp","!tlabel",lbl->key+100);
13145         emitLabel (lbl1);
13146     }
13147     freeAsmop (count, NULL, ic, FALSE);
13148     unsavermask(rsave);
13149 }
13150
13151 /*-----------------------------------------------------------------*/
13152 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13153 /*-----------------------------------------------------------------*/
13154 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13155 {
13156         bitVect *rsave ;
13157         operand *pnum, *result;
13158         int i;
13159
13160         assert (nparms==1);
13161         /* save registers that need to be saved */
13162         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13163                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13164
13165         pnum = parms[0];
13166         aopOp (pnum, ic, FALSE, FALSE);
13167         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13168         freeAsmop (pnum, NULL, ic, FALSE);
13169         emitcode ("lcall","NatLib_LoadPrimitive");
13170         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13171         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13172             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13173                 for (i = (size-1) ; i >= 0 ; i-- ) {
13174                         emitcode ("push","a%s",javaRet[i]);
13175                 }
13176                 for (i=0; i < size ; i++ ) {
13177                         emitcode ("pop","a%s",
13178                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13179                 }
13180         } else {
13181                 for (i = 0 ; i < size ; i++ ) {
13182                         aopPut(result,javaRet[i],i);
13183                 }
13184         }
13185         freeAsmop (result, NULL, ic, FALSE);
13186         unsavermask(rsave);
13187 }
13188
13189 /*-----------------------------------------------------------------*/
13190 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13191 /*-----------------------------------------------------------------*/
13192 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13193 {
13194         bitVect *rsave ;
13195         operand *pnum, *result;
13196         int size = 3;
13197         int i;
13198
13199         assert (nparms==1);
13200         /* save registers that need to be saved */
13201         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13202                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13203
13204         pnum = parms[0];
13205         aopOp (pnum, ic, FALSE, FALSE);
13206         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13207         freeAsmop (pnum, NULL, ic, FALSE);
13208         emitcode ("lcall","NatLib_LoadPointer");
13209         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13210         if (AOP_TYPE(result)!=AOP_STR) {
13211                 for (i = 0 ; i < size ; i++ ) {
13212                         aopPut(result,fReturn[i],i);
13213                 }
13214         }
13215         freeAsmop (result, NULL, ic, FALSE);
13216         unsavermask(rsave);
13217 }
13218
13219 /*-----------------------------------------------------------------*/
13220 /* genNatLibInstallStateBlock -                                    */
13221 /*-----------------------------------------------------------------*/
13222 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13223                                        operand **parms, const char *name)
13224 {
13225         bitVect *rsave ;
13226         operand *psb, *handle;
13227         assert (nparms==2);
13228
13229         /* save registers that need to be saved */
13230         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13231                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13232         psb = parms[0];
13233         handle = parms[1];
13234
13235         /* put pointer to state block into DPTR1 */
13236         aopOp (psb, ic, FALSE, FALSE);
13237         if (AOP_TYPE (psb) == AOP_IMMD) {
13238                 emitcode ("mov","dps,#1");
13239                 emitcode ("mov", "dptr,%s",
13240                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13241                 emitcode ("mov","dps,#0");
13242         } else {
13243                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13244                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13245                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13246         }
13247         freeAsmop (psb, NULL, ic, FALSE);
13248
13249         /* put libraryID into DPTR */
13250         emitcode ("mov","dptr,#LibraryID");
13251
13252         /* put handle into r3:r2 */
13253         aopOp (handle, ic, FALSE, FALSE);
13254         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13255                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13256                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13257                 emitcode ("pop","ar3");
13258                 emitcode ("pop","ar2");
13259         } else {
13260                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13261                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13262         }
13263         freeAsmop (psb, NULL, ic, FALSE);
13264
13265         /* make the call */
13266         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13267
13268         /* put return value into place*/
13269         _G.accInUse++;
13270         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13271         _G.accInUse--;
13272         aopPut(IC_RESULT(ic),"a",0);
13273         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13274         unsavermask(rsave);
13275 }
13276
13277 /*-----------------------------------------------------------------*/
13278 /* genNatLibRemoveStateBlock -                                     */
13279 /*-----------------------------------------------------------------*/
13280 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13281 {
13282         bitVect *rsave ;
13283
13284         assert(nparms==0);
13285
13286         /* save registers that need to be saved */
13287         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13288                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13289
13290         /* put libraryID into DPTR */
13291         emitcode ("mov","dptr,#LibraryID");
13292         /* make the call */
13293         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13294         unsavermask(rsave);
13295 }
13296
13297 /*-----------------------------------------------------------------*/
13298 /* genNatLibGetStateBlock -                                        */
13299 /*-----------------------------------------------------------------*/
13300 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13301                                    operand **parms,const char *name)
13302 {
13303         bitVect *rsave ;
13304         symbol *lbl = newiTempLabel(NULL);
13305
13306         assert(nparms==0);
13307         /* save registers that need to be saved */
13308         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13309                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13310
13311         /* put libraryID into DPTR */
13312         emitcode ("mov","dptr,#LibraryID");
13313         /* make the call */
13314         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13315         emitcode ("jnz","!tlabel",lbl->key+100);
13316
13317         /* put return value into place */
13318         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13319         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13320                 emitcode ("push","ar3");
13321                 emitcode ("push","ar2");
13322                 emitcode ("pop","%s",
13323                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13324                 emitcode ("pop","%s",
13325                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13326         } else {
13327                 aopPut(IC_RESULT(ic),"r2",0);
13328                 aopPut(IC_RESULT(ic),"r3",1);
13329         }
13330         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13331         emitLabel (lbl);
13332         unsavermask(rsave);
13333 }
13334
13335 /*-----------------------------------------------------------------*/
13336 /* genMMMalloc -                                                   */
13337 /*-----------------------------------------------------------------*/
13338 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13339                          int size, const char *name)
13340 {
13341         bitVect *rsave ;
13342         operand *bsize;
13343         symbol *rsym;
13344         symbol *lbl = newiTempLabel(NULL);
13345
13346         assert (nparms == 1);
13347         /* save registers that need to be saved */
13348         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13349                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13350
13351         bsize=parms[0];
13352         aopOp (bsize,ic,FALSE,FALSE);
13353
13354         /* put the size in R4-R2 */
13355         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13356                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13357                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13358                 if (size==3) {
13359                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13360                         emitcode("pop","ar4");
13361                 }
13362                 emitcode("pop","ar3");
13363                 emitcode("pop","ar2");
13364         } else {
13365                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13366                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13367                 if (size==3) {
13368                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13369                 }
13370         }
13371         freeAsmop (bsize, NULL, ic, FALSE);
13372
13373         /* make the call */
13374         emitcode ("lcall","MM_%s",name);
13375         emitcode ("jz","!tlabel",lbl->key+100);
13376         emitcode ("mov","r2,#!constbyte",0xff);
13377         emitcode ("mov","r3,#!constbyte",0xff);
13378         emitLabel (lbl);
13379         /* we don't care about the pointer : we just save the handle */
13380         rsym = OP_SYMBOL(IC_RESULT(ic));
13381         if (rsym->liveFrom != rsym->liveTo) {
13382                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13383                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13384                         emitcode ("push","ar3");
13385                         emitcode ("push","ar2");
13386                         emitcode ("pop","%s",
13387                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13388                         emitcode ("pop","%s",
13389                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13390                 } else {
13391                         aopPut(IC_RESULT(ic),"r2",0);
13392                         aopPut(IC_RESULT(ic),"r3",1);
13393                 }
13394                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13395         }
13396         unsavermask(rsave);
13397 }
13398
13399 /*-----------------------------------------------------------------*/
13400 /* genMMDeref -                                                    */
13401 /*-----------------------------------------------------------------*/
13402 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13403 {
13404         bitVect *rsave ;
13405         operand *handle;
13406
13407         assert (nparms == 1);
13408         /* save registers that need to be saved */
13409         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13410                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13411
13412         handle=parms[0];
13413         aopOp (handle,ic,FALSE,FALSE);
13414
13415         /* put the size in R4-R2 */
13416         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13417                 emitcode("push","%s",
13418                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13419                 emitcode("push","%s",
13420                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13421                 emitcode("pop","ar3");
13422                 emitcode("pop","ar2");
13423         } else {
13424                 emitcode ("mov","r2,%s",
13425                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13426                 emitcode ("mov","r3,%s",
13427                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13428         }
13429         freeAsmop (handle, NULL, ic, FALSE);
13430
13431         /* make the call */
13432         emitcode ("lcall","MM_Deref");
13433
13434         {
13435                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13436                 if (rsym->liveFrom != rsym->liveTo) {
13437                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13438                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13439                             _startLazyDPSEvaluation ();
13440
13441                             aopPut(IC_RESULT(ic),"dpl",0);
13442                             aopPut(IC_RESULT(ic),"dph",1);
13443                             aopPut(IC_RESULT(ic),"dpx",2);
13444
13445                             _endLazyDPSEvaluation ();
13446
13447                         }
13448                 }
13449         }
13450         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13451         unsavermask(rsave);
13452 }
13453
13454 /*-----------------------------------------------------------------*/
13455 /* genMMUnrestrictedPersist -                                      */
13456 /*-----------------------------------------------------------------*/
13457 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13458 {
13459         bitVect *rsave ;
13460         operand *handle;
13461
13462         assert (nparms == 1);
13463         /* save registers that need to be saved */
13464         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13465                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13466
13467         handle=parms[0];
13468         aopOp (handle,ic,FALSE,FALSE);
13469
13470         /* put the size in R3-R2 */
13471         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13472                 emitcode("push","%s",
13473                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13474                 emitcode("push","%s",
13475                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13476                 emitcode("pop","ar3");
13477                 emitcode("pop","ar2");
13478         } else {
13479                 emitcode ("mov","r2,%s",
13480                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13481                 emitcode ("mov","r3,%s",
13482                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13483         }
13484         freeAsmop (handle, NULL, ic, FALSE);
13485
13486         /* make the call */
13487         emitcode ("lcall","MM_UnrestrictedPersist");
13488
13489         {
13490                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13491                 if (rsym->liveFrom != rsym->liveTo) {
13492                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13493                         aopPut(IC_RESULT(ic),"a",0);
13494                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13495                 }
13496         }
13497         unsavermask(rsave);
13498 }
13499
13500 /*-----------------------------------------------------------------*/
13501 /* genSystemExecJavaProcess -                                      */
13502 /*-----------------------------------------------------------------*/
13503 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13504 {
13505         bitVect *rsave ;
13506         operand *handle, *pp;
13507
13508         assert (nparms==2);
13509         /* save registers that need to be saved */
13510         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13511                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13512
13513         pp = parms[0];
13514         handle = parms[1];
13515
13516         /* put the handle in R3-R2 */
13517         aopOp (handle,ic,FALSE,FALSE);
13518         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13519                 emitcode("push","%s",
13520                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13521                 emitcode("push","%s",
13522                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13523                 emitcode("pop","ar3");
13524                 emitcode("pop","ar2");
13525         } else {
13526                 emitcode ("mov","r2,%s",
13527                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13528                 emitcode ("mov","r3,%s",
13529                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13530         }
13531         freeAsmop (handle, NULL, ic, FALSE);
13532
13533         /* put pointer in DPTR */
13534         aopOp (pp,ic,FALSE,FALSE);
13535         if (AOP_TYPE(pp) == AOP_IMMD) {
13536                 emitcode ("mov", "dptr,%s",
13537                           aopGet (pp, 0, TRUE, FALSE, NULL));
13538         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13539                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13540                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13541                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13542         }
13543         freeAsmop (handle, NULL, ic, FALSE);
13544
13545         /* make the call */
13546         emitcode ("lcall","System_ExecJavaProcess");
13547
13548         /* put result in place */
13549         {
13550                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13551                 if (rsym->liveFrom != rsym->liveTo) {
13552                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13553                         aopPut(IC_RESULT(ic),"a",0);
13554                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13555                 }
13556         }
13557
13558         unsavermask(rsave);
13559 }
13560
13561 /*-----------------------------------------------------------------*/
13562 /* genSystemRTCRegisters -                                         */
13563 /*-----------------------------------------------------------------*/
13564 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13565                                   char *name)
13566 {
13567         bitVect *rsave ;
13568         operand *pp;
13569
13570         assert (nparms==1);
13571         /* save registers that need to be saved */
13572         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13573                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13574
13575         pp=parms[0];
13576         /* put pointer in DPTR */
13577         aopOp (pp,ic,FALSE,FALSE);
13578         if (AOP_TYPE (pp) == AOP_IMMD) {
13579                 emitcode ("mov","dps,#1");
13580                 emitcode ("mov", "dptr,%s",
13581                           aopGet (pp, 0, TRUE, FALSE, NULL));
13582                 emitcode ("mov","dps,#0");
13583         } else {
13584                 emitcode ("mov","dpl1,%s",
13585                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13586                 emitcode ("mov","dph1,%s",
13587                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13588                 emitcode ("mov","dpx1,%s",
13589                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13590         }
13591         freeAsmop (pp, NULL, ic, FALSE);
13592
13593         /* make the call */
13594         emitcode ("lcall","System_%sRTCRegisters",name);
13595
13596         unsavermask(rsave);
13597 }
13598
13599 /*-----------------------------------------------------------------*/
13600 /* genSystemThreadSleep -                                          */
13601 /*-----------------------------------------------------------------*/
13602 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13603 {
13604         bitVect *rsave ;
13605         operand *to, *s;
13606
13607         assert (nparms==1);
13608         /* save registers that need to be saved */
13609         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13610                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13611
13612         to = parms[0];
13613         aopOp(to,ic,FALSE,FALSE);
13614         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13615             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13616                 emitcode ("push","%s",
13617                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13618                 emitcode ("push","%s",
13619                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13620                 emitcode ("push","%s",
13621                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13622                 emitcode ("push","%s",
13623                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13624                 emitcode ("pop","ar3");
13625                 emitcode ("pop","ar2");
13626                 emitcode ("pop","ar1");
13627                 emitcode ("pop","ar0");
13628         } else {
13629                 emitcode ("mov","r0,%s",
13630                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13631                 emitcode ("mov","r1,%s",
13632                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13633                 emitcode ("mov","r2,%s",
13634                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13635                 emitcode ("mov","r3,%s",
13636                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13637         }
13638         freeAsmop (to, NULL, ic, FALSE);
13639
13640         /* suspend in acc */
13641         s = parms[1];
13642         aopOp(s,ic,FALSE,FALSE);
13643         emitcode ("mov","a,%s",
13644                   aopGet(s,0,FALSE,TRUE,NULL));
13645         freeAsmop (s, NULL, ic, FALSE);
13646
13647         /* make the call */
13648         emitcode ("lcall","System_%s",name);
13649
13650         unsavermask(rsave);
13651 }
13652
13653 /*-----------------------------------------------------------------*/
13654 /* genSystemThreadResume -                                         */
13655 /*-----------------------------------------------------------------*/
13656 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13657 {
13658         bitVect *rsave ;
13659         operand *tid,*pid;
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         tid = parms[0];
13667         pid = parms[1];
13668
13669         /* PID in R0 */
13670         aopOp(pid,ic,FALSE,FALSE);
13671         emitcode ("mov","r0,%s",
13672                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13673         freeAsmop (pid, NULL, ic, FALSE);
13674
13675         /* tid into ACC */
13676         aopOp(tid,ic,FALSE,FALSE);
13677         emitcode ("mov","a,%s",
13678                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13679         freeAsmop (tid, NULL, ic, FALSE);
13680
13681         emitcode ("lcall","System_ThreadResume");
13682
13683         /* put result into place */
13684         {
13685                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13686                 if (rsym->liveFrom != rsym->liveTo) {
13687                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13688                         aopPut(IC_RESULT(ic),"a",0);
13689                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13690                 }
13691         }
13692         unsavermask(rsave);
13693 }
13694
13695 /*-----------------------------------------------------------------*/
13696 /* genSystemProcessResume -                                        */
13697 /*-----------------------------------------------------------------*/
13698 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13699 {
13700         bitVect *rsave ;
13701         operand *pid;
13702
13703         assert (nparms==1);
13704         /* save registers that need to be saved */
13705         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13706                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13707
13708         pid = parms[0];
13709
13710         /* pid into ACC */
13711         aopOp(pid,ic,FALSE,FALSE);
13712         emitcode ("mov","a,%s",
13713                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13714         freeAsmop (pid, NULL, ic, FALSE);
13715
13716         emitcode ("lcall","System_ProcessResume");
13717
13718         unsavermask(rsave);
13719 }
13720
13721 /*-----------------------------------------------------------------*/
13722 /* genSystem -                                                     */
13723 /*-----------------------------------------------------------------*/
13724 static void genSystem (iCode *ic,int nparms,char *name)
13725 {
13726         assert(nparms == 0);
13727
13728         emitcode ("lcall","System_%s",name);
13729 }
13730
13731 /*-----------------------------------------------------------------*/
13732 /* genSystemPoll -                                                  */
13733 /*-----------------------------------------------------------------*/
13734 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13735 {
13736         bitVect *rsave ;
13737         operand *fp;
13738
13739         assert (nparms==1);
13740         /* save registers that need to be saved */
13741         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13742                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13743
13744         fp = parms[0];
13745         aopOp (fp,ic,FALSE,FALSE);
13746         if (AOP_TYPE (fp) == AOP_IMMD) {
13747                 emitcode ("mov", "dptr,%s",
13748                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13749         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13750                 emitcode ("mov","dpl,%s",
13751                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13752                 emitcode ("mov","dph,%s",
13753                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13754                 emitcode ("mov","dpx,%s",
13755                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13756         }
13757         freeAsmop (fp, NULL, ic, FALSE);
13758
13759         emitcode ("lcall","System_%sPoll",name);
13760
13761         /* put result into place */
13762         {
13763                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13764                 if (rsym->liveFrom != rsym->liveTo) {
13765                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13766                         aopPut(IC_RESULT(ic),"a",0);
13767                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13768                 }
13769         }
13770         unsavermask(rsave);
13771 }
13772
13773 /*-----------------------------------------------------------------*/
13774 /* genSystemGetCurrentID -                                         */
13775 /*-----------------------------------------------------------------*/
13776 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13777 {
13778         assert (nparms==0);
13779
13780         emitcode ("lcall","System_GetCurrent%sId",name);
13781         /* put result into place */
13782         {
13783                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13784                 if (rsym->liveFrom != rsym->liveTo) {
13785                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13786                         aopPut(IC_RESULT(ic),"a",0);
13787                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13788                 }
13789         }
13790 }
13791
13792 /*-----------------------------------------------------------------*/
13793 /* genDjnz - generate decrement & jump if not zero instrucion      */
13794 /*-----------------------------------------------------------------*/
13795 static int
13796 genDjnz (iCode * ic, iCode * ifx)
13797 {
13798   symbol *lbl, *lbl1;
13799   if (!ifx)
13800     return 0;
13801
13802   /* if the if condition has a false label
13803      then we cannot save */
13804   if (IC_FALSE (ifx))
13805     return 0;
13806
13807   /* if the minus is not of the form a = a - 1 */
13808   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13809       !IS_OP_LITERAL (IC_RIGHT (ic)))
13810     return 0;
13811
13812   if (operandLitValue (IC_RIGHT (ic)) != 1)
13813     return 0;
13814
13815   /* if the size of this greater than one then no
13816      saving */
13817   if (getSize (operandType (IC_RESULT (ic))) > 1)
13818     return 0;
13819
13820   /* otherwise we can save BIG */
13821
13822   D (emitcode (";", "genDjnz"));
13823
13824   lbl = newiTempLabel (NULL);
13825   lbl1 = newiTempLabel (NULL);
13826
13827   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13828
13829   if (AOP_NEEDSACC(IC_RESULT(ic)))
13830   {
13831       /* If the result is accessed indirectly via
13832        * the accumulator, we must explicitly write
13833        * it back after the decrement.
13834        */
13835       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13836
13837       if (strcmp(rByte, "a"))
13838       {
13839            /* Something is hopelessly wrong */
13840            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13841                    __FILE__, __LINE__);
13842            /* We can just give up; the generated code will be inefficient,
13843             * but what the hey.
13844             */
13845            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13846            return 0;
13847       }
13848       emitcode ("dec", "%s", rByte);
13849       aopPut (IC_RESULT (ic), rByte, 0);
13850       emitcode ("jnz", "!tlabel", lbl->key + 100);
13851   }
13852   else if (IS_AOP_PREG (IC_RESULT (ic)))
13853     {
13854       emitcode ("dec", "%s",
13855                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13856       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13857       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13858       ifx->generated = 1;
13859       emitcode ("jnz", "!tlabel", lbl->key + 100);
13860     }
13861   else
13862     {
13863       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13864                 lbl->key + 100);
13865     }
13866   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13867   emitLabel (lbl);
13868   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13869   emitLabel (lbl1);
13870
13871   if (!ifx->generated)
13872       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13873   ifx->generated = 1;
13874   return 1;
13875 }
13876
13877 /*-----------------------------------------------------------------*/
13878 /* genReceive - generate code for a receive iCode                  */
13879 /*-----------------------------------------------------------------*/
13880 static void
13881 genReceive (iCode * ic)
13882 {
13883     int size = getSize (operandType (IC_RESULT (ic)));
13884     int offset = 0;
13885     int rb1off ;
13886
13887     D (emitcode (";", "genReceive"));
13888
13889     if (ic->argreg == 1)
13890     {
13891         /* first parameter */
13892         if (AOP_IS_STR(IC_RESULT(ic)))
13893         {
13894             /* Nothing to do: it's already in the proper place. */
13895             return;
13896         }
13897         else
13898         {
13899             bool useDp2;
13900
13901             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13902                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13903                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13904
13905             _G.accInUse++;
13906             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13907             _G.accInUse--;
13908
13909             /* Sanity checking... */
13910             if (AOP_USESDPTR(IC_RESULT(ic)))
13911             {
13912                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13913                         "genReceive got unexpected DPTR.");
13914             }
13915             assignResultValue (IC_RESULT (ic), NULL);
13916         }
13917     }
13918     else if (ic->argreg > 12)
13919     { /* bit parameters */
13920       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13921         {
13922           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13923           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13924           outBitC(IC_RESULT (ic));
13925         }
13926     }
13927     else
13928     {
13929         /* second receive onwards */
13930         /* this gets a little tricky since unused receives will be
13931          eliminated, we have saved the reg in the type field . and
13932          we use that to figure out which register to use */
13933         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13934         rb1off = ic->argreg;
13935         while (size--)
13936         {
13937             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13938         }
13939     }
13940     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13941 }
13942
13943 /*-----------------------------------------------------------------*/
13944 /* genDummyRead - generate code for dummy read of volatiles        */
13945 /*-----------------------------------------------------------------*/
13946 static void
13947 genDummyRead (iCode * ic)
13948 {
13949   operand *op;
13950   int size, offset;
13951
13952   D (emitcode(";", "genDummyRead"));
13953
13954   op = IC_RIGHT (ic);
13955   if (op && IS_SYMOP (op))
13956     {
13957       aopOp (op, ic, FALSE, FALSE);
13958
13959       /* if the result is a bit */
13960       if (AOP_TYPE (op) == AOP_CRY)
13961         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13962       else
13963         {
13964           /* bit variables done */
13965           /* general case */
13966           size = AOP_SIZE (op);
13967           offset = 0;
13968           while (size--)
13969           {
13970             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13971             offset++;
13972           }
13973         }
13974
13975       freeAsmop (op, NULL, ic, TRUE);
13976     }
13977
13978   op = IC_LEFT (ic);
13979   if (op && IS_SYMOP (op))
13980     {
13981       aopOp (op, ic, FALSE, FALSE);
13982
13983       /* if the result is a bit */
13984       if (AOP_TYPE (op) == AOP_CRY)
13985         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13986       else
13987         {
13988           /* bit variables done */
13989           /* general case */
13990           size = AOP_SIZE (op);
13991           offset = 0;
13992           while (size--)
13993           {
13994             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13995             offset++;
13996           }
13997         }
13998
13999       freeAsmop (op, NULL, ic, TRUE);
14000     }
14001 }
14002
14003 /*-----------------------------------------------------------------*/
14004 /* genCritical - generate code for start of a critical sequence    */
14005 /*-----------------------------------------------------------------*/
14006 static void
14007 genCritical (iCode *ic)
14008 {
14009   symbol *tlbl = newiTempLabel (NULL);
14010
14011   D (emitcode(";", "genCritical"));
14012
14013   if (IC_RESULT (ic))
14014     {
14015       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14016       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14017       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14018       aopPut (IC_RESULT (ic), zero, 0);
14019       emitLabel (tlbl);
14020       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14021     }
14022   else
14023     {
14024       emitcode ("setb", "c");
14025       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14026       emitcode ("clr", "c");
14027       emitLabel (tlbl);
14028       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14029     }
14030 }
14031
14032 /*-----------------------------------------------------------------*/
14033 /* genEndCritical - generate code for end of a critical sequence   */
14034 /*-----------------------------------------------------------------*/
14035 static void
14036 genEndCritical (iCode *ic)
14037 {
14038   D(emitcode(";", "genEndCritical"));
14039
14040   if (IC_RIGHT (ic))
14041     {
14042       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14043       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14044         {
14045           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14046           emitcode ("mov", "ea,c");
14047         }
14048       else
14049         {
14050           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14051           emitcode ("rrc", "a");
14052           emitcode ("mov", "ea,c");
14053         }
14054       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14055     }
14056   else
14057     {
14058       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14059       emitcode ("mov", "ea,c");
14060     }
14061 }
14062
14063
14064
14065 /*-----------------------------------------------------------------*/
14066 /* genBuiltIn - calls the appropriate function to  generating code */
14067 /* for a built in function                                         */
14068 /*-----------------------------------------------------------------*/
14069 static void genBuiltIn (iCode *ic)
14070 {
14071         operand *bi_parms[MAX_BUILTIN_ARGS];
14072         int nbi_parms;
14073         iCode *bi_iCode;
14074         symbol *bif;
14075
14076         /* get all the arguments for a built in function */
14077         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14078
14079         /* which function is it */
14080         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14081         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14082                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14083         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14084                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14085         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14086                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14087         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14088                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14089         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14090                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14091         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14092                 genInp(bi_iCode,nbi_parms,bi_parms);
14093         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14094                 genOutp(bi_iCode,nbi_parms,bi_parms);
14095         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14096                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14097                 /* JavaNative builtIns */
14098         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14099                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14100         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14101                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14102         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14103                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14104         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14105                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14106         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14107                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14108         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14109                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14110         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14111                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14112         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14113                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14114         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14115                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14116         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14117                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14118         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14119                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14120         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14121                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14122         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14123                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14124         } else if (strcmp(bif->name,"MM_Free")==0) {
14125                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14126         } else if (strcmp(bif->name,"MM_Deref")==0) {
14127                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14128         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14129                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14130         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14131                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14132         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14133                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14134         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14135                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14136         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14137                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14138         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14139                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14140         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14141                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14142         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14143                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14144         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14145                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14146         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14147                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14148         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14149                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14150         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14151                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14152         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14153                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14154         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14155                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14156         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14157                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14158         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14159                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14160         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14161                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14162         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14163                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14164         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14165                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14166         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14167                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14168         } else {
14169                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14170                 return ;
14171         }
14172         return ;
14173 }
14174
14175 /*-----------------------------------------------------------------*/
14176 /* gen390Code - generate code for Dallas 390 based controllers     */
14177 /*-----------------------------------------------------------------*/
14178 void
14179 gen390Code (iCode * lic)
14180 {
14181   iCode *ic;
14182   int cln = 0;
14183
14184   _G.currentFunc = NULL;
14185   lineHead = lineCurr = NULL;
14186   dptrn[1][0] = "dpl1";
14187   dptrn[1][1] = "dph1";
14188   dptrn[1][2] = "dpx1";
14189
14190   if (options.model == MODEL_FLAT24) {
14191     fReturnSizeDS390 = 5;
14192     fReturn = fReturn24;
14193   } else {
14194     fReturnSizeDS390 = 4;
14195     fReturn = fReturn16;
14196     options.stack10bit=0;
14197   }
14198 #if 1
14199   /* print the allocation information */
14200   if (allocInfo && currFunc)
14201     printAllocInfo (currFunc, codeOutBuf);
14202 #endif
14203   /* if debug information required */
14204   if (options.debug && currFunc)
14205     {
14206       debugFile->writeFunction (currFunc, lic);
14207     }
14208   /* stack pointer name */
14209   if (options.useXstack)
14210     spname = "_spx";
14211   else
14212     spname = "sp";
14213
14214
14215   for (ic = lic; ic; ic = ic->next)
14216     {
14217       _G.current_iCode = ic;
14218
14219       if (ic->lineno && cln != ic->lineno)
14220         {
14221           if (options.debug)
14222             {
14223               debugFile->writeCLine (ic);
14224             }
14225           if (!options.noCcodeInAsm) {
14226             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14227                       printCLine(ic->filename, ic->lineno));
14228           }
14229           cln = ic->lineno;
14230         }
14231       if (options.iCodeInAsm) {
14232         char *iLine = printILine(ic);
14233         emitcode(";", "ic:%d: %s", ic->key, iLine);
14234         dbuf_free(iLine);
14235       }
14236       /* if the result is marked as
14237          spilt and rematerializable or code for
14238          this has already been generated then
14239          do nothing */
14240       if (resultRemat (ic) || ic->generated)
14241         continue;
14242
14243       /* depending on the operation */
14244       switch (ic->op)
14245         {
14246         case '!':
14247           genNot (ic);
14248           break;
14249
14250         case '~':
14251           genCpl (ic);
14252           break;
14253
14254         case UNARYMINUS:
14255           genUminus (ic);
14256           break;
14257
14258         case IPUSH:
14259           genIpush (ic);
14260           break;
14261
14262         case IPOP:
14263           /* IPOP happens only when trying to restore a
14264              spilt live range, if there is an ifx statement
14265              following this pop then the if statement might
14266              be using some of the registers being popped which
14267              would destory the contents of the register so
14268              we need to check for this condition and handle it */
14269           if (ic->next &&
14270               ic->next->op == IFX &&
14271               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14272             genIfx (ic->next, ic);
14273           else
14274             genIpop (ic);
14275           break;
14276
14277         case CALL:
14278           genCall (ic);
14279           break;
14280
14281         case PCALL:
14282           genPcall (ic);
14283           break;
14284
14285         case FUNCTION:
14286           genFunction (ic);
14287           break;
14288
14289         case ENDFUNCTION:
14290           genEndFunction (ic);
14291           break;
14292
14293         case RETURN:
14294           genRet (ic);
14295           break;
14296
14297         case LABEL:
14298           genLabel (ic);
14299           break;
14300
14301         case GOTO:
14302           genGoto (ic);
14303           break;
14304
14305         case '+':
14306           genPlus (ic);
14307           break;
14308
14309         case '-':
14310           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14311             genMinus (ic);
14312           break;
14313
14314         case '*':
14315           genMult (ic);
14316           break;
14317
14318         case '/':
14319           genDiv (ic);
14320           break;
14321
14322         case '%':
14323           genMod (ic);
14324           break;
14325
14326         case '>':
14327           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14328           break;
14329
14330         case '<':
14331           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14332           break;
14333
14334         case LE_OP:
14335         case GE_OP:
14336         case NE_OP:
14337
14338           /* note these two are xlated by algebraic equivalence
14339              during parsing SDCC.y */
14340           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14341                   "got '>=' or '<=' shouldn't have come here");
14342           break;
14343
14344         case EQ_OP:
14345           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14346           break;
14347
14348         case AND_OP:
14349           genAndOp (ic);
14350           break;
14351
14352         case OR_OP:
14353           genOrOp (ic);
14354           break;
14355
14356         case '^':
14357           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14358           break;
14359
14360         case '|':
14361           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14362           break;
14363
14364         case BITWISEAND:
14365           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14366           break;
14367
14368         case INLINEASM:
14369           genInline (ic);
14370           break;
14371
14372         case RRC:
14373           genRRC (ic);
14374           break;
14375
14376         case RLC:
14377           genRLC (ic);
14378           break;
14379
14380         case GETHBIT:
14381           genGetHbit (ic);
14382           break;
14383
14384         case LEFT_OP:
14385           genLeftShift (ic);
14386           break;
14387
14388         case RIGHT_OP:
14389           genRightShift (ic);
14390           break;
14391
14392         case GET_VALUE_AT_ADDRESS:
14393           genPointerGet (ic,
14394                          hasInc (IC_LEFT (ic), ic,
14395                                  getSize (operandType (IC_RESULT (ic)))));
14396           break;
14397
14398         case '=':
14399           if (POINTER_SET (ic))
14400             genPointerSet (ic,
14401                            hasInc (IC_RESULT (ic), ic,
14402                                    getSize (operandType (IC_RIGHT (ic)))));
14403           else
14404             genAssign (ic);
14405           break;
14406
14407         case IFX:
14408           genIfx (ic, NULL);
14409           break;
14410
14411         case ADDRESS_OF:
14412           genAddrOf (ic);
14413           break;
14414
14415         case JUMPTABLE:
14416           genJumpTab (ic);
14417           break;
14418
14419         case CAST:
14420           genCast (ic);
14421           break;
14422
14423         case RECEIVE:
14424           genReceive (ic);
14425           break;
14426
14427         case SEND:
14428           if (ic->builtinSEND)
14429             genBuiltIn(ic);
14430           else
14431             addSet (&_G.sendSet, ic);
14432           break;
14433
14434         case DUMMY_READ_VOLATILE:
14435           genDummyRead (ic);
14436           break;
14437
14438         case CRITICAL:
14439           genCritical (ic);
14440           break;
14441
14442         case ENDCRITICAL:
14443           genEndCritical (ic);
14444           break;
14445
14446         case SWAP:
14447           genSwap (ic);
14448           break;
14449
14450 #if 0 // obsolete, and buggy for != xdata
14451         case ARRAYINIT:
14452             genArrayInit(ic);
14453             break;
14454 #endif
14455
14456         default:
14457             /* This should never happen, right? */
14458             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n", 
14459                     ic->op, ic->op, __FILE__, __LINE__);
14460             ic = ic;
14461         }
14462     }
14463
14464
14465   /* now we are ready to call the
14466      peep hole optimizer */
14467   if (!options.nopeep)
14468     peepHole (&lineHead);
14469
14470   /* now do the actual printing */
14471   printLine (lineHead, codeOutBuf);
14472   return;
14473 }