* src/ds390/gen.c (genAnd, genOr, genXor): fixed bug 1546986
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) x
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37
38 #include "common.h"
39 #include "main.h"
40 #include "ralloc.h"
41 #include "gen.h"
42
43 #define BETTER_LITERAL_SHIFT
44
45 char *aopLiteral (value * val, int offset);
46 extern int allocInfo;
47
48 /* this is the down and dirty file with all kinds of
49    kludgy & hacky stuff. This is what it is all about
50    CODE GENERATION for a specific MCU . some of the
51    routines may be reusable, will have to see */
52
53 static char *zero = "#0";
54 static char *one = "#1";
55 static char *spname;
56
57 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
58 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
59
60 unsigned fReturnSizeDS390 = 5;
61 static char *fReturn24[] =
62 {"dpl", "dph", "dpx", "b", "a"};
63 static char *fReturn16[] =
64 {"dpl", "dph", "b", "a"};
65 static char **fReturn = fReturn24;
66 static char *accUse[] =
67 {"a", "b"};
68 static char *dptrn[2][3];
69 static char *javaRet[] = { "r0","r1","r2","r3"};
70 static short rbank = -1;
71
72 #define REG_WITH_INDEX   ds390_regWithIdx
73
74 #define AOP(op) op->aop
75 #define AOP_TYPE(op) AOP(op)->type
76 #define AOP_SIZE(op) AOP(op)->size
77 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
78                        AOP_TYPE(x) == AOP_R0))
79
80 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
81                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
82                          AOP(x)->paged))
83
84 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
85                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
86                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
87 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
88 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
89 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
90
91 // The following two macros can be used even if the aop has not yet been aopOp'd.
92 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
93 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
94
95 /* Workaround for DS80C390 bug: div ab may return bogus results
96  * if A is accessed in instruction immediately before the div.
97  *
98  * Will be fixed in B4 rev of processor, Dallas claims.
99  */
100
101 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
102     if (!AOP_NEEDSACC(RIGHT))         \
103     {               \
104       /* We can load A first, then B, since     \
105        * B (the RIGHT operand) won't clobber A,   \
106        * thus avoiding touching A right before the div. \
107        */             \
108       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
109       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
110       MOVA(L);            \
111       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
112       MOVB(L); \
113     }               \
114     else              \
115     {               \
116       /* Just stuff in a nop after loading A. */    \
117       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
118       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
119       MOVA(L);            \
120       emitcode("nop", "; workaround for DS80C390 div bug.");  \
121     }
122
123 #define R0INB   _G.bu.bs.r0InB
124 #define R1INB   _G.bu.bs.r1InB
125 #define OPINB   _G.bu.bs.OpInB
126 #define BINUSE  _G.bu.BInUse
127
128 static struct
129   {
130     short r0Pushed;
131     short r1Pushed;
132     union
133       {
134         struct
135           {
136             short r0InB : 2;//2 so we can see it overflow
137             short r1InB : 2;//2 so we can see it overflow
138             short OpInB : 2;//2 so we can see it overflow
139           } bs;
140         short BInUse;
141       } bu;
142     short accInUse;
143     short inLine;
144     short debugLine;
145     short nRegsSaved;
146     short dptrInUse;
147     short dptr1InUse;
148     set *sendSet;
149     iCode *current_iCode;
150     symbol *currentFunc;
151   }
152 _G;
153
154 static char *rb1regs[] = {
155     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
156     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
157 };
158
159 static void saveRBank (int, iCode *, bool);
160
161 #define RESULTONSTACK(x) \
162                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
163                          IC_RESULT(x)->aop->type == AOP_STK )
164
165 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
166 #define MOVB(x)  movb(x)
167
168 #define CLRC    emitcode("clr","c")
169 #define SETC    emitcode("setb","c")
170
171 // A scratch register which will be used to hold
172 // result bytes from operands in far space via DPTR2.
173 #define DP2_RESULT_REG  "_ap"
174
175 static lineNode *lineHead = NULL;
176 static lineNode *lineCurr = NULL;
177
178 static unsigned char SLMask[] =
179 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
180  0xE0, 0xC0, 0x80, 0x00};
181 static unsigned char SRMask[] =
182 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
183  0x07, 0x03, 0x01, 0x00};
184
185 #define LSB     0
186 #define MSB16   1
187 #define MSB24   2
188 #define MSB32   3
189 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
190                                 symbol *lbl = newiTempLabel(NULL);              \
191                                 emitcode ("setb","F1");                         \
192                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
193                                 emitcode ("clr","F1");                          \
194                                 emitcode ("","!tlabeldef",lbl->key+100);        \
195                         }}
196 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
197                                 emitcode ("mov","EA,F1");                       \
198                         }}
199
200 static int _currentDPS;         /* Current processor DPS. */
201 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
202 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
203
204 /*-----------------------------------------------------------------*/
205 /* emitcode - writes the code into a file : for now it is simple    */
206 /*-----------------------------------------------------------------*/
207 static void
208 emitcode (char *inst, const char *fmt,...)
209 {
210   va_list ap;
211   char lb[INITIAL_INLINEASM];
212   char *lbp = lb;
213
214   va_start (ap, fmt);
215
216   if (inst && *inst)
217     {
218       if (fmt && *fmt)
219         {
220           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
221         }
222       else
223         {
224           SNPRINTF (lb, sizeof(lb), "%s", inst);
225         }
226
227       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
228     }
229   else
230     {
231       tvsprintf (lb, sizeof(lb), fmt, ap);
232     }
233
234   while (isspace ((unsigned char)*lbp))
235     {
236       lbp++;
237     }
238
239   if (lbp && *lbp)
240     {
241       lineCurr = (lineCurr ?
242                   connectLine (lineCurr, newLineNode (lb)) :
243                   (lineHead = newLineNode (lb)));
244     }
245
246   lineCurr->isInline = _G.inLine;
247   lineCurr->isDebug = _G.debugLine;
248   lineCurr->ic = _G.current_iCode;
249   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
250   va_end (ap);
251 }
252
253 static void
254 emitLabel (symbol *tlbl)
255 {
256   emitcode ("", "!tlabeldef", tlbl->key + 100);
257 }
258
259 /*-----------------------------------------------------------------*/
260 /* ds390_emitDebuggerSymbol - associate the current code location  */
261 /*   with a debugger symbol                                        */
262 /*-----------------------------------------------------------------*/
263 void
264 ds390_emitDebuggerSymbol (char * debugSym)
265 {
266   _G.debugLine = 1;
267   emitcode ("", "%s ==.", debugSym);
268   _G.debugLine = 0;
269 }
270
271 /*-----------------------------------------------------------------*/
272 /* mova - moves specified value into accumulator                   */
273 /*-----------------------------------------------------------------*/
274 static void
275 mova (const char *x)
276 {
277   /* do some early peephole optimization */
278   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
279     return;
280
281   emitcode("mov", "a,%s", x);
282 }
283
284 /*-----------------------------------------------------------------*/
285 /* movb - moves specified value into register b                    */
286 /*-----------------------------------------------------------------*/
287 static void
288 movb (const char *x)
289 {
290   /* do some early peephole optimization */
291   if (!strncmp(x, "b", 2))
292     return;
293
294   emitcode("mov","b,%s", x);
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* movc - moves specified value into the carry                     */
299 /*-----------------------------------------------------------------*/
300 static void
301 movc (const char *s)
302 {
303   if (s == zero)
304     CLRC;
305   else if (s == one)
306     SETC;
307   else if (strcmp (s, "c"))
308     {/* it's not in carry already */
309       MOVA (s);
310       /* set C, if a >= 1 */
311       emitcode ("add", "a,#0xff");
312     }
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* pushB - saves register B if necessary                           */
317 /*-----------------------------------------------------------------*/
318 static bool
319 pushB (void)
320 {
321   bool pushedB = FALSE;
322
323   if (BINUSE)
324     {
325       emitcode ("push", "b");
326 //    printf("B was in use !\n");
327       pushedB = TRUE;
328     }
329   else
330     {
331       OPINB++;
332     }
333   return pushedB;
334 }
335
336 /*-----------------------------------------------------------------*/
337 /* popB - restores value of register B if necessary                */
338 /*-----------------------------------------------------------------*/
339 static void
340 popB (bool pushedB)
341 {
342   if (pushedB)
343     {
344       emitcode ("pop", "b");
345     }
346   else
347     {
348       OPINB--;
349     }
350 }
351
352 /*-----------------------------------------------------------------*/
353 /* pushReg - saves register                                        */
354 /*-----------------------------------------------------------------*/
355 static bool
356 pushReg (int index, bool bits_pushed)
357 {
358   regs * reg = REG_WITH_INDEX (index);
359   if (reg->type == REG_BIT)
360     {
361       if (!bits_pushed)
362         emitcode ("push", "%s", reg->base);
363       return TRUE;
364     }
365   else
366     emitcode ("push", "%s", reg->dname);
367   return bits_pushed;
368 }
369
370 /*-----------------------------------------------------------------*/
371 /* popReg - restores register                                      */
372 /*-----------------------------------------------------------------*/
373 static bool
374 popReg (int index, bool bits_popped)
375 {
376   regs * reg = REG_WITH_INDEX (index);
377   if (reg->type == REG_BIT)
378     {
379       if (!bits_popped)
380         emitcode ("pop", "%s", reg->base);
381       return TRUE;
382     }
383   else
384     emitcode ("pop", "%s", reg->dname);
385   return bits_popped;
386 }
387
388 /*-----------------------------------------------------------------*/
389 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
390 /*-----------------------------------------------------------------*/
391 static regs *
392 getFreePtr (iCode * ic, asmop ** aopp, bool result)
393 {
394   bool r0iu, r1iu;
395   bool r0ou, r1ou;
396
397   /* the logic: if r0 & r1 used in the instruction
398      then we are in trouble otherwise */
399
400   /* first check if r0 & r1 are used by this
401      instruction, in which case we are in trouble */
402   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
403   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
404   if (r0iu && r1iu) {
405       goto endOfWorld;
406     }
407
408   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
409   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
410
411   /* if no usage of r0 then return it */
412   if (!r0iu && !r0ou)
413     {
414       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
415       (*aopp)->type = AOP_R0;
416
417       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
418     }
419
420   /* if no usage of r1 then return it */
421   if (!r1iu && !r1ou)
422     {
423       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
424       (*aopp)->type = AOP_R1;
425
426       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
427     }
428
429   /* now we know they both have usage */
430   /* if r0 not used in this instruction */
431   if (!r0iu)
432     {
433       /* push it if not already pushed */
434       if (!_G.r0Pushed)
435         {
436           emitcode ("push", "%s",
437                     REG_WITH_INDEX (R0_IDX)->dname);
438           _G.r0Pushed++;
439         }
440
441       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
442       (*aopp)->type = AOP_R0;
443
444       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
445     }
446
447   /* if r1 not used then */
448
449   if (!r1iu)
450     {
451       /* push it if not already pushed */
452       if (!_G.r1Pushed)
453         {
454           emitcode ("push", "%s",
455                     REG_WITH_INDEX (R1_IDX)->dname);
456           _G.r1Pushed++;
457         }
458
459       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
460       (*aopp)->type = AOP_R1;
461       return REG_WITH_INDEX (R1_IDX);
462     }
463
464 endOfWorld:
465   /* I said end of world, but not quite end of world yet */
466   /* if this is a result then we can push it on the stack */
467   if (result)
468     {
469       (*aopp)->type = AOP_STK;
470       return NULL;
471     }
472
473   /* now this is REALLY the end of the world */
474   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
475           "getFreePtr should never reach here");
476   exit (1);
477
478   return NULL; // notreached, but makes compiler happy.
479 }
480
481
482 /*-----------------------------------------------------------------*/
483 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
484 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
485 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
486 /*-----------------------------------------------------------------*/
487 static void
488 genSetDPTR (int n)
489 {
490
491   /* If we are doing lazy evaluation, simply note the desired
492    * change, but don't emit any code yet.
493    */
494   if (_lazyDPS)
495     {
496       _desiredDPS = n;
497       return;
498     }
499
500   if (!n)
501     {
502       emitcode ("mov", "dps,#0");
503     }
504   else
505     {
506       TR_DPTR("#1");
507       emitcode ("mov", "dps,#1");
508     }
509 }
510
511 /*------------------------------------------------------------------*/
512 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
513 /*                                                                  */
514 /* Any code that operates on DPTR (NB: not on the individual        */
515 /* components, like DPH) *must* call _flushLazyDPS() before using   */
516 /* DPTR within a lazy DPS evaluation block.                         */
517 /*                                                                  */
518 /* Note that aopPut and aopGet already contain the proper calls to  */
519 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
520 /* DPS evaluation block.                                            */
521 /*                                                                  */
522 /* Also, _flushLazyDPS must be called before any flow control       */
523 /* operations that could potentially branch out of the block.       */
524 /*                                                                  */
525 /* Lazy DPS evaluation is simply an optimization (though an         */
526 /* important one), so if in doubt, leave it out.                    */
527 /*------------------------------------------------------------------*/
528 static void
529 _startLazyDPSEvaluation (void)
530 {
531   _currentDPS = 0;
532   _desiredDPS = 0;
533 #ifdef BETTER_LITERAL_SHIFT
534   _lazyDPS++;
535 #else
536   _lazyDPS = 1;
537 #endif
538 }
539
540 /*------------------------------------------------------------------*/
541 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
542 /* desired one. Call before using DPTR within a lazy DPS evaluation */
543 /* block.                                                           */
544 /*------------------------------------------------------------------*/
545 static void
546 _flushLazyDPS (void)
547 {
548   if (!_lazyDPS)
549     {
550       /* nothing to do. */
551       return;
552     }
553
554   if (_desiredDPS != _currentDPS)
555     {
556       if (_desiredDPS)
557         {
558           emitcode ("inc", "dps");
559         }
560       else
561         {
562           emitcode ("dec", "dps");
563         }
564       _currentDPS = _desiredDPS;
565     }
566 }
567
568 /*-----------------------------------------------------------------*/
569 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
570 /*                                                                 */
571 /* Forces us back to the safe state (standard DPTR selected).      */
572 /*-----------------------------------------------------------------*/
573 static void
574 _endLazyDPSEvaluation (void)
575 {
576 #ifdef BETTER_LITERAL_SHIFT
577   _lazyDPS--;
578 #else
579   _lazyDPS = 0;
580 #endif
581   if (!_lazyDPS)
582   {
583     if (_currentDPS)
584     {
585       genSetDPTR (0);
586       _flushLazyDPS ();
587     }
588     _currentDPS = 0;
589     _desiredDPS = 0;
590   }
591 }
592
593
594 /*-----------------------------------------------------------------*/
595 /* newAsmop - creates a new asmOp                                  */
596 /*-----------------------------------------------------------------*/
597 static asmop *
598 newAsmop (short type)
599 {
600   asmop *aop;
601
602   aop = Safe_calloc (1, sizeof (asmop));
603   aop->type = type;
604   aop->allocated = 1;
605   return aop;
606 }
607
608 /*-----------------------------------------------------------------*/
609 /* pointerCode - returns the code for a pointer type               */
610 /*-----------------------------------------------------------------*/
611 static int
612 pointerCode (sym_link * etype)
613 {
614
615   return PTR_TYPE (SPEC_OCLS (etype));
616
617 }
618
619 /*-----------------------------------------------------------------*/
620 /* leftRightUseAcc - returns size of accumulator use by operands   */
621 /*-----------------------------------------------------------------*/
622 static int
623 leftRightUseAcc(iCode *ic)
624 {
625   operand *op;
626   int size;
627   int accuseSize = 0;
628   int accuse = 0;
629
630   if (!ic)
631     {
632       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
633               "null iCode pointer");
634       return 0;
635     }
636
637   if (ic->op == IFX)
638     {
639       op = IC_COND (ic);
640       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
641         {
642           accuse = 1;
643           size = getSize (OP_SYMBOL (op)->type);
644           if (size>accuseSize)
645             accuseSize = size;
646         }
647     }
648   else if (ic->op == JUMPTABLE)
649     {
650       op = IC_JTCOND (ic);
651       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
652         {
653           accuse = 1;
654           size = getSize (OP_SYMBOL (op)->type);
655           if (size>accuseSize)
656             accuseSize = size;
657         }
658     }
659   else
660     {
661       op = IC_LEFT (ic);
662       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
663         {
664           accuse = 1;
665           size = getSize (OP_SYMBOL (op)->type);
666           if (size>accuseSize)
667             accuseSize = size;
668         }
669       op = IC_RIGHT (ic);
670       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
671         {
672           accuse = 1;
673           size = getSize (OP_SYMBOL (op)->type);
674           if (size>accuseSize)
675             accuseSize = size;
676         }
677     }
678
679   if (accuseSize)
680     return accuseSize;
681   else
682     return accuse;
683 }
684
685 /*-----------------------------------------------------------------*/
686 /* aopForSym - for a true symbol                                   */
687 /*-----------------------------------------------------------------*/
688 static asmop *
689 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
690 {
691   asmop *aop;
692   memmap *space;
693   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
694   char *dpl = useDP2 ? "dpl1" : "dpl";
695   char *dph = useDP2 ? "dph1" : "dph";
696   char *dpx = useDP2 ? "dpx1" : "dpx";
697
698   wassertl (ic != NULL, "Got a null iCode");
699   wassertl (sym != NULL, "Got a null symbol");
700
701   space = SPEC_OCLS (sym->etype);
702
703   /* if already has one */
704   if (sym->aop)
705     {
706       if ((sym->aop->type == AOP_DPTR && useDP2)
707           || (sym->aop->type == AOP_DPTR2 && !useDP2))
708         sym->aop = NULL;
709       else
710         {
711           sym->aop->allocated++;
712           return sym->aop;
713         }
714     }
715
716   /* assign depending on the storage class */
717   /* if it is on the stack or indirectly addressable */
718   /* space we need to assign either r0 or r1 to it   */
719   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
720     {
721       sym->aop = aop = newAsmop (0);
722       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
723       aop->size = getSize (sym->type);
724
725       /* now assign the address of the variable to
726          the pointer register */
727       if (aop->type != AOP_STK)
728         {
729           if (sym->onStack)
730             {
731               signed char offset = ((sym->stack < 0) ?
732                          ((signed char) (sym->stack - _G.nRegsSaved)) :
733                          ((signed char) sym->stack)) & 0xff;
734
735               if ((abs(offset) <= 3) ||
736                   (accuse && (abs(offset) <= 7)))
737                 {
738                   emitcode ("mov", "%s,_bp",
739                             aop->aopu.aop_ptr->name);
740                   while (offset < 0)
741                     {
742                       emitcode ("dec", aop->aopu.aop_ptr->name);
743                       offset++;
744                     }
745                   while (offset > 0)
746                     {
747                       emitcode ("inc", aop->aopu.aop_ptr->name);
748                       offset--;
749                     }
750                 }
751               else
752                 {
753                   if (accuse)
754                     emitcode ("push", "acc");
755                   emitcode ("mov", "a,_bp");
756                   emitcode ("add", "a,#!constbyte", offset);
757                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
758                   if (accuse)
759                     emitcode ("pop", "acc");
760                 }
761             }
762           else
763             {
764               emitcode ("mov", "%s,#%s",
765                         aop->aopu.aop_ptr->name,
766                         sym->rname);
767             }
768           aop->paged = space->paged;
769         }
770       else
771         aop->aopu.aop_stk = sym->stack;
772       return aop;
773     }
774
775   if (sym->onStack && options.stack10bit)
776     {
777       short stack_val = -((sym->stack < 0) ?
778                           ((short) (sym->stack - _G.nRegsSaved)) :
779                           ((short) sym->stack)) ;
780       if (_G.dptrInUse ) {
781           emitcode ("push",dpl);
782           emitcode ("push",dph);
783           emitcode ("push",dpx);
784       }
785       /* It's on the 10 bit stack, which is located in
786        * far data space.
787        */
788       if (stack_val < 0 && stack_val > -5)
789         { /* between -5 & -1 */
790           if (options.model == MODEL_FLAT24)
791             {
792               emitcode ("mov", "%s,#!constbyte", dpx,
793                         (options.stack_loc >> 16) & 0xff);
794             }
795           emitcode ("mov", "%s,_bpx+1", dph);
796           emitcode ("mov", "%s,_bpx", dpl);
797           if (useDP2) {
798               emitcode ("mov","dps,#1");
799           }
800           stack_val = -stack_val;
801           while (stack_val--) {
802               emitcode ("inc","dptr");
803           }
804           if (useDP2) {
805               emitcode("mov","dps,#0");
806           }
807         }
808       else
809         {
810           if (accuse)
811               emitcode ("push", "acc");
812
813           emitcode ("mov", "a,_bpx");
814           emitcode ("clr","c");
815           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
816           emitcode ("mov","%s,a", dpl);
817           emitcode ("mov","a,_bpx+1");
818           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
819           emitcode ("mov", "%s,a", dph);
820           if (options.model == MODEL_FLAT24)
821             {
822               emitcode ("mov", "%s,#!constbyte", dpx,
823                         (options.stack_loc >> 16) & 0xff);
824             }
825
826           if (accuse)
827               emitcode ("pop", "acc");
828         }
829       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
830       aop->size = getSize (sym->type);
831       return aop;
832     }
833
834   /* if in bit space */
835   if (IN_BITSPACE (space))
836     {
837       sym->aop = aop = newAsmop (AOP_CRY);
838       aop->aopu.aop_dir = sym->rname;
839       aop->size = getSize (sym->type);
840       return aop;
841     }
842   /* if it is in direct space */
843   if (IN_DIRSPACE (space))
844     {
845       sym->aop = aop = newAsmop (AOP_DIR);
846       aop->aopu.aop_dir = sym->rname;
847       aop->size = getSize (sym->type);
848       return aop;
849     }
850
851   /* special case for a function */
852   if (IS_FUNC (sym->type) && !(sym->isitmp))
853     {
854       sym->aop = aop = newAsmop (AOP_IMMD);
855       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
856       aop->size = FPTRSIZE;
857       return aop;
858     }
859
860   /* only remaining is far space */
861   /* in which case DPTR gets the address */
862   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
863   if (useDP2)
864     {
865       genSetDPTR (1);
866       _flushLazyDPS ();
867       emitcode ("mov", "dptr,#%s", sym->rname);
868       genSetDPTR (0);
869     }
870   else
871     {
872       emitcode ("mov", "dptr,#%s", sym->rname);
873     }
874   aop->size = getSize (sym->type);
875
876   /* if it is in code space */
877   if (IN_CODESPACE (space))
878     aop->code = 1;
879
880   return aop;
881 }
882
883 /*-----------------------------------------------------------------*/
884 /* aopForRemat - rematerialzes an object                           */
885 /*-----------------------------------------------------------------*/
886 static asmop *
887 aopForRemat (symbol * sym)
888 {
889   iCode *ic = sym->rematiCode;
890   asmop *aop = newAsmop (AOP_IMMD);
891   int ptr_type = 0;
892   int val = 0;
893
894   for (;;)
895     {
896       if (ic->op == '+')
897         val += (int) operandLitValue (IC_RIGHT (ic));
898       else if (ic->op == '-')
899         val -= (int) operandLitValue (IC_RIGHT (ic));
900       else if (IS_CAST_ICODE(ic)) {
901               sym_link *from_type = operandType(IC_RIGHT(ic));
902               aop->aopu.aop_immd.from_cast_remat = 1;
903               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
904               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
905               continue;
906       } else break;
907
908       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
909     }
910
911   if (val)
912   {
913       SNPRINTF (buffer, sizeof(buffer),
914                 "(%s %c 0x%06x)",
915                 OP_SYMBOL (IC_LEFT (ic))->rname,
916                 val >= 0 ? '+' : '-',
917                 abs (val) & 0xffffff);
918   }
919   else
920   {
921       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
922       {
923           SNPRINTF(buffer, sizeof(buffer),
924                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
925       }
926       else
927       {
928           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
929       }
930   }
931
932   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
933   /* set immd2 field if required */
934   if (aop->aopu.aop_immd.from_cast_remat)
935   {
936       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
937       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
938   }
939
940   return aop;
941 }
942
943 /*-----------------------------------------------------------------*/
944 /* aopHasRegs - returns true if aop has regs between from-to       */
945 /*-----------------------------------------------------------------*/
946 static int aopHasRegs(asmop *aop, int from, int to)
947 {
948     int size =0;
949
950     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
951
952     for (; size < aop->size ; size++) {
953         int reg;
954         for (reg = from ; reg <= to ; reg++)
955             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
956     }
957     return 0;
958 }
959
960 /*-----------------------------------------------------------------*/
961 /* regsInCommon - two operands have some registers in common       */
962 /*-----------------------------------------------------------------*/
963 static bool
964 regsInCommon (operand * op1, operand * op2)
965 {
966   symbol *sym1, *sym2;
967   int i;
968
969   /* if they have registers in common */
970   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
971     return FALSE;
972
973   sym1 = OP_SYMBOL (op1);
974   sym2 = OP_SYMBOL (op2);
975
976   if (sym1->nRegs == 0 || sym2->nRegs == 0)
977     return FALSE;
978
979   for (i = 0; i < sym1->nRegs; i++)
980     {
981       int j;
982       if (!sym1->regs[i])
983         continue;
984
985       for (j = 0; j < sym2->nRegs; j++)
986         {
987           if (!sym2->regs[j])
988             continue;
989
990           if (sym2->regs[j] == sym1->regs[i])
991             return TRUE;
992         }
993     }
994
995   return FALSE;
996 }
997
998 /*-----------------------------------------------------------------*/
999 /* operandsEqu - equivalent                                        */
1000 /*-----------------------------------------------------------------*/
1001 static bool
1002 operandsEqu (operand * op1, operand * op2)
1003 {
1004   symbol *sym1, *sym2;
1005
1006   /* if they're not symbols */
1007   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1008     return FALSE;
1009
1010   sym1 = OP_SYMBOL (op1);
1011   sym2 = OP_SYMBOL (op2);
1012
1013   /* if both are itemps & one is spilt
1014      and the other is not then false */
1015   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1016       sym1->isspilt != sym2->isspilt)
1017     return FALSE;
1018
1019   /* if they are the same */
1020   if (sym1 == sym2)
1021     return TRUE;
1022
1023   /* if they have the same rname */
1024   if (sym1->rname[0] && sym2->rname[0] &&
1025       strcmp (sym1->rname, sym2->rname) == 0 &&
1026       !(IS_PARM (op2) && IS_ITEMP (op1)))
1027     return TRUE;
1028
1029   /* if left is a tmp & right is not */
1030   if (IS_ITEMP (op1) &&
1031       !IS_ITEMP (op2) &&
1032       sym1->isspilt &&
1033       (sym1->usl.spillLoc == sym2))
1034     return TRUE;
1035
1036   if (IS_ITEMP (op2) &&
1037       !IS_ITEMP (op1) &&
1038       sym2->isspilt &&
1039       sym1->level > 0 &&
1040       (sym2->usl.spillLoc == sym1))
1041     return TRUE;
1042
1043   /* are they spilt to the same location */
1044   if (IS_ITEMP (op2) &&
1045       IS_ITEMP (op1) &&
1046       sym2->isspilt &&
1047       sym1->isspilt &&
1048       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1049     return TRUE;
1050
1051   return FALSE;
1052 }
1053
1054 /*-----------------------------------------------------------------*/
1055 /* sameRegs - two asmops have the same registers                   */
1056 /*-----------------------------------------------------------------*/
1057 static bool
1058 sameRegs (asmop * aop1, asmop * aop2)
1059 {
1060   int i;
1061
1062   if (aop1 == aop2)
1063     {
1064       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1065         {
1066           return FALSE;
1067         }
1068       return TRUE;
1069     }
1070
1071   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1072     return FALSE;
1073
1074   if (aop1->type != aop2->type)
1075     return FALSE;
1076
1077   if (aop1->size != aop2->size)
1078     return FALSE;
1079
1080   for (i = 0; i < aop1->size; i++)
1081     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1082       return FALSE;
1083
1084   return TRUE;
1085 }
1086
1087 /*-----------------------------------------------------------------*/
1088 /* aopOp - allocates an asmop for an operand  :                    */
1089 /*-----------------------------------------------------------------*/
1090 static void
1091 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1092 {
1093   asmop *aop;
1094   symbol *sym;
1095   int i;
1096
1097   if (!op)
1098     return;
1099
1100   /* if this a literal */
1101   if (IS_OP_LITERAL (op))
1102     {
1103       op->aop = aop = newAsmop (AOP_LIT);
1104       aop->aopu.aop_lit = op->operand.valOperand;
1105       aop->size = getSize (operandType (op));
1106       return;
1107     }
1108
1109   /* if already has a asmop then continue */
1110   if (op->aop)
1111     {
1112       if ((op->aop->type == AOP_DPTR && useDP2)
1113           || (op->aop->type == AOP_DPTR2 && !useDP2))
1114         op->aop = NULL;
1115       else
1116         {
1117           op->aop->allocated++;
1118           return;
1119         }
1120     }
1121
1122   /* if the underlying symbol has a aop */
1123   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1124     {
1125       op->aop = OP_SYMBOL (op)->aop;
1126       if ((op->aop->type == AOP_DPTR && useDP2)
1127           || (op->aop->type == AOP_DPTR2 && !useDP2))
1128         op->aop = NULL;
1129       else
1130         {
1131           op->aop->allocated++;
1132           return;
1133         }
1134     }
1135
1136   /* if this is a true symbol */
1137   if (IS_TRUE_SYMOP (op))
1138     {
1139       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1140       return;
1141     }
1142
1143   /* this is a temporary : this has
1144      only five choices :
1145      a) register
1146      b) spillocation
1147      c) rematerialize
1148      d) conditional
1149      e) can be a return use only */
1150
1151   sym = OP_SYMBOL (op);
1152
1153   /* if the type is a conditional */
1154   if (sym->regType == REG_CND)
1155     {
1156       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1157       aop->size = 0;
1158       return;
1159     }
1160
1161   /* if it is spilt then two situations
1162      a) is rematerialize
1163      b) has a spill location */
1164   if (sym->isspilt || sym->nRegs == 0)
1165     {
1166
1167       /* rematerialize it NOW */
1168       if (sym->remat)
1169         {
1170           sym->aop = op->aop = aop =
1171             aopForRemat (sym);
1172           aop->size = getSize (sym->type);
1173           return;
1174         }
1175
1176       if (sym->accuse)
1177         {
1178           int i;
1179           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1180           aop->size = getSize (sym->type);
1181           for (i = 0; i < 2; i++)
1182             aop->aopu.aop_str[i] = accUse[i];
1183           return;
1184         }
1185
1186       if (sym->ruonly)
1187         {
1188           unsigned i;
1189
1190           if (useDP2)
1191             {
1192               /* a AOP_STR uses DPTR, but DPTR is already in use;
1193                * we're just hosed.
1194                */
1195                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1196             }
1197
1198           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1199           aop->size = getSize (sym->type);
1200           for (i = 0; i < fReturnSizeDS390; i++)
1201             aop->aopu.aop_str[i] = fReturn[i];
1202           return;
1203         }
1204
1205       if (sym->dptr) { /* has been allocated to a DPTRn */
1206           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1207           aop->size = getSize (sym->type);
1208           aop->aopu.dptr = sym->dptr;
1209           return ;
1210       }
1211
1212       if (sym->usl.spillLoc)
1213         {
1214           asmop *oldAsmOp = NULL;
1215
1216           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1217             {
1218               /* force a new aop if sizes differ */
1219               oldAsmOp = sym->usl.spillLoc->aop;
1220               sym->usl.spillLoc->aop = NULL;
1221             }
1222           sym->aop = op->aop = aop =
1223                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1224           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1225             {
1226               /* Don't reuse the new aop, go with the last one */
1227               sym->usl.spillLoc->aop = oldAsmOp;
1228             }
1229           aop->size = getSize (sym->type);
1230           return;
1231         }
1232
1233       /* else must be a dummy iTemp */
1234       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1235       aop->size = getSize (sym->type);
1236       return;
1237     }
1238
1239   /* if the type is a bit register */
1240   if (sym->regType == REG_BIT)
1241     {
1242       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1243       aop->size = sym->nRegs;//1???
1244       aop->aopu.aop_reg[0] = sym->regs[0];
1245       aop->aopu.aop_dir = sym->regs[0]->name;
1246       return;
1247     }
1248
1249   /* must be in a register */
1250   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1251   aop->size = sym->nRegs;
1252   for (i = 0; i < sym->nRegs; i++)
1253     aop->aopu.aop_reg[i] = sym->regs[i];
1254 }
1255
1256 /*-----------------------------------------------------------------*/
1257 /* freeAsmop - free up the asmop given to an operand               */
1258 /*----------------------------------------------------------------*/
1259 static void
1260 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1261 {
1262   asmop *aop;
1263
1264   if (!op)
1265     aop = aaop;
1266   else
1267     aop = op->aop;
1268
1269   if (!aop)
1270     return;
1271
1272   aop->allocated--;
1273
1274   if (aop->allocated)
1275     goto dealloc;
1276
1277   /* depending on the asmop type only three cases need work
1278      AOP_R0, AOP_R1 & AOP_STK */
1279   switch (aop->type)
1280     {
1281     case AOP_R0:
1282       if (_G.r0Pushed)
1283         {
1284           if (pop)
1285             {
1286               emitcode ("pop", "ar0");
1287               _G.r0Pushed--;
1288             }
1289         }
1290       bitVectUnSetBit (ic->rUsed, R0_IDX);
1291       break;
1292
1293     case AOP_R1:
1294       if (_G.r1Pushed)
1295         {
1296           if (pop)
1297             {
1298               emitcode ("pop", "ar1");
1299               _G.r1Pushed--;
1300             }
1301         }
1302       bitVectUnSetBit (ic->rUsed, R1_IDX);
1303       break;
1304
1305     case AOP_STK:
1306       {
1307         int sz = aop->size;
1308         int stk = aop->aopu.aop_stk + aop->size;
1309         bitVectUnSetBit (ic->rUsed, R0_IDX);
1310         bitVectUnSetBit (ic->rUsed, R1_IDX);
1311
1312         getFreePtr (ic, &aop, FALSE);
1313
1314         if (options.stack10bit)
1315           {
1316             /* I'm not sure what to do here yet... */
1317             /* #STUB */
1318             fprintf (stderr,
1319                      "*** Warning: probably generating bad code for "
1320                      "10 bit stack mode.\n");
1321           }
1322
1323         if (stk)
1324           {
1325             emitcode ("mov", "a,_bp");
1326             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1327             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1328           }
1329         else
1330           {
1331             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1332           }
1333
1334         while (sz--)
1335           {
1336             emitcode ("pop", "acc");
1337             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1338             if (!sz)
1339               break;
1340             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1341           }
1342         op->aop = aop;
1343         freeAsmop (op, NULL, ic, TRUE);
1344         if (_G.r1Pushed)
1345           {
1346             emitcode ("pop", "ar1");
1347             _G.r1Pushed--;
1348           }
1349         if (_G.r0Pushed)
1350           {
1351             emitcode ("pop", "ar0");
1352             _G.r0Pushed--;
1353           }
1354       }
1355     case AOP_DPTR2:
1356         if (_G.dptr1InUse) {
1357             emitcode ("pop","dpx1");
1358             emitcode ("pop","dph1");
1359             emitcode ("pop","dpl1");
1360         }
1361         break;
1362     case AOP_DPTR:
1363         if (_G.dptrInUse) {
1364             emitcode ("pop","dpx");
1365             emitcode ("pop","dph");
1366             emitcode ("pop","dpl");
1367         }
1368         break;
1369     }
1370
1371 dealloc:
1372   /* all other cases just dealloc */
1373   if (op)
1374     {
1375       op->aop = NULL;
1376       if (IS_SYMOP (op))
1377         {
1378           OP_SYMBOL (op)->aop = NULL;
1379           /* if the symbol has a spill */
1380           if (SPIL_LOC (op))
1381             SPIL_LOC (op)->aop = NULL;
1382         }
1383     }
1384 }
1385
1386 #define DEFAULT_ACC_WARNING 0
1387 static int saveAccWarn = DEFAULT_ACC_WARNING;
1388
1389
1390 /*-----------------------------------------------------------------*/
1391 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1392 /*                 clobber the accumulator                         */
1393 /*-----------------------------------------------------------------*/
1394 static bool
1395 aopGetUsesAcc (operand * oper, int offset)
1396 {
1397   asmop * aop = AOP (oper);
1398
1399   if (offset > (aop->size - 1))
1400     return FALSE;
1401
1402   switch (aop->type)
1403     {
1404
1405     case AOP_R0:
1406     case AOP_R1:
1407       if (aop->paged)
1408         return TRUE;
1409       return FALSE;
1410     case AOP_DPTR:
1411       return TRUE;
1412     case AOP_IMMD:
1413       return FALSE;
1414     case AOP_DIR:
1415       return FALSE;
1416     case AOP_REG:
1417       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1418       return FALSE;
1419     case AOP_CRY:
1420       return TRUE;
1421     case AOP_ACC:
1422       if (offset)
1423         return FALSE;
1424       return TRUE;
1425     case AOP_LIT:
1426       return FALSE;
1427     case AOP_STR:
1428       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1429         return TRUE;
1430       return FALSE;
1431     case AOP_DUMMY:
1432       return FALSE;
1433     default:
1434       /* Error case --- will have been caught already */
1435       wassert(0);
1436       return FALSE;
1437     }
1438 }
1439
1440 /*-------------------------------------------------------------------*/
1441 /* aopGet - for fetching value of the aop                            */
1442 /*                                                                   */
1443 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1444 /* in the accumulator. Set it to the name of a free register         */
1445 /* if acc must be preserved; the register will be used to preserve   */
1446 /* acc temporarily and to return the result byte.                    */
1447 /*-------------------------------------------------------------------*/
1448 static char *
1449 aopGet (operand * oper,
1450         int   offset,
1451         bool  bit16,
1452         bool  dname,
1453         char  *saveAcc)
1454 {
1455   asmop * aop = AOP (oper);
1456
1457   /* offset is greater than
1458      size then zero */
1459   if (offset > (aop->size - 1) &&
1460       aop->type != AOP_LIT)
1461     return zero;
1462
1463   /* depending on type */
1464   switch (aop->type)
1465     {
1466     case AOP_DUMMY:
1467       return zero;
1468
1469     case AOP_R0:
1470     case AOP_R1:
1471       /* if we need to increment it */
1472       while (offset > aop->coff)
1473         {
1474           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1475           aop->coff++;
1476         }
1477
1478       while (offset < aop->coff)
1479         {
1480           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1481           aop->coff--;
1482         }
1483
1484       aop->coff = offset;
1485       if (aop->paged)
1486         {
1487           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1488           return (dname ? "acc" : "a");
1489         }
1490       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1491       return Safe_strdup(buffer);
1492
1493     case AOP_DPTRn:
1494         assert(offset <= 3);
1495         return dptrn[aop->aopu.dptr][offset];
1496
1497     case AOP_DPTR:
1498     case AOP_DPTR2:
1499
1500       if (aop->type == AOP_DPTR2)
1501         {
1502           genSetDPTR (1);
1503         }
1504
1505       if (saveAcc)
1506         {
1507             TR_AP("#1");
1508 //          if (aop->type != AOP_DPTR2)
1509 //          {
1510 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1511 //              emitcode(";", "spanky: saveAcc for DPTR");
1512 //          }
1513
1514             emitcode ("xch", "a, %s", saveAcc);
1515         }
1516
1517       _flushLazyDPS ();
1518
1519       while (offset > aop->coff)
1520         {
1521           emitcode ("inc", "dptr");
1522           aop->coff++;
1523         }
1524
1525       while (offset < aop->coff)
1526         {
1527           emitcode ("lcall", "__decdptr");
1528           aop->coff--;
1529         }
1530
1531       aop->coff = offset;
1532       if (aop->code)
1533         {
1534           emitcode ("clr", "a");
1535           emitcode ("movc", "a,@a+dptr");
1536         }
1537       else
1538         {
1539           emitcode ("movx", "a,@dptr");
1540         }
1541
1542       if (aop->type == AOP_DPTR2)
1543         {
1544           genSetDPTR (0);
1545         }
1546
1547       if (saveAcc)
1548         {
1549           TR_AP("#2");
1550           emitcode ("xch", "a, %s", saveAcc);
1551 //        if (strcmp(saveAcc, "_ap"))
1552 //          {
1553 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1554 //          }
1555
1556           return saveAcc;
1557         }
1558       return (dname ? "acc" : "a");
1559
1560     case AOP_IMMD:
1561       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1562         {
1563           SNPRINTF(buffer, sizeof(buffer),
1564                    "%s",aop->aopu.aop_immd.aop_immd2);
1565         }
1566       else if (bit16)
1567         {
1568           SNPRINTF(buffer, sizeof(buffer),
1569                    "#%s", aop->aopu.aop_immd.aop_immd1);
1570         }
1571       else if (offset)
1572         {
1573           switch (offset) {
1574           case 1:
1575               tsprintf(buffer, sizeof(buffer),
1576                        "#!his",aop->aopu.aop_immd.aop_immd1);
1577               break;
1578           case 2:
1579               tsprintf(buffer, sizeof(buffer),
1580                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1581               break;
1582           case 3:
1583               tsprintf(buffer, sizeof(buffer),
1584                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1585               break;
1586           default: /* should not need this (just in case) */
1587               SNPRINTF (buffer, sizeof(buffer),
1588                         "#(%s >> %d)",
1589                        aop->aopu.aop_immd.aop_immd1,
1590                        offset * 8);
1591           }
1592         }
1593       else
1594         {
1595           SNPRINTF (buffer, sizeof(buffer),
1596                     "#%s",
1597                     aop->aopu.aop_immd.aop_immd1);
1598         }
1599       return Safe_strdup(buffer);
1600
1601     case AOP_DIR:
1602       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "(%s >> %d)",
1606                     aop->aopu.aop_dir, offset * 8);
1607         }
1608       else if (offset)
1609         {
1610           SNPRINTF (buffer, sizeof(buffer),
1611                     "(%s + %d)",
1612                    aop->aopu.aop_dir,
1613                    offset);
1614         }
1615       else
1616         {
1617           SNPRINTF (buffer, sizeof(buffer),
1618                     "%s",
1619                     aop->aopu.aop_dir);
1620         }
1621
1622       return Safe_strdup(buffer);
1623
1624     case AOP_REG:
1625       if (dname)
1626         return aop->aopu.aop_reg[offset]->dname;
1627       else
1628         return aop->aopu.aop_reg[offset]->name;
1629
1630     case AOP_CRY:
1631       emitcode ("clr", "a");
1632       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1633       emitcode ("rlc", "a");
1634       return (dname ? "acc" : "a");
1635
1636     case AOP_ACC:
1637       if (!offset && dname)
1638         return "acc";
1639       return aop->aopu.aop_str[offset];
1640
1641     case AOP_LIT:
1642       return aopLiteral (aop->aopu.aop_lit, offset);
1643
1644     case AOP_STR:
1645       aop->coff = offset;
1646       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1647           dname)
1648         return "acc";
1649
1650       return aop->aopu.aop_str[offset];
1651
1652     }
1653
1654   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1655           "aopget got unsupported aop->type");
1656   exit (1);
1657
1658   return NULL;  // not reached, but makes compiler happy.
1659 }
1660
1661 /*-----------------------------------------------------------------*/
1662 /* aopPut - puts a string for a aop and indicates if acc is in use */
1663 /*-----------------------------------------------------------------*/
1664 static bool
1665 aopPut (operand * result, const char *s, int offset)
1666 {
1667   bool bvolatile = isOperandVolatile (result, FALSE);
1668   bool accuse = FALSE;
1669   asmop * aop = AOP (result);
1670
1671   if (aop->size && offset > (aop->size - 1))
1672     {
1673       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1674               "aopPut got offset > aop->size");
1675       exit (1);
1676     }
1677
1678   /* will assign value to value */
1679   /* depending on where it is ofcourse */
1680   switch (aop->type)
1681     {
1682     case AOP_DUMMY:
1683       MOVA (s);         /* read s in case it was volatile */
1684       accuse = TRUE;
1685       break;
1686
1687     case AOP_DIR:
1688       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1689         {
1690           SNPRINTF (buffer, sizeof(buffer),
1691                     "(%s >> %d)",
1692                     aop->aopu.aop_dir, offset * 8);
1693         }
1694       else if (offset)
1695         {
1696           SNPRINTF (buffer, sizeof(buffer),
1697                     "(%s + %d)",
1698                     aop->aopu.aop_dir, offset);
1699         }
1700       else
1701         {
1702           SNPRINTF (buffer, sizeof(buffer),
1703                     "%s",
1704                     aop->aopu.aop_dir);
1705         }
1706
1707       if (strcmp (buffer, s) || bvolatile)
1708         {
1709           emitcode ("mov", "%s,%s", buffer, s);
1710         }
1711       if (!strcmp (buffer, "acc"))
1712         {
1713           accuse = TRUE;
1714         }
1715       break;
1716
1717     case AOP_REG:
1718       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1719           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1720         {
1721           if (*s == '@' ||
1722               strcmp (s, "r0") == 0 ||
1723               strcmp (s, "r1") == 0 ||
1724               strcmp (s, "r2") == 0 ||
1725               strcmp (s, "r3") == 0 ||
1726               strcmp (s, "r4") == 0 ||
1727               strcmp (s, "r5") == 0 ||
1728               strcmp (s, "r6") == 0 ||
1729               strcmp (s, "r7") == 0)
1730             {
1731               emitcode ("mov", "%s,%s",
1732                         aop->aopu.aop_reg[offset]->dname, s);
1733             }
1734             else
1735             {
1736               emitcode ("mov", "%s,%s",
1737                         aop->aopu.aop_reg[offset]->name, s);
1738             }
1739         }
1740       break;
1741
1742     case AOP_DPTRn:
1743         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1744         break;
1745
1746     case AOP_DPTR:
1747     case AOP_DPTR2:
1748
1749       if (aop->type == AOP_DPTR2)
1750         {
1751           genSetDPTR (1);
1752         }
1753       _flushLazyDPS ();
1754
1755       if (aop->code)
1756         {
1757           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1758                   "aopPut writing to code space");
1759           exit (1);
1760         }
1761
1762       while (offset > aop->coff)
1763         {
1764           aop->coff++;
1765           emitcode ("inc", "dptr");
1766         }
1767
1768       while (offset < aop->coff)
1769         {
1770           aop->coff--;
1771           emitcode ("lcall", "__decdptr");
1772         }
1773
1774       aop->coff = offset;
1775
1776       /* if not in accumulator */
1777       MOVA (s);
1778
1779       emitcode ("movx", "@dptr,a");
1780
1781       if (aop->type == AOP_DPTR2)
1782         {
1783           genSetDPTR (0);
1784         }
1785       break;
1786
1787     case AOP_R0:
1788     case AOP_R1:
1789       while (offset > aop->coff)
1790         {
1791           aop->coff++;
1792           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1793         }
1794       while (offset < aop->coff)
1795         {
1796           aop->coff--;
1797           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1798         }
1799       aop->coff = offset;
1800
1801       if (aop->paged)
1802         {
1803           MOVA (s);
1804           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1805         }
1806       else if (*s == '@')
1807         {
1808           MOVA (s);
1809           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1810         }
1811       else if (strcmp (s, "r0") == 0 ||
1812                strcmp (s, "r1") == 0 ||
1813                strcmp (s, "r2") == 0 ||
1814                strcmp (s, "r3") == 0 ||
1815                strcmp (s, "r4") == 0 ||
1816                strcmp (s, "r5") == 0 ||
1817                strcmp (s, "r6") == 0 ||
1818                strcmp (s, "r7") == 0)
1819         {
1820           char buffer[10];
1821           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1822           emitcode ("mov", "@%s,%s",
1823                     aop->aopu.aop_ptr->name, buffer);
1824         }
1825         else
1826         {
1827             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1828         }
1829       break;
1830
1831     case AOP_STK:
1832       if (strcmp (s, "a") == 0)
1833         emitcode ("push", "acc");
1834       else
1835         if (*s=='@') {
1836           MOVA(s);
1837           emitcode ("push", "acc");
1838         } else {
1839           emitcode ("push", s);
1840         }
1841
1842       break;
1843
1844     case AOP_CRY:
1845       /* if not bit variable */
1846       if (!aop->aopu.aop_dir)
1847         {
1848           /* inefficient: move carry into A and use jz/jnz */
1849           emitcode ("clr", "a");
1850           emitcode ("rlc", "a");
1851           accuse = TRUE;
1852         }
1853       else
1854         {
1855           if (s == zero)
1856             emitcode ("clr", "%s", aop->aopu.aop_dir);
1857           else if (s == one)
1858             emitcode ("setb", "%s", aop->aopu.aop_dir);
1859           else if (!strcmp (s, "c"))
1860             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1861           else if (strcmp (s, aop->aopu.aop_dir))
1862             {
1863               MOVA (s);
1864               /* set C, if a >= 1 */
1865               emitcode ("add", "a,#!constbyte",0xff);
1866               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1867             }
1868         }
1869       break;
1870
1871     case AOP_STR:
1872       aop->coff = offset;
1873       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1874         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1875       break;
1876
1877     case AOP_ACC:
1878       accuse = TRUE;
1879       aop->coff = offset;
1880       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1881         break;
1882
1883       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1884         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1885       break;
1886
1887     default:
1888       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1889               "aopPut got unsupported aop->type");
1890       exit (1);
1891     }
1892
1893     return accuse;
1894 }
1895
1896
1897 /*--------------------------------------------------------------------*/
1898 /* reAdjustPreg - points a register back to where it should (coff==0) */
1899 /*--------------------------------------------------------------------*/
1900 static void
1901 reAdjustPreg (asmop * aop)
1902 {
1903   if ((aop->coff==0) || (aop->size <= 1))
1904     return;
1905
1906   switch (aop->type)
1907     {
1908     case AOP_R0:
1909     case AOP_R1:
1910       while (aop->coff--)
1911         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1912       break;
1913     case AOP_DPTR:
1914     case AOP_DPTR2:
1915       if (aop->type == AOP_DPTR2)
1916         {
1917           genSetDPTR (1);
1918           _flushLazyDPS ();
1919         }
1920       while (aop->coff--)
1921         {
1922           emitcode ("lcall", "__decdptr");
1923         }
1924
1925       if (aop->type == AOP_DPTR2)
1926         {
1927           genSetDPTR (0);
1928         }
1929       break;
1930     }
1931   aop->coff = 0;
1932 }
1933
1934 /*-----------------------------------------------------------------*/
1935 /* opIsGptr: returns non-zero if the passed operand is       */
1936 /* a generic pointer type.             */
1937 /*-----------------------------------------------------------------*/
1938 static int
1939 opIsGptr (operand * op)
1940 {
1941   sym_link *type = operandType (op);
1942
1943   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1944     {
1945       return 1;
1946     }
1947   return 0;
1948 }
1949
1950 /*-----------------------------------------------------------------*/
1951 /* getDataSize - get the operand data size                         */
1952 /*-----------------------------------------------------------------*/
1953 static int
1954 getDataSize (operand * op)
1955 {
1956   int size;
1957   size = AOP_SIZE (op);
1958   if (size == GPTRSIZE)
1959     {
1960       sym_link *type = operandType (op);
1961       if (IS_GENPTR (type))
1962         {
1963           /* generic pointer; arithmetic operations
1964            * should ignore the high byte (pointer type).
1965            */
1966           size--;
1967         }
1968     }
1969   return size;
1970 }
1971
1972 /*-----------------------------------------------------------------*/
1973 /* outAcc - output Acc                                             */
1974 /*-----------------------------------------------------------------*/
1975 static void
1976 outAcc (operand * result)
1977 {
1978   int size, offset;
1979   size = getDataSize (result);
1980   if (size)
1981     {
1982       aopPut (result, "a", 0);
1983       size--;
1984       offset = 1;
1985       /* unsigned or positive */
1986       while (size--)
1987         {
1988           aopPut (result, zero, offset++);
1989         }
1990     }
1991 }
1992
1993 /*-----------------------------------------------------------------*/
1994 /* outBitC - output a bit C                                        */
1995 /*-----------------------------------------------------------------*/
1996 static void
1997 outBitC (operand * result)
1998 {
1999   /* if the result is bit */
2000   if (AOP_TYPE (result) == AOP_CRY)
2001     {
2002       aopPut (result, "c", 0);
2003     }
2004   else
2005     {
2006       emitcode ("clr", "a");
2007       emitcode ("rlc", "a");
2008       outAcc (result);
2009     }
2010 }
2011
2012 /*-----------------------------------------------------------------*/
2013 /* toBoolean - emit code for orl a,operator(sizeop)                */
2014 /*-----------------------------------------------------------------*/
2015 static void
2016 toBoolean (operand * oper)
2017 {
2018   int  size = AOP_SIZE (oper) - 1;
2019   int  offset = 1;
2020   bool pushedB;
2021
2022   /* The generic part of a generic pointer should
2023    * not participate in it's truth value.
2024    *
2025    * i.e. 0x10000000 is zero.
2026    */
2027   if (opIsGptr (oper))
2028     {
2029       D (emitcode (";", "toBoolean: generic ptr special case."));
2030       size--;
2031     }
2032
2033   _startLazyDPSEvaluation ();
2034   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2035   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2036     {
2037       pushedB = pushB ();
2038       emitcode("mov", "b,a");
2039       while (--size)
2040         {
2041           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2042           emitcode ("orl", "b,a");
2043         }
2044       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2045       emitcode ("orl", "a,b");
2046       popB (pushedB);
2047     }
2048   else
2049     {
2050       while (size--)
2051         {
2052           emitcode ("orl", "a,%s",
2053                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2054         }
2055     }
2056   _endLazyDPSEvaluation ();
2057 }
2058
2059
2060 /*-----------------------------------------------------------------*/
2061 /* genNot - generate code for ! operation                          */
2062 /*-----------------------------------------------------------------*/
2063 static void
2064 genNot (iCode * ic)
2065 {
2066   symbol *tlbl;
2067
2068   D (emitcode (";", "genNot"));
2069
2070   /* assign asmOps to operand & result */
2071   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2072   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2073
2074   /* if in bit space then a special case */
2075   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2076     {
2077       /* if left==result then cpl bit */
2078       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2079         {
2080           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2081         }
2082       else
2083         {
2084           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2085           emitcode ("cpl", "c");
2086           outBitC (IC_RESULT (ic));
2087         }
2088       goto release;
2089     }
2090
2091   toBoolean (IC_LEFT (ic));
2092
2093   /* set C, if a == 0 */
2094   tlbl = newiTempLabel (NULL);
2095   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2096   emitLabel (tlbl);
2097   outBitC (IC_RESULT (ic));
2098
2099 release:
2100   /* release the aops */
2101   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2102   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2103 }
2104
2105
2106 /*-----------------------------------------------------------------*/
2107 /* genCpl - generate code for complement                           */
2108 /*-----------------------------------------------------------------*/
2109 static void
2110 genCpl (iCode * ic)
2111 {
2112   int offset = 0;
2113   int size;
2114   symbol *tlbl;
2115   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2116
2117   D(emitcode (";", "genCpl"));
2118
2119   /* assign asmOps to operand & result */
2120   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2121   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2122
2123   /* special case if in bit space */
2124   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2125     {
2126       char *l;
2127
2128       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2129           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2130         {
2131           /* promotion rules are responsible for this strange result:
2132              bit -> int -> ~int -> bit
2133              uchar -> int -> ~int -> bit
2134           */
2135           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2136           goto release;
2137         }
2138
2139       tlbl=newiTempLabel(NULL);
2140       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2141       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2142           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2143           IS_AOP_PREG (IC_LEFT (ic)))
2144         {
2145           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2146         }
2147       else
2148         {
2149           MOVA (l);
2150           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2151         }
2152       emitLabel (tlbl);
2153       outBitC (IC_RESULT(ic));
2154       goto release;
2155     }
2156
2157   size = AOP_SIZE (IC_RESULT (ic));
2158   _startLazyDPSEvaluation ();
2159   while (size--)
2160     {
2161       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2162       MOVA (l);
2163       emitcode ("cpl", "a");
2164       aopPut (IC_RESULT (ic), "a", offset++);
2165     }
2166   _endLazyDPSEvaluation ();
2167
2168
2169 release:
2170   /* release the aops */
2171   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2172   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2173 }
2174
2175 /*-----------------------------------------------------------------*/
2176 /* genUminusFloat - unary minus for floating points                */
2177 /*-----------------------------------------------------------------*/
2178 static void
2179 genUminusFloat (operand * op, operand * result)
2180 {
2181   int size, offset = 0;
2182   char *l;
2183
2184   D (emitcode (";", "genUminusFloat"));
2185
2186   /* for this we just copy and then flip the bit */
2187
2188   _startLazyDPSEvaluation ();
2189   size = AOP_SIZE (op) - 1;
2190
2191   while (size--)
2192     {
2193       aopPut (result,
2194               aopGet (op, offset, FALSE, FALSE, NULL),
2195               offset);
2196       offset++;
2197     }
2198
2199   l = aopGet (op, offset, FALSE, FALSE, NULL);
2200   MOVA (l);
2201
2202   emitcode ("cpl", "acc.7");
2203   aopPut (result, "a", offset);
2204   _endLazyDPSEvaluation ();
2205 }
2206
2207 /*-----------------------------------------------------------------*/
2208 /* genUminus - unary minus code generation                         */
2209 /*-----------------------------------------------------------------*/
2210 static void
2211 genUminus (iCode * ic)
2212 {
2213   int offset, size;
2214   sym_link *optype;
2215
2216   D (emitcode (";", "genUminus"));
2217
2218   /* assign asmops */
2219   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2220   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2221
2222   /* if both in bit space then special
2223      case */
2224   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2225       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2226     {
2227
2228       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2229       emitcode ("cpl", "c");
2230       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2231       goto release;
2232     }
2233
2234   optype = operandType (IC_LEFT (ic));
2235
2236   /* if float then do float stuff */
2237   if (IS_FLOAT (optype))
2238     {
2239       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2240       goto release;
2241     }
2242
2243   /* otherwise subtract from zero */
2244   size = AOP_SIZE (IC_LEFT (ic));
2245   offset = 0;
2246   _startLazyDPSEvaluation ();
2247   while (size--)
2248     {
2249       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2250       if (!strcmp (l, "a"))
2251         {
2252           if (offset == 0)
2253             SETC;
2254           emitcode ("cpl", "a");
2255           emitcode ("addc", "a,#0");
2256         }
2257       else
2258         {
2259           if (offset == 0)
2260             CLRC;
2261           emitcode ("clr", "a");
2262           emitcode ("subb", "a,%s", l);
2263         }
2264       aopPut (IC_RESULT (ic), "a", offset++);
2265     }
2266   _endLazyDPSEvaluation ();
2267
2268   /* if any remaining bytes in the result */
2269   /* we just need to propagate the sign   */
2270   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2271     {
2272       emitcode ("rlc", "a");
2273       emitcode ("subb", "a,acc");
2274       while (size--)
2275         aopPut (IC_RESULT (ic), "a", offset++);
2276     }
2277
2278 release:
2279   /* release the aops */
2280   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2281   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2282 }
2283
2284 /*-----------------------------------------------------------------*/
2285 /* savermask - saves registers in the mask                         */
2286 /*-----------------------------------------------------------------*/
2287 static void savermask(bitVect *rs_mask)
2288 {
2289   int i;
2290
2291   if (options.useXstack)
2292     {
2293       if (bitVectBitValue (rs_mask, R0_IDX))
2294           emitcode ("mov", "b,r0");
2295       emitcode ("mov", "r0,%s", spname);
2296       for (i = 0; i < ds390_nRegs; i++)
2297         {
2298           if (bitVectBitValue (rs_mask, i))
2299             {
2300               if (i == R0_IDX)
2301                   emitcode ("mov", "a,b");
2302               else
2303                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2304               emitcode ("movx", "@r0,a");
2305               emitcode ("inc", "r0");
2306             }
2307         }
2308       emitcode ("mov", "%s,r0", spname);
2309       if (bitVectBitValue (rs_mask, R0_IDX))
2310           emitcode ("mov", "r0,b");
2311     }
2312   else
2313     {
2314       bool bits_pushed = FALSE;
2315       for (i = 0; i < ds390_nRegs; i++)
2316         {
2317           if (bitVectBitValue (rs_mask, i))
2318             {
2319               bits_pushed = pushReg (i, bits_pushed);
2320             }
2321         }
2322     }
2323 }
2324
2325 /*-----------------------------------------------------------------*/
2326 /* saveRegisters - will look for a call and save the registers     */
2327 /*-----------------------------------------------------------------*/
2328 static void
2329 saveRegisters (iCode * lic)
2330 {
2331   iCode *ic;
2332   bitVect *rsave;
2333
2334   /* look for call */
2335   for (ic = lic; ic; ic = ic->next)
2336     if (ic->op == CALL || ic->op == PCALL)
2337       break;
2338
2339   if (!ic)
2340     {
2341       fprintf (stderr, "found parameter push with no function call\n");
2342       return;
2343     }
2344
2345   /* if the registers have been saved already or don't need to be then
2346      do nothing */
2347   if (ic->regsSaved
2348       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2349     return;
2350
2351   /* special case if DPTR alive across a function call then must save it
2352      even though callee saves */
2353   if (IS_SYMOP(IC_LEFT(ic)) &&
2354       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2355     {
2356       int i;
2357       rsave = newBitVect(ic->rMask->size);
2358       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2359           if (bitVectBitValue(ic->rMask,i))
2360               rsave = bitVectSetBit(rsave,i);
2361       }
2362       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2363     }
2364   else
2365     {
2366       /* save the registers in use at this time but skip the
2367          ones for the result */
2368       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2369                              ds390_rUmaskForOp (IC_RESULT(ic)));
2370     }
2371   ic->regsSaved = 1;
2372   savermask(rsave);
2373 }
2374
2375 /*-----------------------------------------------------------------*/
2376 /* usavermask - restore registers with mask                        */
2377 /*-----------------------------------------------------------------*/
2378 static void unsavermask(bitVect *rs_mask)
2379 {
2380   int i;
2381
2382   if (options.useXstack)
2383     {
2384       emitcode ("mov", "r0,%s", spname);
2385       for (i = ds390_nRegs; i >= 0; i--)
2386         {
2387           if (bitVectBitValue (rs_mask, i))
2388             {
2389               regs * reg = REG_WITH_INDEX (i);
2390               emitcode ("dec", "r0");
2391               emitcode ("movx", "a,@r0");
2392               if (i == R0_IDX)
2393                 {
2394                   emitcode ("push", "acc");
2395                 }
2396               else
2397                 {
2398                   emitcode ("mov", "%s,a", reg->name);
2399                 }
2400             }
2401         }
2402       emitcode ("mov", "%s,r0", spname);
2403       if (bitVectBitValue (rs_mask, R0_IDX))
2404         {
2405           emitcode ("pop", "ar0");
2406         }
2407     }
2408   else
2409     {
2410       bool bits_popped = FALSE;
2411       for (i = ds390_nRegs; i >= 0; i--)
2412         {
2413           if (bitVectBitValue (rs_mask, i))
2414             {
2415               bits_popped = popReg (i, bits_popped);
2416             }
2417         }
2418     }
2419 }
2420
2421 /*-----------------------------------------------------------------*/
2422 /* unsaveRegisters - pop the pushed registers                      */
2423 /*-----------------------------------------------------------------*/
2424 static void
2425 unsaveRegisters (iCode * ic)
2426 {
2427   bitVect *rsave;
2428
2429   if (IS_SYMOP(IC_LEFT (ic)) &&
2430       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2431       int i;
2432       rsave = newBitVect(ic->rMask->size);
2433       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2434           if (bitVectBitValue(ic->rMask,i))
2435               rsave = bitVectSetBit(rsave,i);
2436       }
2437       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2438   } else {
2439     /* restore the registers in use at this time but skip the
2440        ones for the result */
2441     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2442                            ds390_rUmaskForOp (IC_RESULT(ic)));
2443   }
2444   unsavermask(rsave);
2445 }
2446
2447
2448 /*-----------------------------------------------------------------*/
2449 /* pushSide -                */
2450 /*-----------------------------------------------------------------*/
2451 static void
2452 pushSide (operand * oper, int size)
2453 {
2454   int offset = 0;
2455   _startLazyDPSEvaluation ();
2456   while (size--)
2457     {
2458       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2459       if (AOP_TYPE (oper) != AOP_REG &&
2460           AOP_TYPE (oper) != AOP_DIR &&
2461           strcmp (l, "a"))
2462         {
2463           MOVA (l);
2464           emitcode ("push", "acc");
2465         }
2466       else
2467         {
2468           emitcode ("push", "%s", l);
2469         }
2470     }
2471   _endLazyDPSEvaluation ();
2472 }
2473
2474 /*-----------------------------------------------------------------*/
2475 /* assignResultValue - also indicates if acc is in use afterwards  */
2476 /*-----------------------------------------------------------------*/
2477 static bool
2478 assignResultValue (operand * oper, operand * func)
2479 {
2480   int offset = 0;
2481   unsigned size = AOP_SIZE (oper);
2482   bool accuse = FALSE;
2483   bool pushedA = FALSE;
2484
2485   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2486     {
2487       outBitC (oper);
2488       return FALSE;
2489     }
2490
2491   if (size == fReturnSizeDS390)
2492   {
2493       /* I don't think this case can ever happen... */
2494       /* ACC is the last part of this. If writing the result
2495        * uses ACC, we must preserve it.
2496        */
2497       if (AOP_NEEDSACC(oper))
2498       {
2499           emitcode(";", "assignResultValue special case for ACC.");
2500           emitcode("push", "acc");
2501           pushedA = TRUE;
2502           size--;
2503       }
2504   }
2505
2506   _startLazyDPSEvaluation ();
2507   while (size--)
2508     {
2509       accuse |= aopPut (oper, fReturn[offset], offset);
2510       offset++;
2511     }
2512   _endLazyDPSEvaluation ();
2513
2514   if (pushedA)
2515     {
2516         emitcode ("pop", "acc");
2517         accuse |= aopPut (oper, "a", offset);
2518     }
2519   return accuse;
2520 }
2521
2522
2523 /*-----------------------------------------------------------------*/
2524 /* genXpush - pushes onto the external stack                       */
2525 /*-----------------------------------------------------------------*/
2526 static void
2527 genXpush (iCode * ic)
2528 {
2529   asmop *aop = newAsmop (0);
2530   regs *r;
2531   int size, offset = 0;
2532
2533   D (emitcode (";", "genXpush"));
2534
2535   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2536   r = getFreePtr (ic, &aop, FALSE);
2537
2538   size = AOP_SIZE (IC_LEFT (ic));
2539
2540   if (size == 1)
2541     {
2542       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2543       emitcode ("mov", "%s,_spx", r->name);
2544       emitcode ("inc", "_spx"); // allocate space first
2545       emitcode ("movx", "@%s,a", r->name);
2546     }
2547   else
2548     {
2549       // allocate space first
2550       emitcode ("mov", "%s,_spx", r->name);
2551       MOVA (r->name);
2552       emitcode ("add", "a,#%d", size);
2553       emitcode ("mov", "_spx,a");
2554
2555       _startLazyDPSEvaluation ();
2556       while (size--)
2557         {
2558           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2559           emitcode ("movx", "@%s,a", r->name);
2560           emitcode ("inc", "%s", r->name);
2561         }
2562       _endLazyDPSEvaluation ();
2563     }
2564
2565   freeAsmop (NULL, aop, ic, TRUE);
2566   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2567 }
2568
2569 /*-----------------------------------------------------------------*/
2570 /* genIpush - generate code for pushing this gets a little complex  */
2571 /*-----------------------------------------------------------------*/
2572 static void
2573 genIpush (iCode * ic)
2574 {
2575   int size, offset = 0;
2576   char *l;
2577   char *prev = "";
2578
2579   D (emitcode (";", "genIpush"));
2580
2581   /* if this is not a parm push : ie. it is spill push
2582      and spill push is always done on the local stack */
2583   if (!ic->parmPush)
2584     {
2585
2586       /* and the item is spilt then do nothing */
2587       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2588         return;
2589
2590       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2591       size = AOP_SIZE (IC_LEFT (ic));
2592       /* push it on the stack */
2593       _startLazyDPSEvaluation ();
2594       while (size--)
2595         {
2596           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2597           if (*l == '#')
2598             {
2599               MOVA (l);
2600               l = "acc";
2601             }
2602           emitcode ("push", "%s", l);
2603         }
2604       _endLazyDPSEvaluation ();
2605       return;
2606     }
2607
2608   /* this is a parameter push: in this case we call
2609      the routine to find the call and save those
2610      registers that need to be saved */
2611   saveRegisters (ic);
2612
2613   /* if use external stack then call the external
2614      stack pushing routine */
2615   if (options.useXstack)
2616     {
2617       genXpush (ic);
2618       return;
2619     }
2620
2621   /* then do the push */
2622   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2623
2624   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2625   size = AOP_SIZE (IC_LEFT (ic));
2626
2627   _startLazyDPSEvaluation ();
2628   while (size--)
2629     {
2630       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2631       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2632           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2633           strcmp (l, "acc"))
2634         {
2635           if (strcmp (l, prev) || *l == '@')
2636             MOVA (l);
2637           emitcode ("push", "acc");
2638         }
2639       else
2640         {
2641             emitcode ("push", "%s", l);
2642         }
2643       prev = l;
2644     }
2645   _endLazyDPSEvaluation ();
2646
2647   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2648 }
2649
2650 /*-----------------------------------------------------------------*/
2651 /* genIpop - recover the registers: can happen only for spilling   */
2652 /*-----------------------------------------------------------------*/
2653 static void
2654 genIpop (iCode * ic)
2655 {
2656   int size, offset;
2657
2658   D (emitcode (";", "genIpop"));
2659
2660   /* if the temp was not pushed then */
2661   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2662     return;
2663
2664   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2665   size = AOP_SIZE (IC_LEFT (ic));
2666   offset = (size - 1);
2667   _startLazyDPSEvaluation ();
2668   while (size--)
2669     {
2670       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2671                                      FALSE, TRUE, NULL));
2672     }
2673   _endLazyDPSEvaluation ();
2674
2675   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2676 }
2677
2678 /*-----------------------------------------------------------------*/
2679 /* saveRBank - saves an entire register bank on the stack          */
2680 /*-----------------------------------------------------------------*/
2681 static void
2682 saveRBank (int bank, iCode * ic, bool pushPsw)
2683 {
2684   int i;
2685   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2686   asmop *aop = NULL;
2687   regs *r = NULL;
2688
2689   if (options.useXstack)
2690     {
2691       if (!ic)
2692         {
2693           /* Assume r0 is available for use. */
2694           r = REG_WITH_INDEX (R0_IDX);;
2695         }
2696       else
2697         {
2698           aop = newAsmop (0);
2699           r = getFreePtr (ic, &aop, FALSE);
2700         }
2701       // allocate space first
2702       emitcode ("mov", "%s,_spx", r->name);
2703       MOVA (r->name);
2704       emitcode ("add", "a,#%d", count);
2705       emitcode ("mov", "_spx,a");
2706     }
2707
2708   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2709     {
2710       if (options.useXstack)
2711         {
2712           emitcode ("mov", "a,(%s+%d)",
2713                     regs390[i].base, 8 * bank + regs390[i].offset);
2714           emitcode ("movx", "@%s,a", r->name);
2715           if (--count)
2716             emitcode ("inc", "%s", r->name);
2717         }
2718       else
2719         emitcode ("push", "(%s+%d)",
2720                   regs390[i].base, 8 * bank + regs390[i].offset);
2721     }
2722
2723   if (ds390_nBitRegs > 0)
2724     {
2725       if (options.useXstack)
2726         {
2727           emitcode ("mov", "a,bits");
2728           emitcode ("movx", "@%s,a", r->name);
2729           if (--count)
2730             emitcode ("inc", "%s", r->name);
2731         }
2732       else
2733         {
2734           emitcode ("push", "bits");
2735         }
2736       BitBankUsed = 1;
2737     }
2738
2739   if (pushPsw)
2740     {
2741       if (options.useXstack)
2742         {
2743           emitcode ("mov", "a,psw");
2744           emitcode ("movx", "@%s,a", r->name);
2745         }
2746       else
2747       {
2748         emitcode ("push", "psw");
2749       }
2750
2751       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2752     }
2753
2754   if (aop)
2755     {
2756       freeAsmop (NULL, aop, ic, TRUE);
2757     }
2758
2759   if (ic)
2760   {
2761     ic->bankSaved = 1;
2762   }
2763 }
2764
2765 /*-----------------------------------------------------------------*/
2766 /* unsaveRBank - restores the register bank from stack             */
2767 /*-----------------------------------------------------------------*/
2768 static void
2769 unsaveRBank (int bank, iCode * ic, bool popPsw)
2770 {
2771   int i;
2772   asmop *aop = NULL;
2773   regs *r = NULL;
2774
2775   if (options.useXstack)
2776     {
2777       if (!ic)
2778         {
2779           /* Assume r0 is available for use. */
2780           r = REG_WITH_INDEX (R0_IDX);;
2781         }
2782       else
2783         {
2784           aop = newAsmop (0);
2785           r = getFreePtr (ic, &aop, FALSE);
2786         }
2787       emitcode ("mov", "%s,_spx", r->name);
2788     }
2789
2790   if (popPsw)
2791     {
2792       if (options.useXstack)
2793         {
2794           emitcode ("dec", "%s", r->name);
2795           emitcode ("movx", "a,@%s", r->name);
2796           emitcode ("mov", "psw,a");
2797         }
2798       else
2799       {
2800         emitcode ("pop", "psw");
2801       }
2802     }
2803
2804   if (ds390_nBitRegs > 0)
2805     {
2806       if (options.useXstack)
2807         {
2808           emitcode ("dec", "%s", r->name);
2809           emitcode ("movx", "a,@%s", r->name);
2810           emitcode ("mov", "bits,a");
2811         }
2812       else
2813         {
2814           emitcode ("pop", "bits");
2815         }
2816     }
2817
2818   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2819     {
2820       if (options.useXstack)
2821         {
2822           emitcode ("dec", "%s", r->name);
2823           emitcode ("movx", "a,@%s", r->name);
2824           emitcode ("mov", "(%s+%d),a",
2825                     regs390[i].base, 8 * bank + regs390[i].offset);
2826         }
2827       else
2828         {
2829           emitcode ("pop", "(%s+%d)",
2830                     regs390[i].base, 8 * bank + regs390[i].offset);
2831         }
2832     }
2833
2834   if (options.useXstack)
2835     {
2836       emitcode ("mov", "_spx,%s", r->name);
2837     }
2838
2839   if (aop)
2840     {
2841       freeAsmop (NULL, aop, ic, TRUE);
2842     }
2843 }
2844
2845 /*-----------------------------------------------------------------*/
2846 /* genSend - gen code for SEND                                     */
2847 /*-----------------------------------------------------------------*/
2848 static void genSend(set *sendSet)
2849 {
2850   iCode *sic;
2851   int bit_count = 0;
2852   int sendCount = 0 ;
2853   static int rb1_count = 0;
2854
2855   /* first we do all bit parameters */
2856   for (sic = setFirstItem (sendSet); sic;
2857        sic = setNextItem (sendSet))
2858     {
2859       if (sic->argreg > 12)
2860         {
2861           int bit = sic->argreg-13;
2862
2863           aopOp (IC_LEFT (sic), sic, FALSE,
2864                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2865
2866           /* if left is a literal then
2867              we know what the value is */
2868           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2869             {
2870               if (((int) operandLitValue (IC_LEFT (sic))))
2871                   emitcode ("setb", "b[%d]", bit);
2872               else
2873                   emitcode ("clr", "b[%d]", bit);
2874             }
2875           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2876             {
2877               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2878                 if (strcmp (l, "c"))
2879                     emitcode ("mov", "c,%s", l);
2880                 emitcode ("mov", "b[%d],c", bit);
2881             }
2882           else
2883             {
2884               /* we need to or */
2885               toBoolean (IC_LEFT (sic));
2886               /* set C, if a >= 1 */
2887               emitcode ("add", "a,#0xff");
2888               emitcode ("mov", "b[%d],c", bit);
2889             }
2890           bit_count++;
2891           BitBankUsed = 1;
2892
2893           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2894         }
2895     }
2896
2897   if (bit_count)
2898     {
2899       saveRegisters (setFirstItem (sendSet));
2900       emitcode ("mov", "bits,b");
2901     }
2902
2903   /* then we do all other parameters */
2904   for (sic = setFirstItem (sendSet); sic;
2905        sic = setNextItem (sendSet))
2906     {
2907       if (sic->argreg <= 12)
2908       {
2909         int size, offset = 0;
2910
2911         size = getSize (operandType (IC_LEFT (sic)));
2912         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2913         if (sendCount == 0) { /* first parameter */
2914             // we know that dpl(hxb) is the result, so
2915             rb1_count = 0 ;
2916             _startLazyDPSEvaluation ();
2917             if (size>1) {
2918                 aopOp (IC_LEFT (sic), sic, FALSE,
2919                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2920             } else {
2921                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2922             }
2923             while (size--)
2924               {
2925                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2926                 if (strcmp (l, fReturn[offset]))
2927                   {
2928                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2929                   }
2930                 offset++;
2931               }
2932             _endLazyDPSEvaluation ();
2933             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2934             rb1_count =0;
2935         } else { /* if more parameter in registers */
2936             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2937             while (size--) {
2938                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2939                                                                 FALSE, FALSE, NULL));
2940             }
2941             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2942         }
2943         sendCount++;
2944       }
2945     }
2946 }
2947
2948 static void
2949 adjustEsp(const char *reg)
2950 {
2951     emitcode ("anl","%s,#3", reg);
2952     if (TARGET_IS_DS400)
2953     {
2954         emitcode ("orl","%s,#!constbyte",
2955                   reg,
2956                   (options.stack_loc >> 8) & 0xff);
2957     }
2958 }
2959
2960 /*-----------------------------------------------------------------*/
2961 /* selectRegBank - emit code to select the register bank           */
2962 /*-----------------------------------------------------------------*/
2963 static void
2964 selectRegBank (short bank, bool keepFlags)
2965 {
2966   /* if f.e. result is in carry */
2967   if (keepFlags)
2968     {
2969       emitcode ("anl", "psw,#0xE7");
2970       if (bank)
2971         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2972     }
2973   else
2974     {
2975       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2976     }
2977 }
2978
2979 /*-----------------------------------------------------------------*/
2980 /* genCall - generates a call statement                            */
2981 /*-----------------------------------------------------------------*/
2982 static void
2983 genCall (iCode * ic)
2984 {
2985   sym_link *dtype;
2986   sym_link *etype;
2987   bool restoreBank = FALSE;
2988   bool swapBanks = FALSE;
2989   bool accuse = FALSE;
2990   bool accPushed = FALSE;
2991   bool resultInF0 = FALSE;
2992   bool assignResultGenerated = FALSE;
2993
2994   D (emitcode (";", "genCall"));
2995
2996   /* if we are calling a not _naked function that is not using
2997      the same register bank then we need to save the
2998      destination registers on the stack */
2999   dtype = operandType (IC_LEFT (ic));
3000   etype = getSpec(dtype);
3001   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3002       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3003       IFFUNC_ISISR (currFunc->type))
3004   {
3005       if (!ic->bankSaved)
3006       {
3007            /* This is unexpected; the bank should have been saved in
3008             * genFunction.
3009             */
3010            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3011            restoreBank = TRUE;
3012       }
3013       swapBanks = TRUE;
3014   }
3015
3016   /* if caller saves & we have not saved then */
3017   if (!ic->regsSaved)
3018       saveRegisters (ic);
3019
3020   /* if send set is not empty then assign */
3021   /* We've saved all the registers we care about;
3022   * therefore, we may clobber any register not used
3023   * in the calling convention (i.e. anything not in
3024   * fReturn.
3025   */
3026   if (_G.sendSet)
3027     {
3028         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3029             genSend(reverseSet(_G.sendSet));
3030         } else {
3031             genSend(_G.sendSet);
3032         }
3033       _G.sendSet = NULL;
3034     }
3035
3036   if (swapBanks)
3037     {
3038       emitcode ("mov", "psw,#!constbyte",
3039          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3040     }
3041
3042   /* make the call */
3043   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3044                             OP_SYMBOL (IC_LEFT (ic))->rname :
3045                             OP_SYMBOL (IC_LEFT (ic))->name));
3046
3047   if (swapBanks)
3048     {
3049       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3050     }
3051
3052   /* if we need assign a result value */
3053   if ((IS_ITEMP (IC_RESULT (ic)) &&
3054        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3055        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3056         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3057         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3058       IS_TRUE_SYMOP (IC_RESULT (ic)))
3059     {
3060       if (isOperandInFarSpace (IC_RESULT (ic))
3061           && getSize (operandType (IC_RESULT (ic))) <= 2)
3062         {
3063           int size = getSize (operandType (IC_RESULT (ic)));
3064           bool pushedB = FALSE;
3065
3066           /* Special case for 1 or 2 byte return in far space. */
3067           MOVA (fReturn[0]);
3068           if (size > 1)
3069             {
3070               pushedB = pushB ();
3071               emitcode ("mov", "b,%s", fReturn[1]);
3072             }
3073
3074           _G.accInUse++;
3075           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3076           _G.accInUse--;
3077
3078           popB (pushedB);
3079
3080           aopPut (IC_RESULT (ic), "a", 0);
3081
3082           if (size > 1)
3083             {
3084               aopPut (IC_RESULT (ic), "b", 1);
3085             }
3086           assignResultGenerated = TRUE;
3087           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3088         }
3089       else
3090         {
3091           bool pushedB = pushB ();
3092           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3093           popB (pushedB);
3094
3095           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3096           assignResultGenerated = TRUE;
3097           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3098         }
3099     }
3100
3101   /* adjust the stack for parameters if required */
3102   if (ic->parmBytes)
3103     {
3104       int i;
3105       if (options.stack10bit) {
3106           if (ic->parmBytes <= 10) {
3107               emitcode(";","stack adjustment for parms");
3108               for (i=0; i < ic->parmBytes ; i++) {
3109                   emitcode("pop","acc");
3110               }
3111           } else {
3112               PROTECT_SP;
3113               emitcode ("clr","c");
3114               emitcode ("mov","a,sp");
3115               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3116               emitcode ("mov","sp,a");
3117               emitcode ("mov","a,esp");
3118               adjustEsp("a");
3119               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3120               emitcode ("mov","esp,a");
3121               UNPROTECT_SP;
3122           }
3123       } else {
3124           if (ic->parmBytes > 3)
3125             {
3126               if (accuse)
3127                 {
3128                   emitcode ("push", "acc");
3129                   accPushed = TRUE;
3130                 }
3131               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3132                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3133                   !assignResultGenerated)
3134                 {
3135                   emitcode ("mov", "F0,c");
3136                   resultInF0 = TRUE;
3137                 }
3138
3139               emitcode ("mov", "a,%s", spname);
3140               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3141               emitcode ("mov", "%s,a", spname);
3142
3143               /* unsaveRegisters from xstack needs acc, but */
3144               /* unsaveRegisters from stack needs this popped */
3145               if (accPushed && !options.useXstack)
3146                 {
3147                   emitcode ("pop", "acc");
3148                   accPushed = FALSE;
3149                 }
3150             }
3151           else
3152               for (i = 0; i < ic->parmBytes; i++)
3153                   emitcode ("dec", "%s", spname);
3154       }
3155   }
3156
3157   /* if we had saved some registers then unsave them */
3158   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3159     {
3160       if (accuse && !accPushed && options.useXstack)
3161         {
3162           /* xstack needs acc, but doesn't touch normal stack */
3163           emitcode ("push", "acc");
3164           accPushed = TRUE;
3165         }
3166       unsaveRegisters (ic);
3167     }
3168
3169   /* if register bank was saved then pop them */
3170   if (restoreBank)
3171     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3172
3173   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3174     {
3175       if (resultInF0)
3176           emitcode ("mov", "c,F0");
3177
3178       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3179       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3180       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3181     }
3182
3183   if (accPushed)
3184     emitcode ("pop", "acc");
3185 }
3186
3187 /*-----------------------------------------------------------------*/
3188 /* genPcall - generates a call by pointer statement                */
3189 /*-----------------------------------------------------------------*/
3190 static void
3191 genPcall (iCode * ic)
3192 {
3193   sym_link *dtype;
3194   sym_link *etype;
3195   symbol *rlbl = newiTempLabel (NULL);
3196   bool restoreBank=FALSE;
3197   bool resultInF0 = FALSE;
3198
3199   D (emitcode (";", "genPcall"));
3200
3201   dtype = operandType (IC_LEFT (ic))->next;
3202   etype = getSpec(dtype);
3203   /* if caller saves & we have not saved then */
3204   if (!ic->regsSaved)
3205     saveRegisters (ic);
3206
3207   /* if we are calling a not _naked function that is not using
3208      the same register bank then we need to save the
3209      destination registers on the stack */
3210   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3211       IFFUNC_ISISR (currFunc->type) &&
3212       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3213     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3214     restoreBank=TRUE;
3215   }
3216
3217   /* push the return address on to the stack */
3218   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3219   emitcode ("push", "acc");
3220   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3221   emitcode ("push", "acc");
3222
3223   if (options.model == MODEL_FLAT24)
3224     {
3225       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3226       emitcode ("push", "acc");
3227     }
3228
3229   /* now push the calling address */
3230   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3231
3232   pushSide (IC_LEFT (ic), FPTRSIZE);
3233
3234   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3235
3236   /* if send set is not empty the assign */
3237   if (_G.sendSet)
3238     {
3239         genSend(reverseSet(_G.sendSet));
3240         _G.sendSet = NULL;
3241     }
3242
3243   /* make the call */
3244   emitcode ("ret", "");
3245   emitLabel (rlbl);
3246
3247
3248   /* if we need assign a result value */
3249   if ((IS_ITEMP (IC_RESULT (ic)) &&
3250        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3251        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3252         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3253       IS_TRUE_SYMOP (IC_RESULT (ic)))
3254     {
3255
3256       _G.accInUse++;
3257       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3258       _G.accInUse--;
3259
3260       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3261
3262       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3263     }
3264
3265   /* adjust the stack for parameters if required */
3266   if (ic->parmBytes)
3267     {
3268       int i;
3269       if (options.stack10bit) {
3270           if (ic->parmBytes <= 10) {
3271               emitcode(";","stack adjustment for parms");
3272               for (i=0; i < ic->parmBytes ; i++) {
3273                   emitcode("pop","acc");
3274               }
3275           } else {
3276               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3277                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3278                 {
3279                   emitcode ("mov", "F0,c");
3280                   resultInF0 = TRUE;
3281                 }
3282
3283               PROTECT_SP;
3284               emitcode ("clr","c");
3285               emitcode ("mov","a,sp");
3286               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3287               emitcode ("mov","sp,a");
3288               emitcode ("mov","a,esp");
3289               adjustEsp("a");
3290               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3291               emitcode ("mov","esp,a");
3292               UNPROTECT_SP;
3293           }
3294       } else {
3295           if (ic->parmBytes > 3) {
3296               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3297                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3298                 {
3299                   emitcode ("mov", "F0,c");
3300                   resultInF0 = TRUE;
3301                 }
3302
3303               emitcode ("mov", "a,%s", spname);
3304               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3305               emitcode ("mov", "%s,a", spname);
3306           }
3307           else
3308               for (i = 0; i < ic->parmBytes; i++)
3309                   emitcode ("dec", "%s", spname);
3310       }
3311     }
3312   /* if register bank was saved then unsave them */
3313   if (restoreBank)
3314     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3315
3316   /* if we had saved some registers then unsave them */
3317   if (ic->regsSaved)
3318     unsaveRegisters (ic);
3319
3320   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3321     {
3322       if (resultInF0)
3323           emitcode ("mov", "c,F0");
3324
3325       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3326       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3327       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3328     }
3329 }
3330
3331 /*-----------------------------------------------------------------*/
3332 /* resultRemat - result  is rematerializable                       */
3333 /*-----------------------------------------------------------------*/
3334 static int
3335 resultRemat (iCode * ic)
3336 {
3337   if (SKIP_IC (ic) || ic->op == IFX)
3338     return 0;
3339
3340   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3341     {
3342       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3343       if (sym->remat && !POINTER_SET (ic))
3344         return 1;
3345     }
3346
3347   return 0;
3348 }
3349
3350 #if defined(__BORLANDC__) || defined(_MSC_VER)
3351 #define STRCASECMP stricmp
3352 #else
3353 #define STRCASECMP strcasecmp
3354 #endif
3355
3356 /*-----------------------------------------------------------------*/
3357 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3358 /*-----------------------------------------------------------------*/
3359 static int
3360 regsCmp(void *p1, void *p2)
3361 {
3362   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3363 }
3364
3365 static bool
3366 inExcludeList (char *s)
3367 {
3368   const char *p = setFirstItem(options.excludeRegsSet);
3369
3370   if (p == NULL || STRCASECMP(p, "none") == 0)
3371     return FALSE;
3372
3373
3374   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3375 }
3376
3377 /*-----------------------------------------------------------------*/
3378 /* genFunction - generated code for function entry                 */
3379 /*-----------------------------------------------------------------*/
3380 static void
3381 genFunction (iCode * ic)
3382 {
3383   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3384   sym_link *ftype;
3385   bool     switchedPSW = FALSE;
3386   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3387
3388   D (emitcode (";", "genFunction"));
3389
3390   _G.nRegsSaved = 0;
3391   /* create the function header */
3392   emitcode (";", "-----------------------------------------");
3393   emitcode (";", " function %s", sym->name);
3394   emitcode (";", "-----------------------------------------");
3395
3396   emitcode ("", "%s:", sym->rname);
3397   ftype = operandType (IC_LEFT (ic));
3398   _G.currentFunc = sym;
3399
3400   if (IFFUNC_ISNAKED(ftype))
3401   {
3402       emitcode(";", "naked function: no prologue.");
3403       return;
3404   }
3405
3406   if (options.stack_probe)
3407       emitcode ("lcall","__stack_probe");
3408
3409   /* here we need to generate the equates for the
3410      register bank if required */
3411   if (FUNC_REGBANK (ftype) != rbank)
3412     {
3413       int i;
3414
3415       rbank = FUNC_REGBANK (ftype);
3416       for (i = 0; i < ds390_nRegs; i++)
3417         {
3418           if (regs390[i].print) {
3419               if (strcmp (regs390[i].base, "0") == 0)
3420                   emitcode ("", "%s !equ !constbyte",
3421                             regs390[i].dname,
3422                             8 * rbank + regs390[i].offset);
3423               else
3424                   emitcode ("", "%s !equ %s + !constbyte",
3425                             regs390[i].dname,
3426                             regs390[i].base,
3427                             8 * rbank + regs390[i].offset);
3428           }
3429         }
3430     }
3431
3432   /* if this is an interrupt service routine then
3433      save acc, b, dpl, dph  */
3434   if (IFFUNC_ISISR (sym->type))
3435       { /* is ISR */
3436       if (!inExcludeList ("acc"))
3437         emitcode ("push", "acc");
3438       if (!inExcludeList ("b"))
3439         emitcode ("push", "b");
3440       if (!inExcludeList ("dpl"))
3441         emitcode ("push", "dpl");
3442       if (!inExcludeList ("dph"))
3443         emitcode ("push", "dph");
3444       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3445         {
3446           emitcode ("push", "dpx");
3447           /* Make sure we're using standard DPTR */
3448           emitcode ("push", "dps");
3449           emitcode ("mov", "dps,#0");
3450           if (options.stack10bit)
3451             {
3452               /* This ISR could conceivably use DPTR2. Better save it. */
3453               emitcode ("push", "dpl1");
3454               emitcode ("push", "dph1");
3455               emitcode ("push", "dpx1");
3456               emitcode ("push",  DP2_RESULT_REG);
3457             }
3458         }
3459       /* if this isr has no bank i.e. is going to
3460          run with bank 0 , then we need to save more
3461          registers :-) */
3462       if (!FUNC_REGBANK (sym->type))
3463         {
3464             int i;
3465
3466           /* if this function does not call any other
3467              function then we can be economical and
3468              save only those registers that are used */
3469           if (!IFFUNC_HASFCALL(sym->type))
3470             {
3471               /* if any registers used */
3472               if (sym->regsUsed)
3473                 {
3474                   bool bits_pushed = FALSE;
3475                   /* save the registers used */
3476                   for (i = 0; i < sym->regsUsed->size; i++)
3477                     {
3478                       if (bitVectBitValue (sym->regsUsed, i))
3479                         bits_pushed = pushReg (i, bits_pushed);
3480                     }
3481                 }
3482             }
3483           else
3484             {
3485               /* this function has a function call. We cannot
3486                  determine register usage so we will have to push the
3487                  entire bank */
3488               saveRBank (0, ic, FALSE);
3489               if (options.parms_in_bank1) {
3490                   for (i=0; i < 8 ; i++ ) {
3491                       emitcode ("push","%s",rb1regs[i]);
3492                   }
3493               }
3494             }
3495         }
3496         else
3497         {
3498             /* This ISR uses a non-zero bank.
3499              *
3500              * We assume that the bank is available for our
3501              * exclusive use.
3502              *
3503              * However, if this ISR calls a function which uses some
3504              * other bank, we must save that bank entirely.
3505              */
3506             unsigned long banksToSave = 0;
3507
3508             if (IFFUNC_HASFCALL(sym->type))
3509             {
3510
3511 #define MAX_REGISTER_BANKS 4
3512
3513                 iCode *i;
3514                 int ix;
3515
3516                 for (i = ic; i; i = i->next)
3517                 {
3518                     if (i->op == ENDFUNCTION)
3519                     {
3520                         /* we got to the end OK. */
3521                         break;
3522                     }
3523
3524                     if (i->op == CALL)
3525                     {
3526                         sym_link *dtype;
3527
3528                         dtype = operandType (IC_LEFT(i));
3529                         if (dtype
3530                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3531                         {
3532                              /* Mark this bank for saving. */
3533                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3534                              {
3535                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3536                              }
3537                              else
3538                              {
3539                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3540                              }
3541
3542                              /* And note that we don't need to do it in
3543                               * genCall.
3544                               */
3545                              i->bankSaved = 1;
3546                         }
3547                     }
3548                     if (i->op == PCALL)
3549                     {
3550                         /* This is a mess; we have no idea what
3551                          * register bank the called function might
3552                          * use.
3553                          *
3554                          * The only thing I can think of to do is
3555                          * throw a warning and hope.
3556                          */
3557                         werror(W_FUNCPTR_IN_USING_ISR);
3558                     }
3559                 }
3560
3561                 if (banksToSave && options.useXstack)
3562                 {
3563                     /* Since we aren't passing it an ic,
3564                      * saveRBank will assume r0 is available to abuse.
3565                      *
3566                      * So switch to our (trashable) bank now, so
3567                      * the caller's R0 isn't trashed.
3568                      */
3569                     emitcode ("push", "psw");
3570                     emitcode ("mov", "psw,#!constbyte",
3571                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3572                     switchedPSW = TRUE;
3573                 }
3574
3575                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3576                 {
3577                      if (banksToSave & (1 << ix))
3578                      {
3579                          saveRBank(ix, NULL, FALSE);
3580                      }
3581                 }
3582             }
3583             // TODO: this needs a closer look
3584             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3585         }
3586     }
3587   else
3588     {
3589       /* if callee-save to be used for this function
3590          then save the registers being used in this function */
3591       if (IFFUNC_CALLEESAVES(sym->type))
3592         {
3593           int i;
3594
3595           /* if any registers used */
3596           if (sym->regsUsed)
3597             {
3598               bool bits_pushed = FALSE;
3599               /* save the registers used */
3600               for (i = 0; i < sym->regsUsed->size; i++)
3601                 {
3602                   if (bitVectBitValue (sym->regsUsed, i))
3603                     {
3604                       bits_pushed = pushReg (i, bits_pushed);
3605                       _G.nRegsSaved++;
3606                     }
3607                 }
3608             }
3609         }
3610     }
3611
3612   /* set the register bank to the desired value */
3613   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3614    && !switchedPSW)
3615     {
3616       emitcode ("push", "psw");
3617       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3618     }
3619
3620   if (fReentrant &&
3621        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3622       if (options.stack10bit) {
3623           emitcode ("push","_bpx");
3624           emitcode ("push","_bpx+1");
3625           emitcode ("mov","_bpx,%s",spname);
3626           emitcode ("mov","_bpx+1,esp");
3627           adjustEsp("_bpx+1");
3628       } else {
3629           if (options.useXstack)
3630           {
3631               emitcode ("mov", "r0,%s", spname);
3632               emitcode ("mov", "a,_bp");
3633               emitcode ("movx", "@r0,a");
3634               emitcode ("inc", "%s", spname);
3635           } else {
3636               /* set up the stack */
3637               emitcode ("push", "_bp"); /* save the callers stack  */
3638           }
3639           emitcode ("mov", "_bp,%s", spname);
3640       }
3641   }
3642
3643   /* adjust the stack for the function */
3644   if (sym->stack) {
3645       int i = sym->stack;
3646       if (options.stack10bit) {
3647           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3648           assert (sym->recvSize <= 4);
3649           if (sym->stack <= 8) {
3650               while (i--) emitcode ("push","acc");
3651           } else {
3652               PROTECT_SP;
3653               emitcode ("mov","a,sp");
3654               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3655               emitcode ("mov","sp,a");
3656               emitcode ("mov","a,esp");
3657               adjustEsp("a");
3658               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3659               emitcode ("mov","esp,a");
3660               UNPROTECT_SP;
3661           }
3662       } else {
3663           if (i > 256)
3664               werror (W_STACK_OVERFLOW, sym->name);
3665
3666           if (i > 3 && sym->recvSize < 4) {
3667
3668               emitcode ("mov", "a,sp");
3669               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3670               emitcode ("mov", "sp,a");
3671
3672           } else
3673               while (i--)
3674                   emitcode ("inc", "sp");
3675       }
3676   }
3677
3678   if (sym->xstack)
3679     {
3680
3681       emitcode ("mov", "a,_spx");
3682       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3683       emitcode ("mov", "_spx,a");
3684     }
3685
3686   /* if critical function then turn interrupts off */
3687   if (IFFUNC_ISCRITICAL (ftype))
3688     {
3689       symbol *tlbl = newiTempLabel (NULL);
3690       emitcode ("setb", "c");
3691       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3692       emitcode ("clr", "c");
3693       emitLabel (tlbl);
3694       emitcode ("push", "psw"); /* save old ea via c in psw */
3695     }
3696 }
3697
3698 /*-----------------------------------------------------------------*/
3699 /* genEndFunction - generates epilogue for functions               */
3700 /*-----------------------------------------------------------------*/
3701 static void
3702 genEndFunction (iCode * ic)
3703 {
3704   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3705   lineNode *lnp = lineCurr;
3706   bitVect *regsUsed;
3707   bitVect *regsUsedPrologue;
3708   bitVect *regsUnneeded;
3709   int idx;
3710
3711   D (emitcode (";", "genEndFunction"));
3712
3713   _G.currentFunc = NULL;
3714   if (IFFUNC_ISNAKED(sym->type))
3715   {
3716       emitcode(";", "naked function: no epilogue.");
3717       if (options.debug && currFunc)
3718         debugFile->writeEndFunction (currFunc, ic, 0);
3719       return;
3720   }
3721
3722   if (IFFUNC_ISCRITICAL (sym->type))
3723     {
3724       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3725         {
3726           emitcode ("rlc", "a");   /* save c in a */
3727           emitcode ("pop", "psw"); /* restore ea via c in psw */
3728           emitcode ("mov", "ea,c");
3729           emitcode ("rrc", "a");   /* restore c from a */
3730         }
3731       else
3732         {
3733           emitcode ("pop", "psw"); /* restore ea via c in psw */
3734           emitcode ("mov", "ea,c");
3735         }
3736     }
3737
3738   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3739        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3740
3741       if (options.stack10bit) {
3742           PROTECT_SP;
3743           emitcode ("mov", "sp,_bpx", spname);
3744           emitcode ("mov", "esp,_bpx+1", spname);
3745           UNPROTECT_SP;
3746       } else {
3747           emitcode ("mov", "%s,_bp", spname);
3748       }
3749   }
3750
3751   /* if use external stack but some variables were
3752      added to the local stack then decrement the
3753      local stack */
3754   if (options.useXstack && sym->stack) {
3755       emitcode ("mov", "a,sp");
3756       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3757       emitcode ("mov", "sp,a");
3758   }
3759
3760
3761   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3762        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3763
3764       if (options.useXstack) {
3765           emitcode ("mov", "r0,%s", spname);
3766           emitcode ("movx", "a,@r0");
3767           emitcode ("mov", "_bp,a");
3768           emitcode ("dec", "%s", spname);
3769       } else {
3770           if (options.stack10bit) {
3771               emitcode ("pop", "_bpx+1");
3772               emitcode ("pop", "_bpx");
3773           } else {
3774               emitcode ("pop", "_bp");
3775           }
3776       }
3777   }
3778
3779   /* restore the register bank  */
3780   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3781   {
3782     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3783      || !options.useXstack)
3784     {
3785         /* Special case of ISR using non-zero bank with useXstack
3786          * is handled below.
3787          */
3788         emitcode ("pop", "psw");
3789     }
3790   }
3791
3792   if (IFFUNC_ISISR (sym->type))
3793     { /* is ISR */
3794
3795       /* now we need to restore the registers */
3796       /* if this isr has no bank i.e. is going to
3797          run with bank 0 , then we need to save more
3798          registers :-) */
3799       if (!FUNC_REGBANK (sym->type))
3800         {
3801           int i;
3802           /* if this function does not call any other
3803              function then we can be economical and
3804              save only those registers that are used */
3805           if (!IFFUNC_HASFCALL(sym->type))
3806             {
3807               /* if any registers used */
3808               if (sym->regsUsed)
3809                 {
3810                   bool bits_popped = FALSE;
3811                   /* save the registers used */
3812                   for (i = sym->regsUsed->size; i >= 0; i--)
3813                     {
3814                       if (bitVectBitValue (sym->regsUsed, i))
3815                         bits_popped = popReg (i, bits_popped);
3816                     }
3817                 }
3818             }
3819           else
3820             {
3821               /* this function has a function call. We cannot
3822                  determine register usage so we will have to pop the
3823                  entire bank */
3824               if (options.parms_in_bank1) {
3825                   for (i = 7 ; i >= 0 ; i-- ) {
3826                       emitcode ("pop","%s",rb1regs[i]);
3827                   }
3828               }
3829               unsaveRBank (0, ic, FALSE);
3830             }
3831         }
3832       else
3833         {
3834             /* This ISR uses a non-zero bank.
3835              *
3836              * Restore any register banks saved by genFunction
3837              * in reverse order.
3838              */
3839             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3840             int ix;
3841
3842             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3843             {
3844                 if (savedBanks & (1 << ix))
3845                 {
3846                     unsaveRBank(ix, NULL, FALSE);
3847                 }
3848             }
3849
3850             if (options.useXstack)
3851             {
3852                 /* Restore bank AFTER calling unsaveRBank,
3853                  * since it can trash r0.
3854                  */
3855                 emitcode ("pop", "psw");
3856             }
3857         }
3858
3859       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3860         {
3861           if (options.stack10bit)
3862             {
3863               emitcode ("pop", DP2_RESULT_REG);
3864               emitcode ("pop", "dpx1");
3865               emitcode ("pop", "dph1");
3866               emitcode ("pop", "dpl1");
3867             }
3868           emitcode ("pop", "dps");
3869           emitcode ("pop", "dpx");
3870         }
3871       if (!inExcludeList ("dph"))
3872         emitcode ("pop", "dph");
3873       if (!inExcludeList ("dpl"))
3874         emitcode ("pop", "dpl");
3875       if (!inExcludeList ("b"))
3876         emitcode ("pop", "b");
3877       if (!inExcludeList ("acc"))
3878         emitcode ("pop", "acc");
3879
3880       /* if debug then send end of function */
3881       if (options.debug && currFunc)
3882         {
3883           debugFile->writeEndFunction (currFunc, ic, 1);
3884         }
3885
3886       emitcode ("reti", "");
3887     }
3888   else
3889     {
3890       if (IFFUNC_CALLEESAVES(sym->type))
3891         {
3892           int i;
3893
3894           /* if any registers used */
3895           if (sym->regsUsed)
3896             {
3897               /* save the registers used */
3898               for (i = sym->regsUsed->size; i >= 0; i--)
3899                 {
3900                   if (bitVectBitValue (sym->regsUsed, i))
3901                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3902                 }
3903             }
3904         }
3905
3906       /* if debug then send end of function */
3907       if (options.debug && currFunc)
3908         {
3909           debugFile->writeEndFunction (currFunc, ic, 1);
3910         }
3911
3912       emitcode ("ret", "");
3913     }
3914
3915   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3916     return;
3917
3918   /* If this was an interrupt handler using bank 0 that called another */
3919   /* function, then all registers must be saved; nothing to optimized. */
3920   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3921       && !FUNC_REGBANK(sym->type))
3922     return;
3923
3924   /* There are no push/pops to optimize if not callee-saves or ISR */
3925   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3926     return;
3927
3928   /* If there were stack parameters, we cannot optimize without also    */
3929   /* fixing all of the stack offsets; this is too dificult to consider. */
3930   if (FUNC_HASSTACKPARM(sym->type))
3931     return;
3932
3933   /* Compute the registers actually used */
3934   regsUsed = newBitVect (ds390_nRegs);
3935   regsUsedPrologue = newBitVect (ds390_nRegs);
3936   while (lnp)
3937     {
3938       if (lnp->ic && lnp->ic->op == FUNCTION)
3939         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3940       else
3941         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3942
3943       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3944           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3945         break;
3946       if (!lnp->prev)
3947         break;
3948       lnp = lnp->prev;
3949     }
3950
3951   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3952       && !bitVectBitValue (regsUsed, DPS_IDX))
3953     {
3954       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3955     }
3956
3957   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3958       && !bitVectBitValue (regsUsed, CND_IDX))
3959     {
3960       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3961       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3962           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3963         bitVectUnSetBit (regsUsed, CND_IDX);
3964     }
3965   else
3966     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3967
3968   /* If this was an interrupt handler that called another function */
3969   /* function, then assume working registers may be modified by it. */
3970   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3971     {
3972       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3973       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3974       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3975       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3976       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3983     }
3984
3985   /* Remove the unneeded push/pops */
3986   regsUnneeded = newBitVect (ds390_nRegs);
3987   while (lnp)
3988     {
3989       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3990         {
3991           if (!strncmp(lnp->line, "push", 4))
3992             {
3993               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3994               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3995                 {
3996                   connectLine (lnp->prev, lnp->next);
3997                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3998                 }
3999             }
4000           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4001             {
4002               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4003               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4004                 {
4005                   connectLine (lnp->prev, lnp->next);
4006                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4007                 }
4008             }
4009         }
4010       lnp = lnp->next;
4011     }
4012
4013   for (idx = 0; idx < regsUnneeded->size; idx++)
4014     if (bitVectBitValue (regsUnneeded, idx))
4015       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4016
4017   freeBitVect (regsUnneeded);
4018   freeBitVect (regsUsed);
4019   freeBitVect (regsUsedPrologue);
4020 }
4021
4022 /*-----------------------------------------------------------------*/
4023 /* genJavaNativeRet - generate code for return JavaNative          */
4024 /*-----------------------------------------------------------------*/
4025 static void genJavaNativeRet(iCode *ic)
4026 {
4027     int i, size;
4028
4029     aopOp (IC_LEFT (ic), ic, FALSE,
4030            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4031     size = AOP_SIZE (IC_LEFT (ic));
4032
4033     assert (size <= 4);
4034
4035     /* it is assigned to GPR0-R3 then push them */
4036     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4037         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4038         for (i = 0 ; i < size ; i++ ) {
4039             emitcode ("push","%s",
4040                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4041         }
4042         for (i = (size-1) ; i >= 0 ; i--) {
4043             emitcode ("pop","a%s",javaRet[i]);
4044         }
4045     } else {
4046         for (i = 0 ; i < size ; i++)
4047             emitcode ("mov","%s,%s",javaRet[i],
4048                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4049     }
4050     for (i = size ; i < 4 ; i++ )
4051             emitcode ("mov","%s,#0",javaRet[i]);
4052     return;
4053 }
4054
4055 /*-----------------------------------------------------------------*/
4056 /* genRet - generate code for return statement                     */
4057 /*-----------------------------------------------------------------*/
4058 static void
4059 genRet (iCode * ic)
4060 {
4061   int size, offset = 0, pushed = 0;
4062
4063   D (emitcode (";", "genRet"));
4064
4065   /* if we have no return value then
4066      just generate the "ret" */
4067   if (!IC_LEFT (ic))
4068     goto jumpret;
4069
4070   /* if this is a JavaNative function then return
4071      value in different register */
4072   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4073       genJavaNativeRet(ic);
4074       goto jumpret;
4075   }
4076   /* we have something to return then
4077      move the return value into place */
4078   aopOp (IC_LEFT (ic), ic, FALSE,
4079          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4080   size = AOP_SIZE (IC_LEFT (ic));
4081
4082   _startLazyDPSEvaluation ();
4083
4084   if (IS_BIT(_G.currentFunc->etype))
4085     {
4086       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4087       size = 0;
4088     }
4089
4090   while (size--)
4091     {
4092       char *l;
4093       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4094         {
4095           l = aopGet (IC_LEFT (ic), offset++,
4096                       FALSE, TRUE, NULL);
4097           emitcode ("push", "%s", l);
4098           pushed++;
4099         }
4100       else
4101         {
4102           /* Since A is the last element of fReturn,
4103            * it is OK to clobber it in the aopGet.
4104            */
4105           l = aopGet (IC_LEFT (ic), offset,
4106                       FALSE, FALSE, NULL);
4107           if (strcmp (fReturn[offset], l))
4108             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4109         }
4110     }
4111   _endLazyDPSEvaluation ();
4112
4113   while (pushed)
4114     {
4115       pushed--;
4116       if (strcmp (fReturn[pushed], "a"))
4117         emitcode ("pop", fReturn[pushed]);
4118       else
4119         emitcode ("pop", "acc");
4120     }
4121   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4122
4123 jumpret:
4124   /* generate a jump to the return label
4125      if the next is not the return statement */
4126   if (!(ic->next && ic->next->op == LABEL &&
4127         IC_LABEL (ic->next) == returnLabel))
4128
4129     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4130
4131 }
4132
4133 /*-----------------------------------------------------------------*/
4134 /* genLabel - generates a label                                    */
4135 /*-----------------------------------------------------------------*/
4136 static void
4137 genLabel (iCode * ic)
4138 {
4139   /* special case never generate */
4140   if (IC_LABEL (ic) == entryLabel)
4141     return;
4142
4143   D (emitcode (";", "genLabel"));
4144
4145   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4146 }
4147
4148 /*-----------------------------------------------------------------*/
4149 /* genGoto - generates a ljmp                                      */
4150 /*-----------------------------------------------------------------*/
4151 static void
4152 genGoto (iCode * ic)
4153 {
4154   D (emitcode (";", "genGoto"));
4155
4156   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4157 }
4158
4159 /*-----------------------------------------------------------------*/
4160 /* findLabelBackwards: walks back through the iCode chain looking  */
4161 /* for the given label. Returns number of iCode instructions     */
4162 /* between that label and given ic.          */
4163 /* Returns zero if label not found.          */
4164 /*-----------------------------------------------------------------*/
4165 static int
4166 findLabelBackwards (iCode * ic, int key)
4167 {
4168   int count = 0;
4169
4170   while (ic->prev)
4171     {
4172       ic = ic->prev;
4173       count++;
4174
4175       /* If we have any pushes or pops, we cannot predict the distance.
4176          I don't like this at all, this should be dealt with in the
4177          back-end */
4178       if (ic->op == IPUSH || ic->op == IPOP) {
4179         return 0;
4180       }
4181
4182       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4183         {
4184           /* printf("findLabelBackwards = %d\n", count); */
4185           return count;
4186         }
4187     }
4188
4189   return 0;
4190 }
4191
4192 /*-----------------------------------------------------------------*/
4193 /* genPlusIncr :- does addition with increment if possible         */
4194 /*-----------------------------------------------------------------*/
4195 static bool
4196 genPlusIncr (iCode * ic)
4197 {
4198   unsigned int icount;
4199   unsigned int size = getDataSize (IC_RESULT (ic));
4200
4201   /* will try to generate an increment */
4202   /* if the right side is not a literal
4203      we cannot */
4204   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4205     return FALSE;
4206
4207   /* if the literal value of the right hand side
4208      is greater than 4 then it is not worth it */
4209   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4210     return FALSE;
4211
4212   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4213       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4214       while (icount--) {
4215           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4216       }
4217       return TRUE;
4218   }
4219   /* if increment 16 bits in register */
4220   if (
4221        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4222        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4223        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4224        (size > 1) &&
4225        (icount == 1))
4226     {
4227       symbol  *tlbl;
4228       int     emitTlbl;
4229       int     labelRange;
4230       char    *l;
4231
4232       /* If the next instruction is a goto and the goto target
4233        * is <= 5 instructions previous to this, we can generate
4234        * jumps straight to that target.
4235        */
4236       if (ic->next && ic->next->op == GOTO
4237           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4238           && labelRange <= 5)
4239         {
4240           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4241           tlbl = IC_LABEL (ic->next);
4242           emitTlbl = 0;
4243         }
4244       else
4245         {
4246           tlbl = newiTempLabel (NULL);
4247           emitTlbl = 1;
4248         }
4249       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4250       emitcode ("inc", "%s", l);
4251
4252       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4253           IS_AOP_PREG (IC_RESULT (ic)))
4254         {
4255           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4256         }
4257       else
4258         {
4259           emitcode ("clr", "a");
4260           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4261         }
4262
4263       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4264       emitcode ("inc", "%s", l);
4265       if (size > 2)
4266         {
4267           if (!strcmp(l, "acc"))
4268             {
4269                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4270             }
4271           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4272                    IS_AOP_PREG (IC_RESULT (ic)))
4273             {
4274                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4275             }
4276           else
4277             {
4278                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4279             }
4280
4281           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4282           emitcode ("inc", "%s", l);
4283         }
4284       if (size > 3)
4285         {
4286           if (!strcmp(l, "acc"))
4287             {
4288                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4289             }
4290           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4291                    IS_AOP_PREG (IC_RESULT (ic)))
4292             {
4293                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4294             }
4295           else
4296             {
4297                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4298             }
4299
4300           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4301           emitcode ("inc", "%s", l);
4302         }
4303
4304       if (emitTlbl)
4305         {
4306           emitLabel (tlbl);
4307         }
4308       return TRUE;
4309     }
4310
4311   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4312       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4313       options.model == MODEL_FLAT24 )
4314     {
4315       if (IC_RESULT(ic)->isGptr)
4316         {
4317           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4318         }
4319       switch (size) {
4320       case 3:
4321           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4322       case 2:
4323           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4324       case 1:
4325           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4326           break;
4327       }
4328       while (icount--)
4329         emitcode ("inc", "dptr");
4330       return TRUE;
4331   }
4332
4333   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4334       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4335       icount <= 5 ) {
4336       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4337       while (icount--)
4338         emitcode ("inc", "dptr");
4339       emitcode ("mov", "dps,#0");
4340       return TRUE;
4341   }
4342
4343   /* if the sizes are greater than 1 then we cannot */
4344   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4345       AOP_SIZE (IC_LEFT (ic)) > 1)
4346     return FALSE;
4347
4348   /* we can if the aops of the left & result match or
4349      if they are in registers and the registers are the
4350      same */
4351   if (
4352        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4353        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4354        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4355     {
4356       if (icount > 3)
4357         {
4358           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4359           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4360           aopPut (IC_RESULT (ic), "a", 0);
4361         }
4362       else
4363         {
4364           _startLazyDPSEvaluation ();
4365           while (icount--)
4366             {
4367               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4368             }
4369           _endLazyDPSEvaluation ();
4370         }
4371
4372       return TRUE;
4373     }
4374
4375   return FALSE;
4376 }
4377
4378 /*-----------------------------------------------------------------*/
4379 /* outBitAcc - output a bit in acc                                 */
4380 /*-----------------------------------------------------------------*/
4381 static void
4382 outBitAcc (operand * result)
4383 {
4384   symbol *tlbl = newiTempLabel (NULL);
4385   /* if the result is a bit */
4386   if (AOP_TYPE (result) == AOP_CRY)
4387     {
4388       aopPut (result, "a", 0);
4389     }
4390   else
4391     {
4392       emitcode ("jz", "!tlabel", tlbl->key + 100);
4393       emitcode ("mov", "a,%s", one);
4394       emitLabel (tlbl);
4395       outAcc (result);
4396     }
4397 }
4398
4399 /*-----------------------------------------------------------------*/
4400 /* genPlusBits - generates code for addition of two bits           */
4401 /*-----------------------------------------------------------------*/
4402 static void
4403 genPlusBits (iCode * ic)
4404 {
4405   D (emitcode (";", "genPlusBits"));
4406
4407   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4408     {
4409       symbol *lbl = newiTempLabel (NULL);
4410       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4411       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4412       emitcode ("cpl", "c");
4413       emitLabel (lbl);
4414       outBitC (IC_RESULT (ic));
4415     }
4416   else
4417     {
4418       emitcode ("clr", "a");
4419       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4420       emitcode ("rlc", "a");
4421       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4422       emitcode ("addc", "a,%s", zero);
4423       outAcc (IC_RESULT (ic));
4424     }
4425 }
4426
4427 static void
4428 adjustArithmeticResult (iCode * ic)
4429 {
4430   if (opIsGptr (IC_RESULT (ic)) &&
4431       opIsGptr (IC_LEFT (ic)) &&
4432       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4433     {
4434       aopPut (IC_RESULT (ic),
4435               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4436               GPTRSIZE - 1);
4437     }
4438
4439   if (opIsGptr (IC_RESULT (ic)) &&
4440       opIsGptr (IC_RIGHT (ic)) &&
4441       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4442     {
4443       aopPut (IC_RESULT (ic),
4444               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4445               GPTRSIZE - 1);
4446     }
4447
4448   if (opIsGptr (IC_RESULT (ic)) &&
4449       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4450       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4451       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4452       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4453     {
4454       char buffer[5];
4455       SNPRINTF (buffer, sizeof(buffer),
4456                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4457       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4458     }
4459 }
4460
4461 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4462 // generates the result if possible. If result is generated, returns TRUE; otherwise
4463 // returns false and caller must deal with fact that result isn't aopOp'd.
4464 bool aopOp3(iCode * ic)
4465 {
4466     bool dp1InUse, dp2InUse;
4467     bool useDp2;
4468
4469     // First, generate the right opcode. DPTR may be used if neither left nor result are
4470     // of type AOP_STR.
4471
4472 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4473 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4474 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4475 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4476 //      );
4477 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4478 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4479 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4480 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4481 //      );
4482
4483     // Right uses DPTR unless left or result is an AOP_STR; however,
4484     // if right is an AOP_STR, it must use DPTR regardless.
4485     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4486      && !AOP_IS_STR (IC_RIGHT (ic)))
4487     {
4488         useDp2 = TRUE;
4489     }
4490     else
4491     {
4492         useDp2 = FALSE;
4493     }
4494
4495     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4496
4497     // if the right used DPTR, left MUST use DPTR2.
4498     // if the right used DPTR2, left MUST use DPTR.
4499     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4500     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4501     // enabling us to assign DPTR to result.
4502
4503     if (AOP_USESDPTR (IC_RIGHT (ic)))
4504     {
4505         useDp2 = TRUE;
4506     }
4507     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4508     {
4509         useDp2 = FALSE;
4510     }
4511     else
4512     {
4513         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4514         {
4515             useDp2 = TRUE;
4516         }
4517         else
4518         {
4519             useDp2 = FALSE;
4520         }
4521     }
4522
4523     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4524
4525
4526     // We've op'd the left & right. So, if left or right are the same operand as result,
4527     // we know aopOp will succeed, and we can just do it & bail.
4528     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4529       {
4530         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4531         return TRUE;
4532       }
4533     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4534       {
4535 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4536         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4537         return TRUE;
4538       }
4539
4540     // Operands may be equivalent (but not equal) if they share a spill location. If
4541     // so, use the same DPTR or DPTR2.
4542     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4543       {
4544         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4545         return TRUE;
4546       }
4547     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4548       {
4549         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4550         return TRUE;
4551       }
4552
4553     // Note which dptrs are currently in use.
4554     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4555     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4556
4557     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4558     // generate it.
4559     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4560     {
4561         return FALSE;
4562     }
4563
4564     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4565     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4566     {
4567         return FALSE;
4568     }
4569
4570     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4571     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4572     {
4573         return FALSE;
4574     }
4575
4576     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4577
4578     // Some sanity checking...
4579     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4580     {
4581         fprintf(stderr,
4582                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4583                 __FILE__, __LINE__, ic->filename, ic->lineno);
4584         emitcode(";", ">>> unexpected DPTR here.");
4585     }
4586
4587     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4588     {
4589         fprintf(stderr,
4590                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4591                 __FILE__, __LINE__, ic->filename, ic->lineno);
4592         emitcode(";", ">>> unexpected DPTR2 here.");
4593     }
4594
4595     return TRUE;
4596 }
4597
4598 // Macro to aopOp all three operands of an ic. If this cannot be done,
4599 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4600 // will be set TRUE. The caller must then handle the case specially, noting
4601 // that the IC_RESULT operand is not aopOp'd.
4602 //
4603 #define AOP_OP_3_NOFATAL(ic, rc) \
4604             do { rc = !aopOp3(ic); } while (0)
4605
4606 // aopOp the left & right operands of an ic.
4607 #define AOP_OP_2(ic) \
4608     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4609     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4610
4611 // convienience macro.
4612 #define AOP_SET_LOCALS(ic) \
4613     left = IC_LEFT(ic); \
4614     right = IC_RIGHT(ic); \
4615     result = IC_RESULT(ic);
4616
4617
4618 // Given an integer value of pushedSize bytes on the stack,
4619 // adjust it to be resultSize bytes, either by discarding
4620 // the most significant bytes or by zero-padding.
4621 //
4622 // On exit from this macro, pushedSize will have been adjusted to
4623 // equal resultSize, and ACC may be trashed.
4624 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4625       /* If the pushed data is bigger than the result,          \
4626        * simply discard unused bytes. Icky, but works.          \
4627        */                                                       \
4628       while (pushedSize > resultSize)                           \
4629       {                                                         \
4630           D (emitcode (";", "discarding unused result byte.")); \
4631           emitcode ("pop", "acc");                              \
4632           pushedSize--;                                         \
4633       }                                                         \
4634       if (pushedSize < resultSize)                              \
4635       {                                                         \
4636           emitcode ("clr", "a");                                \
4637           /* Conversly, we haven't pushed enough here.          \
4638            * just zero-pad, and all is well.                    \
4639            */                                                   \
4640           while (pushedSize < resultSize)                       \
4641           {                                                     \
4642               emitcode("push", "acc");                          \
4643               pushedSize++;                                     \
4644           }                                                     \
4645       }                                                         \
4646       assert(pushedSize == resultSize);
4647
4648 /*-----------------------------------------------------------------*/
4649 /* genPlus - generates code for addition                           */
4650 /*-----------------------------------------------------------------*/
4651 static void
4652 genPlus (iCode * ic)
4653 {
4654   int size, offset = 0;
4655   bool pushResult;
4656   int rSize;
4657   bool swappedLR = FALSE;
4658
4659   D (emitcode (";", "genPlus"));
4660
4661   /* special cases :- */
4662   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4663       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4664       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4665       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4666       if (size <= 9) {
4667           while (size--) emitcode ("inc","dptr");
4668       } else {
4669           emitcode ("mov", "a,dpl");
4670           emitcode ("add", "a,#!constbyte", size & 0xff);
4671           emitcode ("mov", "dpl,a");
4672           emitcode ("mov", "a,dph");
4673           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4674           emitcode ("mov", "dph,a");
4675           emitcode ("mov", "a,dpx");
4676           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4677           emitcode ("mov", "dpx,a");
4678       }
4679       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4680       return ;
4681   }
4682   if ( IS_SYMOP (IC_LEFT (ic)) &&
4683        OP_SYMBOL (IC_LEFT (ic))->remat &&
4684        isOperandInFarSpace (IC_RIGHT (ic))) {
4685       operand *op = IC_RIGHT(ic);
4686       IC_RIGHT(ic) = IC_LEFT(ic);
4687       IC_LEFT(ic) = op;
4688   }
4689
4690   AOP_OP_3_NOFATAL (ic, pushResult);
4691
4692   if (pushResult)
4693     {
4694       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4695     }
4696
4697   if (!pushResult)
4698     {
4699       /* if literal, literal on the right or
4700          if left requires ACC or right is already
4701          in ACC */
4702       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4703           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4704           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4705         {
4706           operand *t = IC_RIGHT (ic);
4707           IC_RIGHT (ic) = IC_LEFT (ic);
4708           IC_LEFT (ic) = t;
4709           swappedLR = TRUE;
4710           D (emitcode (";", "Swapped plus args."));
4711         }
4712
4713       /* if both left & right are in bit
4714          space */
4715       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4716           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4717         {
4718           genPlusBits (ic);
4719           goto release;
4720         }
4721
4722       /* if left in bit space & right literal */
4723       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4724           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4725         {
4726           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4727           /* if result in bit space */
4728           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4729             {
4730               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4731                 emitcode ("cpl", "c");
4732               outBitC (IC_RESULT (ic));
4733             }
4734           else
4735             {
4736               size = getDataSize (IC_RESULT (ic));
4737               _startLazyDPSEvaluation ();
4738               while (size--)
4739                 {
4740                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4741                   emitcode ("addc", "a,%s", zero);
4742                   aopPut (IC_RESULT (ic), "a", offset++);
4743                 }
4744               _endLazyDPSEvaluation ();
4745             }
4746           goto release;
4747         }
4748
4749       /* if I can do an increment instead
4750          of add then GOOD for ME */
4751       if (genPlusIncr (ic) == TRUE)
4752         {
4753           D (emitcode (";", "did genPlusIncr"));
4754           goto release;
4755         }
4756
4757     }
4758   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4759
4760   _startLazyDPSEvaluation ();
4761   while (size--)
4762     {
4763       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4764         {
4765           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4766           if (offset == 0)
4767             emitcode ("add", "a,%s",
4768                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4769           else
4770             emitcode ("addc", "a,%s",
4771                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4772         }
4773       else
4774         {
4775           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4776           {
4777               /* right is going to use ACC or we would have taken the
4778                * above branch.
4779                */
4780               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4781               TR_AP("#3");
4782               D(emitcode(";", "+ AOP_ACC special case."););
4783               emitcode("xch", "a, %s", DP2_RESULT_REG);
4784           }
4785           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4786           if (offset == 0)
4787           {
4788             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4789             {
4790                 TR_AP("#4");
4791                 emitcode("add", "a, %s", DP2_RESULT_REG);
4792             }
4793             else
4794             {
4795                 emitcode ("add", "a,%s",
4796                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4797                                   DP2_RESULT_REG));
4798             }
4799           }
4800           else
4801           {
4802             emitcode ("addc", "a,%s",
4803                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4804                           DP2_RESULT_REG));
4805           }
4806         }
4807       if (!pushResult)
4808         {
4809           aopPut (IC_RESULT (ic), "a", offset);
4810         }
4811       else
4812         {
4813           emitcode ("push", "acc");
4814         }
4815       offset++;
4816     }
4817   _endLazyDPSEvaluation ();
4818
4819   if (pushResult)
4820     {
4821       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4822
4823       size = getDataSize (IC_LEFT (ic));
4824       rSize = getDataSize (IC_RESULT (ic));
4825
4826       ADJUST_PUSHED_RESULT(size, rSize);
4827
4828       _startLazyDPSEvaluation ();
4829       while (size--)
4830         {
4831           emitcode ("pop", "acc");
4832           aopPut (IC_RESULT (ic), "a", size);
4833         }
4834       _endLazyDPSEvaluation ();
4835     }
4836
4837   adjustArithmeticResult (ic);
4838
4839 release:
4840   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4841   if (!swappedLR)
4842     {
4843       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4844       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4845     }
4846   else
4847     {
4848       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4849       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4850     }
4851 }
4852
4853 /*-----------------------------------------------------------------*/
4854 /* genMinusDec :- does subtraction with decrement if possible      */
4855 /*-----------------------------------------------------------------*/
4856 static bool
4857 genMinusDec (iCode * ic)
4858 {
4859   unsigned int icount;
4860   unsigned int size = getDataSize (IC_RESULT (ic));
4861
4862   /* will try to generate an increment */
4863   /* if the right side is not a literal
4864      we cannot */
4865   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4866     return FALSE;
4867
4868   /* if the literal value of the right hand side
4869      is greater than 4 then it is not worth it */
4870   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4871     return FALSE;
4872
4873   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4874       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4875       while (icount--) {
4876           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4877       }
4878       return TRUE;
4879   }
4880   /* if decrement 16 bits in register */
4881   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4882       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4883       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4884       (size > 1) &&
4885       (icount == 1))
4886     {
4887       symbol *tlbl;
4888       int    emitTlbl;
4889       int    labelRange;
4890       char   *l;
4891
4892       /* If the next instruction is a goto and the goto target
4893          * is <= 5 instructions previous to this, we can generate
4894          * jumps straight to that target.
4895        */
4896       if (ic->next && ic->next->op == GOTO
4897           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4898           && labelRange <= 5)
4899         {
4900           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4901           tlbl = IC_LABEL (ic->next);
4902           emitTlbl = 0;
4903         }
4904       else
4905         {
4906           tlbl = newiTempLabel (NULL);
4907           emitTlbl = 1;
4908         }
4909
4910       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4911       emitcode ("dec", "%s", l);
4912
4913       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4914           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4915           IS_AOP_PREG (IC_RESULT (ic)))
4916       {
4917           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4918       }
4919       else
4920       {
4921           emitcode ("mov", "a,#!constbyte",0xff);
4922           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4923       }
4924       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4925       emitcode ("dec", "%s", l);
4926       if (size > 2)
4927         {
4928             if (!strcmp(l, "acc"))
4929             {
4930                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4931             }
4932             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4933                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4934                      IS_AOP_PREG (IC_RESULT (ic)))
4935             {
4936                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4937             }
4938             else
4939             {
4940                 emitcode ("mov", "a,#!constbyte",0xff);
4941                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4942             }
4943             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4944             emitcode ("dec", "%s", l);
4945         }
4946       if (size > 3)
4947         {
4948             if (!strcmp(l, "acc"))
4949             {
4950                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4951             }
4952             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4953                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4954                      IS_AOP_PREG (IC_RESULT (ic)))
4955             {
4956                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4957             }
4958             else
4959             {
4960                 emitcode ("mov", "a,#!constbyte",0xff);
4961                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4962             }
4963             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4964             emitcode ("dec", "%s", l);
4965         }
4966       if (emitTlbl)
4967         {
4968           emitLabel (tlbl);
4969         }
4970       return TRUE;
4971     }
4972
4973   /* if the sizes are greater than 1 then we cannot */
4974   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4975       AOP_SIZE (IC_LEFT (ic)) > 1)
4976     return FALSE;
4977
4978   /* we can if the aops of the left & result match or
4979      if they are in registers and the registers are the
4980      same */
4981   if (
4982        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4983        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4984        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4985     {
4986       char *l;
4987
4988       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4989         {
4990           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4991           l = "a";
4992         }
4993       else
4994         {
4995           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
4996         }
4997
4998       _startLazyDPSEvaluation ();
4999       while (icount--)
5000         {
5001           emitcode ("dec", "%s", l);
5002         }
5003       _endLazyDPSEvaluation ();
5004
5005       if (AOP_NEEDSACC (IC_RESULT (ic)))
5006         aopPut (IC_RESULT (ic), "a", 0);
5007
5008       return TRUE;
5009     }
5010
5011   return FALSE;
5012 }
5013
5014 /*-----------------------------------------------------------------*/
5015 /* addSign - complete with sign                                    */
5016 /*-----------------------------------------------------------------*/
5017 static void
5018 addSign (operand * result, int offset, int sign)
5019 {
5020   int size = (getDataSize (result) - offset);
5021   if (size > 0)
5022     {
5023       _startLazyDPSEvaluation();
5024       if (sign)
5025         {
5026           emitcode ("rlc", "a");
5027           emitcode ("subb", "a,acc");
5028           while (size--)
5029             {
5030               aopPut (result, "a", offset++);
5031             }
5032         }
5033       else
5034       {
5035         while (size--)
5036         {
5037           aopPut (result, zero, offset++);
5038         }
5039       }
5040       _endLazyDPSEvaluation();
5041     }
5042 }
5043
5044 /*-----------------------------------------------------------------*/
5045 /* genMinusBits - generates code for subtraction  of two bits      */
5046 /*-----------------------------------------------------------------*/
5047 static void
5048 genMinusBits (iCode * ic)
5049 {
5050   symbol *lbl = newiTempLabel (NULL);
5051
5052   D (emitcode (";", "genMinusBits"));
5053
5054   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5055     {
5056       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5057       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5058       emitcode ("cpl", "c");
5059       emitLabel (lbl);
5060       outBitC (IC_RESULT (ic));
5061     }
5062   else
5063     {
5064       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5065       emitcode ("subb", "a,acc");
5066       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5067       emitcode ("inc", "a");
5068       emitLabel (lbl);
5069       aopPut (IC_RESULT (ic), "a", 0);
5070       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5071     }
5072 }
5073
5074 /*-----------------------------------------------------------------*/
5075 /* genMinus - generates code for subtraction                       */
5076 /*-----------------------------------------------------------------*/
5077 static void
5078 genMinus (iCode * ic)
5079 {
5080     int size, offset = 0;
5081     int rSize;
5082     long lit = 0L;
5083     bool pushResult;
5084
5085     D (emitcode (";", "genMinus"));
5086
5087     AOP_OP_3_NOFATAL(ic, pushResult);
5088
5089     if (!pushResult)
5090     {
5091       /* special cases :- */
5092       /* if both left & right are in bit space */
5093       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5094           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5095         {
5096           genMinusBits (ic);
5097           goto release;
5098         }
5099
5100       /* if I can do an decrement instead
5101          of subtract then GOOD for ME */
5102       if (genMinusDec (ic) == TRUE)
5103         goto release;
5104
5105     }
5106
5107   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5108
5109   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5110     {
5111       CLRC;
5112     }
5113   else
5114     {
5115       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5116       lit = -lit;
5117     }
5118
5119
5120   /* if literal, add a,#-lit, else normal subb */
5121   _startLazyDPSEvaluation ();
5122   while (size--) {
5123       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5124           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5125               emitcode ("mov","b,%s",
5126                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5127               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5128               emitcode ("subb","a,b");
5129           } else {
5130               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5131               emitcode ("subb", "a,%s",
5132                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5133                                 DP2_RESULT_REG));
5134           }
5135       } else {
5136           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5137           /* first add without previous c */
5138           if (!offset) {
5139               if (!size && lit==-1) {
5140                   emitcode ("dec", "a");
5141               } else {
5142                   emitcode ("add", "a,#!constbyte",
5143                             (unsigned int) (lit & 0x0FFL));
5144               }
5145           } else {
5146               emitcode ("addc", "a,#!constbyte",
5147                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5148           }
5149       }
5150
5151       if (pushResult) {
5152           emitcode ("push", "acc");
5153       } else {
5154           aopPut (IC_RESULT (ic), "a", offset);
5155       }
5156       offset++;
5157   }
5158   _endLazyDPSEvaluation ();
5159
5160   if (pushResult)
5161     {
5162       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5163
5164       size = getDataSize (IC_LEFT (ic));
5165       rSize = getDataSize (IC_RESULT (ic));
5166
5167       ADJUST_PUSHED_RESULT(size, rSize);
5168
5169       _startLazyDPSEvaluation ();
5170       while (size--)
5171         {
5172           emitcode ("pop", "acc");
5173           aopPut (IC_RESULT (ic), "a", size);
5174         }
5175       _endLazyDPSEvaluation ();
5176     }
5177
5178   adjustArithmeticResult (ic);
5179
5180 release:
5181   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5182   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5183   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5184 }
5185
5186
5187 /*-----------------------------------------------------------------*/
5188 /* genMultbits :- multiplication of bits                           */
5189 /*-----------------------------------------------------------------*/
5190 static void
5191 genMultbits (operand * left,
5192              operand * right,
5193              operand * result,
5194              iCode   * ic)
5195 {
5196   D (emitcode (";", "genMultbits"));
5197
5198   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5199   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5200   aopOp(result, ic, TRUE, FALSE);
5201   outBitC (result);
5202 }
5203
5204 /*-----------------------------------------------------------------*/
5205 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5206 /*-----------------------------------------------------------------*/
5207 static void
5208 genMultOneByte (operand * left,
5209                 operand * right,
5210                 operand * result,
5211                 iCode   * ic)
5212 {
5213   symbol *lbl;
5214   int size;
5215   bool runtimeSign, compiletimeSign;
5216   bool lUnsigned, rUnsigned, pushedB;
5217
5218   /* (if two literals: the value is computed before) */
5219   /* if one literal, literal on the right */
5220   if (AOP_TYPE (left) == AOP_LIT)
5221     {
5222       operand *t = right;
5223       right = left;
5224       left = t;
5225       /* emitcode (";", "swapped left and right"); */
5226     }
5227   /* if no literal, unsigned on the right: shorter code */
5228   if (   AOP_TYPE (right) != AOP_LIT
5229       && SPEC_USIGN (getSpec (operandType (left))))
5230     {
5231       operand *t = right;
5232       right = left;
5233       left = t;
5234     }
5235
5236   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5237   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5238
5239   pushedB = pushB ();
5240
5241   if ((lUnsigned && rUnsigned)
5242 /* sorry, I don't know how to get size
5243    without calling aopOp (result,...);
5244    see Feature Request  */
5245       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5246                    no need to take care about the signedness! */
5247     {
5248       /* just an unsigned 8 * 8 = 8 multiply
5249          or 8u * 8u = 16u */
5250       /* emitcode (";","unsigned"); */
5251       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5252       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5253       emitcode ("mul", "ab");
5254
5255       _G.accInUse++;
5256       aopOp (result, ic, TRUE, FALSE);
5257       size = AOP_SIZE (result);
5258
5259       if (size < 1 || size > 2)
5260         {
5261           /* this should never happen */
5262           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5263                    size, __FILE__, lineno);
5264           exit (1);
5265         }
5266
5267       aopPut (result, "a", 0);
5268       _G.accInUse--;
5269       if (size == 2)
5270         aopPut (result, "b", 1);
5271
5272       popB (pushedB);
5273       return;
5274     }
5275
5276   /* we have to do a signed multiply */
5277   /* emitcode (";", "signed"); */
5278
5279   /* now sign adjust for both left & right */
5280
5281   /* let's see what's needed: */
5282   /* apply negative sign during runtime */
5283   runtimeSign = FALSE;
5284   /* negative sign from literals */
5285   compiletimeSign = FALSE;
5286
5287   if (!lUnsigned)
5288     {
5289       if (AOP_TYPE(left) == AOP_LIT)
5290         {
5291           /* signed literal */
5292           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5293           if (val < 0)
5294             compiletimeSign = TRUE;
5295         }
5296       else
5297         /* signed but not literal */
5298         runtimeSign = TRUE;
5299     }
5300
5301   if (!rUnsigned)
5302     {
5303       if (AOP_TYPE(right) == AOP_LIT)
5304         {
5305           /* signed literal */
5306           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5307           if (val < 0)
5308             compiletimeSign ^= TRUE;
5309         }
5310       else
5311         /* signed but not literal */
5312         runtimeSign = TRUE;
5313     }
5314
5315   /* initialize F0, which stores the runtime sign */
5316   if (runtimeSign)
5317     {
5318       if (compiletimeSign)
5319         emitcode ("setb", "F0"); /* set sign flag */
5320       else
5321         emitcode ("clr", "F0"); /* reset sign flag */
5322     }
5323
5324   /* save the signs of the operands */
5325   if (AOP_TYPE(right) == AOP_LIT)
5326     {
5327       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5328
5329       if (!rUnsigned && val < 0)
5330         emitcode ("mov", "b,#!constbyte", -val);
5331       else
5332         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5333     }
5334   else /* ! literal */
5335     {
5336       if (rUnsigned)  /* emitcode (";", "signed"); */
5337         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5338       else
5339         {
5340           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5341           lbl = newiTempLabel (NULL);
5342           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5343           emitcode ("cpl", "F0"); /* complement sign flag */
5344           emitcode ("cpl", "a");  /* 2's complement */
5345           emitcode ("inc", "a");
5346           emitLabel (lbl);
5347           emitcode ("mov", "b,a");
5348         }
5349     }
5350
5351   if (AOP_TYPE(left) == AOP_LIT)
5352     {
5353       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5354
5355       if (!lUnsigned && val < 0)
5356         emitcode ("mov", "a,#!constbyte", -val);
5357       else
5358         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5359     }
5360   else /* ! literal */
5361     {
5362       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5363
5364       if (!lUnsigned)  /* emitcode (";", "signed"); */
5365         {
5366           lbl = newiTempLabel (NULL);
5367           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5368           emitcode ("cpl", "F0"); /* complement sign flag */
5369           emitcode ("cpl", "a");  /* 2's complement */
5370           emitcode ("inc", "a");
5371           emitLabel (lbl);
5372         }
5373     }
5374
5375   /* now the multiplication */
5376   emitcode ("mul", "ab");
5377   _G.accInUse++;
5378   aopOp(result, ic, TRUE, FALSE);
5379   size = AOP_SIZE (result);
5380
5381   if (size < 1 || size > 2)
5382     {
5383       /* this should never happen */
5384       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5385                size, __FILE__, lineno);
5386       exit (1);
5387     }
5388
5389   if (runtimeSign || compiletimeSign)
5390     {
5391       lbl = newiTempLabel (NULL);
5392       if (runtimeSign)
5393         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5394       emitcode ("cpl", "a"); /* lsb 2's complement */
5395       if (size != 2)
5396         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5397       else
5398         {
5399           emitcode ("add", "a,#1"); /* this sets carry flag */
5400           emitcode ("xch", "a,b");
5401           emitcode ("cpl", "a"); /* msb 2's complement */
5402           emitcode ("addc", "a,#0");
5403           emitcode ("xch", "a,b");
5404         }
5405       emitLabel (lbl);
5406     }
5407   aopPut (result, "a", 0);
5408   _G.accInUse--;
5409   if (size == 2)
5410     aopPut (result, "b", 1);
5411
5412   popB (pushedB);
5413 }
5414
5415 /*-----------------------------------------------------------------*/
5416 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5417 /*-----------------------------------------------------------------*/
5418 static void genMultTwoByte (operand *left, operand *right,
5419                             operand *result, iCode *ic)
5420 {
5421         sym_link *retype = getSpec(operandType(right));
5422         sym_link *letype = getSpec(operandType(left));
5423         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5424         symbol *lbl;
5425
5426         if (AOP_TYPE (left) == AOP_LIT) {
5427                 operand *t = right;
5428                 right = left;
5429                 left = t;
5430         }
5431         /* save EA bit in F1 */
5432         lbl = newiTempLabel(NULL);
5433         emitcode ("setb","F1");
5434         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5435         emitcode ("clr","F1");
5436         emitLabel (lbl);
5437
5438         /* load up MB with right */
5439         if (!umult) {
5440                 emitcode("clr","F0");
5441                 if (AOP_TYPE(right) == AOP_LIT) {
5442                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5443                         if (val < 0) {
5444                                 emitcode("setb","F0");
5445                                 val = -val;
5446                         }
5447                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5448                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5449                 } else {
5450                         lbl = newiTempLabel(NULL);
5451                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5452                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5453                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5454                         emitcode ("xch", "a,b");
5455                         emitcode ("cpl","a");
5456                         emitcode ("add", "a,#1");
5457                         emitcode ("xch", "a,b");
5458                         emitcode ("cpl", "a"); // msb
5459                         emitcode ("addc", "a,#0");
5460                         emitcode ("setb","F0");
5461                         emitLabel (lbl);
5462                         emitcode ("mov","mb,b");
5463                         emitcode ("mov","mb,a");
5464                 }
5465         } else {
5466                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5467                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5468         }
5469         /* load up MA with left */
5470         if (!umult) {
5471                 lbl = newiTempLabel(NULL);
5472                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5473                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5474                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5475                 emitcode ("xch", "a,b");
5476                 emitcode ("cpl","a");
5477                 emitcode ("add", "a,#1");
5478                 emitcode ("xch", "a,b");
5479                 emitcode ("cpl", "a"); // msb
5480                 emitcode ("addc","a,#0");
5481                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5482                 emitcode ("setb","F0");
5483                 emitLabel (lbl);
5484                 emitcode ("mov","ma,b");
5485                 emitcode ("mov","ma,a");
5486         } else {
5487                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5488                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5489         }
5490         /* wait for multiplication to finish */
5491         lbl = newiTempLabel(NULL);
5492         emitLabel (lbl);
5493         emitcode("mov","a,mcnt1");
5494         emitcode("anl","a,#!constbyte",0x80);
5495         emitcode("jnz","!tlabel",lbl->key+100);
5496
5497         freeAsmop (left, NULL, ic, TRUE);
5498         freeAsmop (right, NULL, ic,TRUE);
5499         aopOp(result, ic, TRUE, FALSE);
5500
5501         /* if unsigned then simple */
5502         if (umult) {
5503                 emitcode ("mov","a,ma");
5504                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5505                 emitcode ("mov","a,ma");
5506                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5507                 aopPut(result,"ma",1);
5508                 aopPut(result,"ma",0);
5509         } else {
5510                 emitcode("push","ma");
5511                 emitcode("push","ma");
5512                 emitcode("push","ma");
5513                 MOVA("ma");
5514                 /* negate result if needed */
5515                 lbl = newiTempLabel(NULL);
5516                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5517                 emitcode("cpl","a");
5518                 emitcode("add","a,#1");
5519                 emitLabel (lbl);
5520                 if (AOP_TYPE(result) == AOP_ACC)
5521                 {
5522                     D (emitcode(";", "ACC special case."));
5523                     /* We know result is the only live aop, and
5524                      * it's obviously not a DPTR2, so AP is available.
5525                      */
5526                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5527                 }
5528                 else
5529                 {
5530                     aopPut(result,"a",0);
5531                 }
5532
5533                 emitcode("pop","acc");
5534                 lbl = newiTempLabel(NULL);
5535                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5536                 emitcode("cpl","a");
5537                 emitcode("addc","a,#0");
5538                 emitLabel (lbl);
5539                 aopPut(result,"a",1);
5540                 emitcode("pop","acc");
5541                 if (AOP_SIZE(result) >= 3) {
5542                         lbl = newiTempLabel(NULL);
5543                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5544                         emitcode("cpl","a");
5545                         emitcode("addc","a,#0");
5546                         emitLabel (lbl);
5547                         aopPut(result,"a",2);
5548                 }
5549                 emitcode("pop","acc");
5550                 if (AOP_SIZE(result) >= 4) {
5551                         lbl = newiTempLabel(NULL);
5552                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5553                         emitcode("cpl","a");
5554                         emitcode("addc","a,#0");
5555                         emitLabel (lbl);
5556                         aopPut(result,"a",3);
5557                 }
5558                 if (AOP_TYPE(result) == AOP_ACC)
5559                 {
5560                     /* We stashed the result away above. */
5561                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5562                 }
5563
5564         }
5565         freeAsmop (result, NULL, ic, TRUE);
5566
5567         /* restore EA bit in F1 */
5568         lbl = newiTempLabel(NULL);
5569         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5570         emitcode ("setb","EA");
5571         emitLabel (lbl);
5572         return ;
5573 }
5574
5575 /*-----------------------------------------------------------------*/
5576 /* genMult - generates code for multiplication                     */
5577 /*-----------------------------------------------------------------*/
5578 static void
5579 genMult (iCode * ic)
5580 {
5581   operand *left = IC_LEFT (ic);
5582   operand *right = IC_RIGHT (ic);
5583   operand *result = IC_RESULT (ic);
5584
5585   D (emitcode (";", "genMult"));
5586
5587   /* assign the asmops */
5588   AOP_OP_2 (ic);
5589
5590   /* special cases first */
5591   /* both are bits */
5592   if (AOP_TYPE (left) == AOP_CRY &&
5593       AOP_TYPE (right) == AOP_CRY)
5594     {
5595       genMultbits (left, right, result, ic);
5596       goto release;
5597     }
5598
5599   /* if both are of size == 1 */
5600   if (AOP_SIZE (left) == 1 &&
5601       AOP_SIZE (right) == 1)
5602     {
5603       genMultOneByte (left, right, result, ic);
5604       goto release;
5605     }
5606
5607   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5608           /* use the ds390 ARITHMETIC accel UNIT */
5609           genMultTwoByte (left, right, result, ic);
5610           return ;
5611   }
5612   /* should have been converted to function call */
5613   assert (0);
5614
5615 release:
5616   freeAsmop (result, NULL, ic, TRUE);
5617   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5618   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5619 }
5620
5621 /*-----------------------------------------------------------------*/
5622 /* genDivbits :- division of bits                                  */
5623 /*-----------------------------------------------------------------*/
5624 static void
5625 genDivbits (operand * left,
5626             operand * right,
5627             operand * result,
5628             iCode   * ic)
5629 {
5630   char *l;
5631   bool pushedB;
5632
5633   D(emitcode (";     genDivbits",""));
5634
5635   pushedB = pushB ();
5636
5637   /* the result must be bit */
5638   LOAD_AB_FOR_DIV (left, right, l);
5639   emitcode ("div", "ab");
5640   emitcode ("rrc", "a");
5641   aopOp(result, ic, TRUE, FALSE);
5642
5643   popB (pushedB);
5644
5645   aopPut (result, "c", 0);
5646 }
5647
5648 /*-----------------------------------------------------------------*/
5649 /* genDivOneByte : 8 bit division                                  */
5650 /*-----------------------------------------------------------------*/
5651 static void
5652 genDivOneByte (operand * left,
5653                operand * right,
5654                operand * result,
5655                iCode   * ic)
5656 {
5657   bool lUnsigned, rUnsigned, pushedB;
5658   bool runtimeSign, compiletimeSign;
5659   char *l;
5660   symbol *lbl;
5661   int size, offset;
5662
5663   D(emitcode (";     genDivOneByte",""));
5664
5665   offset = 1;
5666   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5667   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5668
5669   pushedB = pushB ();
5670
5671   /* signed or unsigned */
5672   if (lUnsigned && rUnsigned)
5673     {
5674       /* unsigned is easy */
5675       LOAD_AB_FOR_DIV (left, right, l);
5676       emitcode ("div", "ab");
5677
5678       _G.accInUse++;
5679       aopOp (result, ic, TRUE, FALSE);
5680       aopPut (result, "a", 0);
5681       _G.accInUse--;
5682
5683       size = AOP_SIZE (result) - 1;
5684
5685       while (size--)
5686         aopPut (result, zero, offset++);
5687
5688       popB (pushedB);
5689       return;
5690     }
5691
5692   /* signed is a little bit more difficult */
5693
5694   /* now sign adjust for both left & right */
5695
5696   /* let's see what's needed: */
5697   /* apply negative sign during runtime */
5698   runtimeSign = FALSE;
5699   /* negative sign from literals */
5700   compiletimeSign = FALSE;
5701
5702   if (!lUnsigned)
5703     {
5704       if (AOP_TYPE(left) == AOP_LIT)
5705         {
5706           /* signed literal */
5707           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5708           if (val < 0)
5709             compiletimeSign = TRUE;
5710         }
5711       else
5712         /* signed but not literal */
5713         runtimeSign = TRUE;
5714     }
5715
5716   if (!rUnsigned)
5717     {
5718       if (AOP_TYPE(right) == AOP_LIT)
5719         {
5720           /* signed literal */
5721           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5722           if (val < 0)
5723             compiletimeSign ^= TRUE;
5724         }
5725       else
5726         /* signed but not literal */
5727         runtimeSign = TRUE;
5728     }
5729
5730   /* initialize F0, which stores the runtime sign */
5731   if (runtimeSign)
5732     {
5733       if (compiletimeSign)
5734         emitcode ("setb", "F0"); /* set sign flag */
5735       else
5736         emitcode ("clr", "F0"); /* reset sign flag */
5737     }
5738
5739   /* save the signs of the operands */
5740   if (AOP_TYPE(right) == AOP_LIT)
5741     {
5742       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5743
5744       if (!rUnsigned && val < 0)
5745         emitcode ("mov", "b,#0x%02x", -val);
5746       else
5747         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5748     }
5749   else /* ! literal */
5750     {
5751       if (rUnsigned)
5752         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5753       else
5754         {
5755           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5756           lbl = newiTempLabel (NULL);
5757           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5758           emitcode ("cpl", "F0"); /* complement sign flag */
5759           emitcode ("cpl", "a");  /* 2's complement */
5760           emitcode ("inc", "a");
5761           emitLabel (lbl);
5762           emitcode ("mov", "b,a");
5763         }
5764     }
5765
5766   if (AOP_TYPE(left) == AOP_LIT)
5767     {
5768       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5769
5770       if (!lUnsigned && val < 0)
5771         emitcode ("mov", "a,#0x%02x", -val);
5772       else
5773         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5774     }
5775   else /* ! literal */
5776     {
5777       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5778
5779       if (!lUnsigned)
5780         {
5781           lbl = newiTempLabel (NULL);
5782           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5783           emitcode ("cpl", "F0"); /* complement sign flag */
5784           emitcode ("cpl", "a");  /* 2's complement */
5785           emitcode ("inc", "a");
5786           emitLabel (lbl);
5787         }
5788     }
5789
5790   /* now the division */
5791   emitcode ("nop", "; workaround for DS80C390 div bug.");
5792   emitcode ("div", "ab");
5793
5794   if (runtimeSign || compiletimeSign)
5795     {
5796       lbl = newiTempLabel (NULL);
5797       if (runtimeSign)
5798         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5799       emitcode ("cpl", "a"); /* lsb 2's complement */
5800       emitcode ("inc", "a");
5801       emitLabel (lbl);
5802
5803       _G.accInUse++;
5804       aopOp (result, ic, TRUE, FALSE);
5805       size = AOP_SIZE (result) - 1;
5806
5807       if (size > 0)
5808         {
5809           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5810              then the result will be in b, a */
5811           emitcode ("mov", "b,a"); /* 1 */
5812           /* msb is 0x00 or 0xff depending on the sign */
5813           if (runtimeSign)
5814             {
5815               emitcode ("mov",  "c,F0");
5816               emitcode ("subb", "a,acc");
5817               emitcode ("xch",  "a,b"); /* 2 */
5818               while (size--)
5819                 aopPut (result, "b", offset++); /* write msb's */
5820             }
5821           else /* compiletimeSign */
5822             while (size--)
5823               aopPut (result, "#0xff", offset++); /* write msb's */
5824         }
5825       aopPut (result, "a", 0); /* 3: write lsb */
5826     }
5827   else
5828     {
5829       _G.accInUse++;
5830       aopOp(result, ic, TRUE, FALSE);
5831       size = AOP_SIZE (result) - 1;
5832
5833       aopPut (result, "a", 0);
5834       while (size--)
5835         aopPut (result, zero, offset++);
5836     }
5837   _G.accInUse--;
5838   popB (pushedB);
5839 }
5840
5841 /*-----------------------------------------------------------------*/
5842 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5843 /*-----------------------------------------------------------------*/
5844 static void genDivTwoByte (operand *left, operand *right,
5845                             operand *result, iCode *ic)
5846 {
5847         sym_link *retype = getSpec(operandType(right));
5848         sym_link *letype = getSpec(operandType(left));
5849         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5850         symbol *lbl;
5851
5852         /* save EA bit in F1 */
5853         lbl = newiTempLabel(NULL);
5854         emitcode ("setb","F1");
5855         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5856         emitcode ("clr","F1");
5857         emitLabel (lbl);
5858
5859         /* load up MA with left */
5860         if (!umult) {
5861                 emitcode("clr","F0");
5862                 lbl = newiTempLabel(NULL);
5863                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5864                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5865                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5866                 emitcode ("xch", "a,b");
5867                 emitcode ("cpl","a");
5868                 emitcode ("add", "a,#1");
5869                 emitcode ("xch", "a,b");
5870                 emitcode ("cpl", "a"); // msb
5871                 emitcode ("addc","a,#0");
5872                 emitcode ("setb","F0");
5873                 emitLabel (lbl);
5874                 emitcode ("mov","ma,b");
5875                 emitcode ("mov","ma,a");
5876         } else {
5877                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5878                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5879         }
5880
5881         /* load up MB with right */
5882         if (!umult) {
5883                 if (AOP_TYPE(right) == AOP_LIT) {
5884                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5885                         if (val < 0) {
5886                                 lbl = newiTempLabel(NULL);
5887                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5888                                 emitcode("setb","F0");
5889                                 emitLabel (lbl);
5890                                 val = -val;
5891                         }
5892                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5893                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5894                 } else {
5895                         lbl = newiTempLabel(NULL);
5896                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5897                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5898                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5899                         emitcode ("xch", "a,b");
5900                         emitcode ("cpl","a");
5901                         emitcode ("add", "a,#1");
5902                         emitcode ("xch", "a,b");
5903                         emitcode ("cpl", "a"); // msb
5904                         emitcode ("addc", "a,#0");
5905                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5906                         emitcode ("setb","F0");
5907                         emitLabel (lbl);
5908                         emitcode ("mov","mb,b");
5909                         emitcode ("mov","mb,a");
5910                 }
5911         } else {
5912                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5913                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5914         }
5915
5916         /* wait for multiplication to finish */
5917         lbl = newiTempLabel(NULL);
5918         emitLabel (lbl);
5919         emitcode("mov","a,mcnt1");
5920         emitcode("anl","a,#!constbyte",0x80);
5921         emitcode("jnz","!tlabel",lbl->key+100);
5922
5923         freeAsmop (left, NULL, ic, TRUE);
5924         freeAsmop (right, NULL, ic,TRUE);
5925         aopOp(result, ic, TRUE, FALSE);
5926
5927         /* if unsigned then simple */
5928         if (umult) {
5929                 aopPut(result,"ma",1);
5930                 aopPut(result,"ma",0);
5931         } else {
5932                 emitcode("push","ma");
5933                 MOVA("ma");
5934                 /* negate result if needed */
5935                 lbl = newiTempLabel(NULL);
5936                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5937                 emitcode("cpl","a");
5938                 emitcode("add","a,#1");
5939                 emitLabel (lbl);
5940                 aopPut(result,"a",0);
5941                 emitcode("pop","acc");
5942                 lbl = newiTempLabel(NULL);
5943                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5944                 emitcode("cpl","a");
5945                 emitcode("addc","a,#0");
5946                 emitLabel (lbl);
5947                 aopPut(result,"a",1);
5948         }
5949         freeAsmop (result, NULL, ic, TRUE);
5950         /* restore EA bit in F1 */
5951         lbl = newiTempLabel(NULL);
5952         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5953         emitcode ("setb","EA");
5954         emitLabel (lbl);
5955         return ;
5956 }
5957
5958 /*-----------------------------------------------------------------*/
5959 /* genDiv - generates code for division                            */
5960 /*-----------------------------------------------------------------*/
5961 static void
5962 genDiv (iCode * ic)
5963 {
5964   operand *left = IC_LEFT (ic);
5965   operand *right = IC_RIGHT (ic);
5966   operand *result = IC_RESULT (ic);
5967
5968   D (emitcode (";", "genDiv"));
5969
5970   /* assign the amsops */
5971   AOP_OP_2 (ic);
5972
5973   /* special cases first */
5974   /* both are bits */
5975   if (AOP_TYPE (left) == AOP_CRY &&
5976       AOP_TYPE (right) == AOP_CRY)
5977     {
5978       genDivbits (left, right, result, ic);
5979       goto release;
5980     }
5981
5982   /* if both are of size == 1 */
5983   if (AOP_SIZE (left) == 1 &&
5984       AOP_SIZE (right) == 1)
5985     {
5986       genDivOneByte (left, right, result, ic);
5987       goto release;
5988     }
5989
5990   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5991           /* use the ds390 ARITHMETIC accel UNIT */
5992           genDivTwoByte (left, right, result, ic);
5993           return ;
5994   }
5995   /* should have been converted to function call */
5996   assert (0);
5997 release:
5998   freeAsmop (result, NULL, ic, TRUE);
5999   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6000   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6001 }
6002
6003 /*-----------------------------------------------------------------*/
6004 /* genModbits :- modulus of bits                                   */
6005 /*-----------------------------------------------------------------*/
6006 static void
6007 genModbits (operand * left,
6008             operand * right,
6009             operand * result,
6010             iCode   * ic)
6011 {
6012   char *l;
6013   bool pushedB;
6014
6015   D (emitcode (";", "genModbits"));
6016
6017   pushedB = pushB ();
6018
6019   /* the result must be bit */
6020   LOAD_AB_FOR_DIV (left, right, l);
6021   emitcode ("div", "ab");
6022   emitcode ("mov", "a,b");
6023   emitcode ("rrc", "a");
6024   aopOp(result, ic, TRUE, FALSE);
6025
6026   popB (pushedB);
6027
6028   aopPut (result, "c", 0);
6029 }
6030
6031 /*-----------------------------------------------------------------*/
6032 /* genModOneByte : 8 bit modulus                                   */
6033 /*-----------------------------------------------------------------*/
6034 static void
6035 genModOneByte (operand * left,
6036                operand * right,
6037                operand * result,
6038                iCode   * ic)
6039 {
6040   bool lUnsigned, rUnsigned, pushedB;
6041   bool runtimeSign, compiletimeSign;
6042   char *l;
6043   symbol *lbl;
6044   int size, offset;
6045
6046   D (emitcode (";", "genModOneByte"));
6047
6048   offset = 1;
6049   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6050   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6051
6052   pushedB = pushB ();
6053
6054   /* signed or unsigned */
6055   if (lUnsigned && rUnsigned)
6056     {
6057       /* unsigned is easy */
6058       LOAD_AB_FOR_DIV (left, right, l);
6059       emitcode ("div", "ab");
6060       aopOp (result, ic, TRUE, FALSE);
6061       aopPut (result, "b", 0);
6062
6063       for (size = AOP_SIZE (result) - 1; size--;)
6064         aopPut (result, zero, offset++);
6065
6066       popB (pushedB);
6067       return;
6068     }
6069
6070   /* signed is a little bit more difficult */
6071
6072   /* now sign adjust for both left & right */
6073
6074   /* modulus: sign of the right operand has no influence on the result! */
6075   if (AOP_TYPE(right) == AOP_LIT)
6076     {
6077       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6078
6079       if (!rUnsigned && val < 0)
6080         emitcode ("mov", "b,#0x%02x", -val);
6081       else
6082         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6083     }
6084   else /* not literal */
6085     {
6086       if (rUnsigned)
6087         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6088       else
6089         {
6090           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6091           lbl = newiTempLabel (NULL);
6092           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6093           emitcode ("cpl", "a");  /* 2's complement */
6094           emitcode ("inc", "a");
6095           emitLabel (lbl);
6096           emitcode ("mov", "b,a");
6097         }
6098     }
6099
6100   /* let's see what's needed: */
6101   /* apply negative sign during runtime */
6102   runtimeSign = FALSE;
6103   /* negative sign from literals */
6104   compiletimeSign = FALSE;
6105
6106   /* sign adjust left side */
6107   if (AOP_TYPE(left) == AOP_LIT)
6108     {
6109       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6110
6111       if (!lUnsigned && val < 0)
6112         {
6113           compiletimeSign = TRUE; /* set sign flag */
6114           emitcode ("mov", "a,#0x%02x", -val);
6115         }
6116       else
6117         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6118     }
6119   else /* ! literal */
6120     {
6121       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6122
6123       if (!lUnsigned)
6124         {
6125           runtimeSign = TRUE;
6126           emitcode ("clr", "F0"); /* clear sign flag */
6127
6128           lbl = newiTempLabel (NULL);
6129           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6130           emitcode ("setb", "F0"); /* set sign flag */
6131           emitcode ("cpl", "a");   /* 2's complement */
6132           emitcode ("inc", "a");
6133           emitLabel (lbl);
6134         }
6135     }
6136
6137   /* now the modulus */
6138   emitcode ("nop", "; workaround for DS80C390 div bug.");
6139   emitcode ("div", "ab");
6140
6141   if (runtimeSign || compiletimeSign)
6142     {
6143       emitcode ("mov", "a,b");
6144       lbl = newiTempLabel (NULL);
6145       if (runtimeSign)
6146         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6147       emitcode ("cpl", "a"); /* lsb 2's complement */
6148       emitcode ("inc", "a");
6149       emitLabel (lbl);
6150
6151       _G.accInUse++;
6152       aopOp (result, ic, TRUE, FALSE);
6153       size = AOP_SIZE (result) - 1;
6154
6155       if (size > 0)
6156         {
6157           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6158              then the result will be in b, a */
6159           emitcode ("mov", "b,a"); /* 1 */
6160           /* msb is 0x00 or 0xff depending on the sign */
6161           if (runtimeSign)
6162             {
6163               emitcode ("mov",  "c,F0");
6164               emitcode ("subb", "a,acc");
6165               emitcode ("xch",  "a,b"); /* 2 */
6166               while (size--)
6167                 aopPut (result, "b", offset++); /* write msb's */
6168             }
6169           else /* compiletimeSign */
6170             while (size--)
6171               aopPut (result, "#0xff", offset++); /* write msb's */
6172         }
6173       aopPut (result, "a", 0); /* 3: write lsb */
6174     }
6175   else
6176     {
6177       _G.accInUse++;
6178       aopOp(result, ic, TRUE, FALSE);
6179       size = AOP_SIZE (result) - 1;
6180
6181       aopPut (result, "b", 0);
6182       while (size--)
6183         aopPut (result, zero, offset++);
6184     }
6185   _G.accInUse--;
6186   popB (pushedB);
6187 }
6188
6189 /*-----------------------------------------------------------------*/
6190 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6191 /*-----------------------------------------------------------------*/
6192 static void genModTwoByte (operand *left, operand *right,
6193                             operand *result, iCode *ic)
6194 {
6195         sym_link *retype = getSpec(operandType(right));
6196         sym_link *letype = getSpec(operandType(left));
6197         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6198         symbol *lbl;
6199
6200         /* load up MA with left */
6201         /* save EA bit in F1 */
6202         lbl = newiTempLabel(NULL);
6203         emitcode ("setb","F1");
6204         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6205         emitcode ("clr","F1");
6206         emitLabel (lbl);
6207
6208         if (!umult) {
6209                 lbl = newiTempLabel(NULL);
6210                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6211                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6212                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6213                 emitcode ("xch", "a,b");
6214                 emitcode ("cpl","a");
6215                 emitcode ("add", "a,#1");
6216                 emitcode ("xch", "a,b");
6217                 emitcode ("cpl", "a"); // msb
6218                 emitcode ("addc","a,#0");
6219                 emitLabel (lbl);
6220                 emitcode ("mov","ma,b");
6221                 emitcode ("mov","ma,a");
6222         } else {
6223                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6224                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6225         }
6226
6227         /* load up MB with right */
6228         if (!umult) {
6229                 if (AOP_TYPE(right) == AOP_LIT) {
6230                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6231                         if (val < 0) {
6232                                 val = -val;
6233                         }
6234                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6235                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6236                 } else {
6237                         lbl = newiTempLabel(NULL);
6238                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6239                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6240                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6241                         emitcode ("xch", "a,b");
6242                         emitcode ("cpl","a");
6243                         emitcode ("add", "a,#1");
6244                         emitcode ("xch", "a,b");
6245                         emitcode ("cpl", "a"); // msb
6246                         emitcode ("addc", "a,#0");
6247                         emitLabel (lbl);
6248                         emitcode ("mov","mb,b");
6249                         emitcode ("mov","mb,a");
6250                 }
6251         } else {
6252                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6253                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6254         }
6255
6256         /* wait for multiplication to finish */
6257         lbl = newiTempLabel(NULL);
6258         emitLabel (lbl);
6259         emitcode("mov","a,mcnt1");
6260         emitcode("anl","a,#!constbyte",0x80);
6261         emitcode("jnz","!tlabel",lbl->key+100);
6262
6263         freeAsmop (left, NULL, ic, TRUE);
6264         freeAsmop (right, NULL, ic,TRUE);
6265         aopOp(result, ic, TRUE, FALSE);
6266
6267         aopPut(result,"mb",1);
6268         aopPut(result,"mb",0);
6269         freeAsmop (result, NULL, ic, TRUE);
6270
6271         /* restore EA bit in F1 */
6272         lbl = newiTempLabel(NULL);
6273         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6274         emitcode ("setb","EA");
6275         emitLabel (lbl);
6276 }
6277
6278 /*-----------------------------------------------------------------*/
6279 /* genMod - generates code for division                            */
6280 /*-----------------------------------------------------------------*/
6281 static void
6282 genMod (iCode * ic)
6283 {
6284   operand *left = IC_LEFT (ic);
6285   operand *right = IC_RIGHT (ic);
6286   operand *result = IC_RESULT (ic);
6287
6288   D (emitcode (";", "genMod"));
6289
6290   /* assign the asmops */
6291   AOP_OP_2 (ic);
6292
6293   /* special cases first */
6294   /* both are bits */
6295   if (AOP_TYPE (left) == AOP_CRY &&
6296       AOP_TYPE (right) == AOP_CRY)
6297     {
6298       genModbits (left, right, result, ic);
6299       goto release;
6300     }
6301
6302   /* if both are of size == 1 */
6303   if (AOP_SIZE (left) == 1 &&
6304       AOP_SIZE (right) == 1)
6305     {
6306       genModOneByte (left, right, result, ic);
6307       goto release;
6308     }
6309
6310   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6311           /* use the ds390 ARITHMETIC accel UNIT */
6312           genModTwoByte (left, right, result, ic);
6313           return ;
6314   }
6315
6316   /* should have been converted to function call */
6317   assert (0);
6318
6319 release:
6320   freeAsmop (result, NULL, ic, TRUE);
6321   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6322   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6323 }
6324
6325 /*-----------------------------------------------------------------*/
6326 /* genIfxJump :- will create a jump depending on the ifx           */
6327 /*-----------------------------------------------------------------*/
6328 static void
6329 genIfxJump (iCode * ic, char *jval)
6330 {
6331   symbol *jlbl;
6332   symbol *tlbl = newiTempLabel (NULL);
6333   char *inst;
6334
6335   D (emitcode (";", "genIfxJump"));
6336
6337   /* if true label then we jump if condition
6338      supplied is true */
6339   if (IC_TRUE (ic))
6340     {
6341       jlbl = IC_TRUE (ic);
6342       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6343                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6344     }
6345   else
6346     {
6347       /* false label is present */
6348       jlbl = IC_FALSE (ic);
6349       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6350                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6351     }
6352   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6353     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6354   else
6355     emitcode (inst, "!tlabel", tlbl->key + 100);
6356   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6357   emitLabel (tlbl);
6358
6359   /* mark the icode as generated */
6360   ic->generated = 1;
6361 }
6362
6363 /*-----------------------------------------------------------------*/
6364 /* genCmp :- greater or less than comparison                       */
6365 /*-----------------------------------------------------------------*/
6366 static void
6367 genCmp (operand * left, operand * right,
6368         iCode * ic, iCode * ifx, int sign)
6369 {
6370   int size, offset = 0;
6371   unsigned long lit = 0L;
6372   operand *result;
6373
6374   D (emitcode (";", "genCmp"));
6375
6376   result = IC_RESULT (ic);
6377
6378   /* if left & right are bit variables */
6379   if (AOP_TYPE (left) == AOP_CRY &&
6380       AOP_TYPE (right) == AOP_CRY)
6381     {
6382       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6383       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6384     }
6385   else
6386     {
6387       /* subtract right from left if at the
6388          end the carry flag is set then we know that
6389          left is greater than right */
6390       size = max (AOP_SIZE (left), AOP_SIZE (right));
6391
6392       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6393       if ((size == 1) && !sign &&
6394           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6395         {
6396           symbol *lbl = newiTempLabel (NULL);
6397           emitcode ("cjne", "%s,%s,!tlabel",
6398                     aopGet (left, offset, FALSE, FALSE, NULL),
6399                     aopGet (right, offset, FALSE, FALSE, NULL),
6400                     lbl->key + 100);
6401           emitLabel (lbl);
6402         }
6403       else
6404         {
6405           if (AOP_TYPE (right) == AOP_LIT)
6406             {
6407               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6408               /* optimize if(x < 0) or if(x >= 0) */
6409               if (lit == 0L)
6410                 {
6411                   if (!sign)
6412                     {
6413                       CLRC;
6414                     }
6415                   else
6416                     {
6417                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6418
6419                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6420                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6421
6422                       aopOp (result, ic, FALSE, FALSE);
6423
6424                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6425                         {
6426                           freeAsmop (result, NULL, ic, TRUE);
6427                           genIfxJump (ifx, "acc.7");
6428                           return;
6429                         }
6430                       else
6431                         {
6432                           emitcode ("rlc", "a");
6433                         }
6434                       goto release_freedLR;
6435                     }
6436                   goto release;
6437                 }
6438             }
6439           CLRC;
6440           while (size--)
6441             {
6442               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6443               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6444               // emitcode (";", "genCmp #2");
6445               if (sign && (size == 0))
6446                 {
6447                   // emitcode (";", "genCmp #3");
6448                   emitcode ("xrl", "a,#!constbyte",0x80);
6449                   if (AOP_TYPE (right) == AOP_LIT)
6450                     {
6451                       unsigned long lit = (unsigned long)
6452                       floatFromVal (AOP (right)->aopu.aop_lit);
6453                       // emitcode (";", "genCmp #3.1");
6454                       emitcode ("subb", "a,#!constbyte",
6455                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6456                     }
6457                   else
6458                     {
6459                       // emitcode (";", "genCmp #3.2");
6460                       saveAccWarn = 0;
6461                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6462                       saveAccWarn = DEFAULT_ACC_WARNING;
6463                       emitcode ("xrl", "b,#!constbyte",0x80);
6464                       emitcode ("subb", "a,b");
6465                     }
6466                 }
6467               else
6468                 {
6469                   const char *s;
6470
6471                   // emitcode (";", "genCmp #4");
6472                   saveAccWarn = 0;
6473                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6474                   saveAccWarn = DEFAULT_ACC_WARNING;
6475
6476                   emitcode ("subb", "a,%s", s);
6477                 }
6478             }
6479         }
6480     }
6481
6482 release:
6483 /* Don't need the left & right operands any more; do need the result. */
6484   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6485   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6486
6487   aopOp (result, ic, FALSE, FALSE);
6488
6489 release_freedLR:
6490
6491   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6492     {
6493       outBitC (result);
6494     }
6495   else
6496     {
6497       /* if the result is used in the next
6498          ifx conditional branch then generate
6499          code a little differently */
6500       if (ifx)
6501         {
6502           genIfxJump (ifx, "c");
6503         }
6504       else
6505         {
6506           outBitC (result);
6507         }
6508       /* leave the result in acc */
6509     }
6510   freeAsmop (result, NULL, ic, TRUE);
6511 }
6512
6513 /*-----------------------------------------------------------------*/
6514 /* genCmpGt :- greater than comparison                             */
6515 /*-----------------------------------------------------------------*/
6516 static void
6517 genCmpGt (iCode * ic, iCode * ifx)
6518 {
6519   operand *left, *right;
6520   sym_link *letype, *retype;
6521   int sign;
6522
6523   D (emitcode (";", "genCmpGt"));
6524
6525   left = IC_LEFT (ic);
6526   right = IC_RIGHT (ic);
6527
6528   letype = getSpec (operandType (left));
6529   retype = getSpec (operandType (right));
6530   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6531
6532   /* assign the left & right amsops */
6533   AOP_OP_2 (ic);
6534
6535   genCmp (right, left, ic, ifx, sign);
6536 }
6537
6538 /*-----------------------------------------------------------------*/
6539 /* genCmpLt - less than comparisons                                */
6540 /*-----------------------------------------------------------------*/
6541 static void
6542 genCmpLt (iCode * ic, iCode * ifx)
6543 {
6544   operand *left, *right;
6545   sym_link *letype, *retype;
6546   int sign;
6547
6548   D (emitcode (";", "genCmpLt"));
6549
6550   left = IC_LEFT (ic);
6551   right = IC_RIGHT (ic);
6552
6553   letype = getSpec (operandType (left));
6554   retype = getSpec (operandType (right));
6555   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6556
6557   /* assign the left & right amsops */
6558   AOP_OP_2 (ic);
6559
6560   genCmp (left, right, ic, ifx, sign);
6561 }
6562
6563 /*-----------------------------------------------------------------*/
6564 /* gencjneshort - compare and jump if not equal                    */
6565 /*-----------------------------------------------------------------*/
6566 static void
6567 gencjneshort (operand * left, operand * right, symbol * lbl)
6568 {
6569   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6570   int offset = 0;
6571   unsigned long lit = 0L;
6572
6573   D (emitcode (";", "gencjneshort"));
6574
6575   /* if the left side is a literal or
6576      if the right is in a pointer register and left
6577      is not */
6578   if ((AOP_TYPE (left) == AOP_LIT) ||
6579       (AOP_TYPE (left) == AOP_IMMD) ||
6580       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6581     {
6582       operand *t = right;
6583       right = left;
6584       left = t;
6585     }
6586
6587   if (AOP_TYPE (right) == AOP_LIT)
6588     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6589
6590   if (opIsGptr (left) || opIsGptr (right))
6591     {
6592       /* We are comparing a generic pointer to something.
6593        * Exclude the generic type byte from the comparison.
6594        */
6595       size--;
6596       D (emitcode (";", "cjneshort: generic ptr special case."););
6597     }
6598
6599
6600   /* if the right side is a literal then anything goes */
6601   if (AOP_TYPE (right) == AOP_LIT &&
6602       AOP_TYPE (left) != AOP_DIR)
6603     {
6604       while (size--)
6605         {
6606           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6607           emitcode ("cjne", "a,%s,!tlabel",
6608                     aopGet (right, offset, FALSE, FALSE, NULL),
6609                     lbl->key + 100);
6610           offset++;
6611         }
6612     }
6613
6614   /* if the right side is in a register or in direct space or
6615      if the left is a pointer register & right is not */
6616   else if (AOP_TYPE (right) == AOP_REG ||
6617            AOP_TYPE (right) == AOP_DIR ||
6618            AOP_TYPE (right) == AOP_LIT ||
6619            AOP_TYPE (right) == AOP_IMMD ||
6620            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6621            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6622     {
6623       while (size--)
6624         {
6625           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6626           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6627               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6628             emitcode ("jnz", "!tlabel", lbl->key + 100);
6629           else
6630             emitcode ("cjne", "a,%s,!tlabel",
6631                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6632                       lbl->key + 100);
6633           offset++;
6634         }
6635     }
6636   else
6637     {
6638       /* right is a pointer reg need both a & b */
6639       while (size--)
6640         {
6641           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6642           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6643           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6644           offset++;
6645         }
6646     }
6647 }
6648
6649 /*-----------------------------------------------------------------*/
6650 /* gencjne - compare and jump if not equal                         */
6651 /*-----------------------------------------------------------------*/
6652 static void
6653 gencjne (operand * left, operand * right, symbol * lbl)
6654 {
6655   symbol *tlbl = newiTempLabel (NULL);
6656
6657   D (emitcode (";", "gencjne"));
6658
6659   gencjneshort (left, right, lbl);
6660
6661   emitcode ("mov", "a,%s", one);
6662   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6663   emitLabel (lbl);
6664   emitcode ("clr", "a");
6665   emitLabel (tlbl);
6666 }
6667
6668 /*-----------------------------------------------------------------*/
6669 /* genCmpEq - generates code for equal to                          */
6670 /*-----------------------------------------------------------------*/
6671 static void
6672 genCmpEq (iCode * ic, iCode * ifx)
6673 {
6674   operand *left, *right, *result;
6675
6676   D (emitcode (";", "genCmpEq"));
6677
6678   AOP_OP_2 (ic);
6679   AOP_SET_LOCALS (ic);
6680
6681   /* if literal, literal on the right or
6682      if the right is in a pointer register and left
6683      is not */
6684   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6685       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6686     {
6687       operand *t = IC_RIGHT (ic);
6688       IC_RIGHT (ic) = IC_LEFT (ic);
6689       IC_LEFT (ic) = t;
6690     }
6691
6692   if (ifx &&                    /* !AOP_SIZE(result) */
6693       OP_SYMBOL (result) &&
6694       OP_SYMBOL (result)->regType == REG_CND)
6695     {
6696       symbol *tlbl;
6697       /* if they are both bit variables */
6698       if (AOP_TYPE (left) == AOP_CRY &&
6699           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6700         {
6701           if (AOP_TYPE (right) == AOP_LIT)
6702             {
6703               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6704               if (lit == 0L)
6705                 {
6706                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6707                   emitcode ("cpl", "c");
6708                 }
6709               else if (lit == 1L)
6710                 {
6711                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6712                 }
6713               else
6714                 {
6715                   emitcode ("clr", "c");
6716                 }
6717               /* AOP_TYPE(right) == AOP_CRY */
6718             }
6719           else
6720             {
6721               symbol *lbl = newiTempLabel (NULL);
6722               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6723               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6724               emitcode ("cpl", "c");
6725               emitLabel (lbl);
6726             }
6727           /* if true label then we jump if condition
6728              supplied is true */
6729           tlbl = newiTempLabel (NULL);
6730           if (IC_TRUE (ifx))
6731             {
6732               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6733               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6734             }
6735           else
6736             {
6737               emitcode ("jc", "!tlabel", tlbl->key + 100);
6738               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6739             }
6740           emitLabel (tlbl);
6741         }
6742       else
6743         {
6744           tlbl = newiTempLabel (NULL);
6745           gencjneshort (left, right, tlbl);
6746           if (IC_TRUE (ifx))
6747             {
6748               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6749               emitLabel (tlbl);
6750             }
6751           else
6752             {
6753               symbol *lbl = newiTempLabel (NULL);
6754               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6755               emitLabel (tlbl);
6756               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6757               emitLabel (lbl);
6758             }
6759         }
6760       /* mark the icode as generated */
6761       ifx->generated = 1;
6762
6763       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6764       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6765       return;
6766     }
6767
6768   /* if they are both bit variables */
6769   if (AOP_TYPE (left) == AOP_CRY &&
6770       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6771     {
6772       if (AOP_TYPE (right) == AOP_LIT)
6773         {
6774           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6775           if (lit == 0L)
6776             {
6777               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6778               emitcode ("cpl", "c");
6779             }
6780           else if (lit == 1L)
6781             {
6782               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6783             }
6784           else
6785             {
6786               emitcode ("clr", "c");
6787             }
6788           /* AOP_TYPE(right) == AOP_CRY */
6789         }
6790       else
6791         {
6792           symbol *lbl = newiTempLabel (NULL);
6793           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6794           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6795           emitcode ("cpl", "c");
6796           emitLabel (lbl);
6797         }
6798
6799       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6800       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6801
6802       aopOp (result, ic, TRUE, FALSE);
6803
6804       /* c = 1 if egal */
6805       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6806         {
6807           outBitC (result);
6808           goto release;
6809         }
6810       if (ifx)
6811         {
6812           genIfxJump (ifx, "c");
6813           goto release;
6814         }
6815       /* if the result is used in an arithmetic operation
6816          then put the result in place */
6817       outBitC (result);
6818     }
6819   else
6820     {
6821       gencjne (left, right, newiTempLabel (NULL));
6822
6823       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6824       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6825
6826       aopOp (result, ic, TRUE, FALSE);
6827
6828       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6829         {
6830           aopPut (result, "a", 0);
6831           goto release;
6832         }
6833       if (ifx)
6834         {
6835           genIfxJump (ifx, "a");
6836           goto release;
6837         }
6838       /* if the result is used in an arithmetic operation
6839          then put the result in place */
6840       if (AOP_TYPE (result) != AOP_CRY)
6841         outAcc (result);
6842       /* leave the result in acc */
6843     }
6844
6845 release:
6846   freeAsmop (result, NULL, ic, TRUE);
6847 }
6848
6849 /*-----------------------------------------------------------------*/
6850 /* ifxForOp - returns the icode containing the ifx for operand     */
6851 /*-----------------------------------------------------------------*/
6852 static iCode *
6853 ifxForOp (operand * op, iCode * ic)
6854 {
6855   /* if true symbol then needs to be assigned */
6856   if (IS_TRUE_SYMOP (op))
6857     return NULL;
6858
6859   /* if this has register type condition and
6860      the next instruction is ifx with the same operand
6861      and live to of the operand is upto the ifx only then */
6862   if (ic->next &&
6863       ic->next->op == IFX &&
6864       IC_COND (ic->next)->key == op->key &&
6865       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6866     return ic->next;
6867
6868   return NULL;
6869 }
6870
6871 /*-----------------------------------------------------------------*/
6872 /* hasInc - operand is incremented before any other use            */
6873 /*-----------------------------------------------------------------*/
6874 static iCode *
6875 hasInc (operand *op, iCode *ic, int osize)
6876 {
6877   sym_link *type = operandType(op);
6878   sym_link *retype = getSpec (type);
6879   iCode *lic = ic->next;
6880   int isize ;
6881
6882   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6883   if (!IS_SYMOP(op)) return NULL;
6884
6885   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6886   if (IS_AGGREGATE(type->next)) return NULL;
6887   if (osize != (isize = getSize(type->next))) return NULL;
6888
6889   while (lic) {
6890       /* if operand of the form op = op + <sizeof *op> */
6891       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6892           isOperandEqual(IC_RESULT(lic),op) &&
6893           isOperandLiteral(IC_RIGHT(lic)) &&
6894           operandLitValue(IC_RIGHT(lic)) == isize) {
6895           return lic;
6896       }
6897       /* if the operand used or deffed */
6898       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6899           return NULL;
6900       }
6901       /* if GOTO or IFX */
6902       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6903       lic = lic->next;
6904   }
6905   return NULL;
6906 }
6907
6908 /*-----------------------------------------------------------------*/
6909 /* genAndOp - for && operation                                     */
6910 /*-----------------------------------------------------------------*/
6911 static void
6912 genAndOp (iCode * ic)
6913 {
6914   operand *left, *right, *result;
6915   symbol *tlbl;
6916
6917   D (emitcode (";", "genAndOp"));
6918
6919   /* note here that && operations that are in an
6920      if statement are taken away by backPatchLabels
6921      only those used in arthmetic operations remain */
6922   AOP_OP_2 (ic);
6923   AOP_SET_LOCALS (ic);
6924
6925   /* if both are bit variables */
6926   if (AOP_TYPE (left) == AOP_CRY &&
6927       AOP_TYPE (right) == AOP_CRY)
6928     {
6929       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6930       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6931       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6932       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6933
6934       aopOp (result,ic,FALSE, FALSE);
6935       outBitC (result);
6936     }
6937   else
6938     {
6939       tlbl = newiTempLabel (NULL);
6940       toBoolean (left);
6941       emitcode ("jz", "!tlabel", tlbl->key + 100);
6942       toBoolean (right);
6943       emitLabel (tlbl);
6944       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6945       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6946
6947       aopOp (result,ic,FALSE, FALSE);
6948       outBitAcc (result);
6949     }
6950
6951     freeAsmop (result, NULL, ic, TRUE);
6952 }
6953
6954
6955 /*-----------------------------------------------------------------*/
6956 /* genOrOp - for || operation                                      */
6957 /*-----------------------------------------------------------------*/
6958 static void
6959 genOrOp (iCode * ic)
6960 {
6961   operand *left, *right, *result;
6962   symbol *tlbl;
6963
6964   D (emitcode (";", "genOrOp"));
6965
6966   /* note here that || operations that are in an
6967      if statement are taken away by backPatchLabels
6968      only those used in arthmetic operations remain */
6969   AOP_OP_2 (ic);
6970   AOP_SET_LOCALS (ic);
6971
6972   /* if both are bit variables */
6973   if (AOP_TYPE (left) == AOP_CRY &&
6974       AOP_TYPE (right) == AOP_CRY)
6975     {
6976       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6977       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6978       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6979       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6980
6981       aopOp (result,ic,FALSE, FALSE);
6982
6983       outBitC (result);
6984     }
6985   else
6986     {
6987       tlbl = newiTempLabel (NULL);
6988       toBoolean (left);
6989       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6990       toBoolean (right);
6991       emitLabel (tlbl);
6992       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6993       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6994
6995       aopOp (result,ic,FALSE, FALSE);
6996
6997       outBitAcc (result);
6998     }
6999
7000   freeAsmop (result, NULL, ic, TRUE);
7001 }
7002
7003 /*-----------------------------------------------------------------*/
7004 /* isLiteralBit - test if lit == 2^n                               */
7005 /*-----------------------------------------------------------------*/
7006 static int
7007 isLiteralBit (unsigned long lit)
7008 {
7009   unsigned long pw[32] =
7010   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7011    0x100L, 0x200L, 0x400L, 0x800L,
7012    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7013    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7014    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7015    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7016    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7017   int idx;
7018
7019   for (idx = 0; idx < 32; idx++)
7020     if (lit == pw[idx])
7021       return idx + 1;
7022   return 0;
7023 }
7024
7025 /*-----------------------------------------------------------------*/
7026 /* continueIfTrue -                                                */
7027 /*-----------------------------------------------------------------*/
7028 static void
7029 continueIfTrue (iCode * ic)
7030 {
7031   if (IC_TRUE (ic))
7032     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7033   ic->generated = 1;
7034 }
7035
7036 /*-----------------------------------------------------------------*/
7037 /* jmpIfTrue -                                                     */
7038 /*-----------------------------------------------------------------*/
7039 static void
7040 jumpIfTrue (iCode * ic)
7041 {
7042   if (!IC_TRUE (ic))
7043     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7044   ic->generated = 1;
7045 }
7046
7047 /*-----------------------------------------------------------------*/
7048 /* jmpTrueOrFalse -                                                */
7049 /*-----------------------------------------------------------------*/
7050 static void
7051 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7052 {
7053   // ugly but optimized by peephole
7054   if (IC_TRUE (ic))
7055     {
7056       symbol *nlbl = newiTempLabel (NULL);
7057       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7058       emitLabel (tlbl);
7059       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7060       emitLabel (nlbl);
7061     }
7062   else
7063     {
7064       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7065       emitLabel (tlbl);
7066     }
7067   ic->generated = 1;
7068 }
7069
7070 // Generate code to perform a bit-wise logic operation
7071 // on two operands in far space (assumed to already have been
7072 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7073 // in far space. This requires pushing the result on the stack
7074 // then popping it into the result.
7075 static void
7076 genFarFarLogicOp(iCode *ic, char *logicOp)
7077 {
7078       int size, resultSize, compSize;
7079       int offset = 0;
7080
7081       TR_AP("#5");
7082       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7083       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7084                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7085
7086       _startLazyDPSEvaluation();
7087       for (size = compSize; (size--); offset++)
7088       {
7089           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7090           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7091           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7092
7093           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7094           emitcode ("push", "acc");
7095       }
7096       _endLazyDPSEvaluation();
7097
7098       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7099       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7100       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7101
7102       resultSize = AOP_SIZE(IC_RESULT(ic));
7103
7104       ADJUST_PUSHED_RESULT(compSize, resultSize);
7105
7106       _startLazyDPSEvaluation();
7107       while (compSize--)
7108       {
7109           emitcode ("pop", "acc");
7110           aopPut (IC_RESULT (ic), "a", compSize);
7111       }
7112       _endLazyDPSEvaluation();
7113       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7114 }
7115
7116
7117 /*-----------------------------------------------------------------*/
7118 /* genAnd  - code for and                                          */
7119 /*-----------------------------------------------------------------*/
7120 static void
7121 genAnd (iCode * ic, iCode * ifx)
7122 {
7123   operand *left, *right, *result;
7124   int size, offset = 0;
7125   unsigned long lit = 0L;
7126   int bytelit = 0;
7127   char buffer[10];
7128   bool pushResult;
7129
7130   D (emitcode (";", "genAnd"));
7131
7132   AOP_OP_3_NOFATAL (ic, pushResult);
7133   AOP_SET_LOCALS (ic);
7134
7135   if (pushResult)
7136   {
7137       genFarFarLogicOp(ic, "anl");
7138       return;
7139   }
7140
7141 #ifdef DEBUG_TYPE
7142   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7143             AOP_TYPE (result),
7144             AOP_TYPE (left), AOP_TYPE (right));
7145   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7146             AOP_SIZE (result),
7147             AOP_SIZE (left), AOP_SIZE (right));
7148 #endif
7149
7150   /* if left is a literal & right is not then exchange them */
7151   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7152 #ifdef LOGIC_OPS_BROKEN
7153     ||  AOP_NEEDSACC (left)
7154 #endif
7155     )
7156     {
7157       operand *tmp = right;
7158       right = left;
7159       left = tmp;
7160     }
7161
7162   /* if result = right then exchange left and right */
7163   if (sameRegs (AOP (result), AOP (right)))
7164     {
7165       operand *tmp = right;
7166       right = left;
7167       left = tmp;
7168     }
7169
7170   /* if right is bit then exchange them */
7171   if (AOP_TYPE (right) == AOP_CRY &&
7172       AOP_TYPE (left) != AOP_CRY)
7173     {
7174       operand *tmp = right;
7175       right = left;
7176       left = tmp;
7177     }
7178   if (AOP_TYPE (right) == AOP_LIT)
7179     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7180
7181   size = AOP_SIZE (result);
7182
7183   // if(bit & yy)
7184   // result = bit & yy;
7185   if (AOP_TYPE (left) == AOP_CRY)
7186     {
7187       // c = bit & literal;
7188       if (AOP_TYPE (right) == AOP_LIT)
7189         {
7190           if (lit & 1)
7191             {
7192               if (size && sameRegs (AOP (result), AOP (left)))
7193                 // no change
7194                 goto release;
7195               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7196             }
7197           else
7198             {
7199               // bit(result) = 0;
7200               if (size && (AOP_TYPE (result) == AOP_CRY))
7201                 {
7202                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7203                   goto release;
7204                 }
7205               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7206                 {
7207                   jumpIfTrue (ifx);
7208                   goto release;
7209                 }
7210               emitcode ("clr", "c");
7211             }
7212         }
7213       else
7214         {
7215           if (AOP_TYPE (right) == AOP_CRY)
7216             {
7217               // c = bit & bit;
7218               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7219               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7220             }
7221           else
7222             {
7223               // c = bit & val;
7224               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7225               // c = lsb
7226               emitcode ("rrc", "a");
7227               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7228             }
7229         }
7230       // bit = c
7231       // val = c
7232       if (size)
7233         outBitC (result);
7234       // if(bit & ...)
7235       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7236         genIfxJump (ifx, "c");
7237       goto release;
7238     }
7239
7240   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7241   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7242   if ((AOP_TYPE (right) == AOP_LIT) &&
7243       (AOP_TYPE (result) == AOP_CRY) &&
7244       (AOP_TYPE (left) != AOP_CRY))
7245     {
7246       int posbit = isLiteralBit (lit);
7247       /* left &  2^n */
7248       if (posbit)
7249         {
7250           posbit--;
7251           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7252           // bit = left & 2^n
7253           if (size)
7254             {
7255               switch (posbit & 0x07)
7256                 {
7257                   case 0: emitcode ("rrc", "a");
7258                           break;
7259                   case 7: emitcode ("rlc", "a");
7260                           break;
7261                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7262                           break;
7263                 }
7264             }
7265           // if(left &  2^n)
7266           else
7267             {
7268               if (ifx)
7269                 {
7270                   SNPRINTF (buffer, sizeof(buffer),
7271                             "acc.%d", posbit & 0x07);
7272                   genIfxJump (ifx, buffer);
7273                 }
7274               else
7275                 {
7276                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7277                 }
7278               goto release;
7279             }
7280         }
7281       else
7282         {
7283           symbol *tlbl = newiTempLabel (NULL);
7284           int sizel = AOP_SIZE (left);
7285           if (size)
7286             emitcode ("setb", "c");
7287           while (sizel--)
7288             {
7289               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7290                 {
7291                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7292                   // byte ==  2^n ?
7293                   if ((posbit = isLiteralBit (bytelit)) != 0)
7294                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7295                   else
7296                     {
7297                       if (bytelit != 0x0FFL)
7298                         emitcode ("anl", "a,%s",
7299                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7300                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7301                     }
7302                 }
7303               offset++;
7304             }
7305           // bit = left & literal
7306           if (size)
7307             {
7308               emitcode ("clr", "c");
7309               emitLabel (tlbl);
7310             }
7311           // if(left & literal)
7312           else
7313             {
7314               if (ifx)
7315                 jmpTrueOrFalse (ifx, tlbl);
7316               else
7317                 emitLabel (tlbl);
7318               goto release;
7319             }
7320         }
7321       outBitC (result);
7322       goto release;
7323     }
7324
7325   /* if left is same as result */
7326   if (sameRegs (AOP (result), AOP (left)))
7327     {
7328       for (; size--; offset++)
7329         {
7330           if (AOP_TYPE (right) == AOP_LIT)
7331             {
7332               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7333               if (bytelit == 0x0FF)
7334                 {
7335                   /* dummy read of volatile operand */
7336                   if (isOperandVolatile (left, FALSE))
7337                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7338                   else
7339                     continue;
7340                 }
7341               else if (bytelit == 0)
7342                 {
7343                   aopPut (result, zero, offset);
7344                 }
7345               else if (IS_AOP_PREG (result))
7346                 {
7347                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7348                   emitcode ("anl", "a,%s",
7349                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7350                   aopPut (result, "a", offset);
7351                 }
7352               else
7353                 emitcode ("anl", "%s,%s",
7354                           aopGet (left, offset, FALSE, TRUE, NULL),
7355                           aopGet (right, offset, FALSE, FALSE, NULL));
7356             }
7357           else
7358             {
7359               if (AOP_TYPE (left) == AOP_ACC)
7360                 {
7361                   if (offset)
7362                     emitcode("mov", "a,b");
7363                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7364                 }
7365               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7366                 {
7367                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7368                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7369                   emitcode ("anl", "a,b");
7370                   aopPut (result, "a", offset);
7371                 }
7372               else if (aopGetUsesAcc (left, offset))
7373                 {
7374                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7375                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7376                   aopPut (result, "a", offset);
7377                 }
7378               else
7379                 {
7380                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7381                   if (IS_AOP_PREG (result))
7382                     {
7383                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7384                       aopPut (result, "a", offset);
7385                     }
7386                   else
7387                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7388                 }
7389             }
7390         }
7391     }
7392   else
7393     {
7394       // left & result in different registers
7395       if (AOP_TYPE (result) == AOP_CRY)
7396         {
7397           // result = bit
7398           // if(size), result in bit
7399           // if(!size && ifx), conditional oper: if(left & right)
7400           symbol *tlbl = newiTempLabel (NULL);
7401           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7402           if (size)
7403             emitcode ("setb", "c");
7404           while (sizer--)
7405             {
7406               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7407                   && AOP_TYPE(left)==AOP_ACC)
7408                 {
7409                   if (offset)
7410                     emitcode("mov", "a,b");
7411                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7412                 }
7413               else if (AOP_TYPE(left)==AOP_ACC)
7414                 {
7415                   if (!offset)
7416                     {
7417                       bool pushedB = pushB ();
7418                       emitcode("mov", "b,a");
7419                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7420                       emitcode("anl", "a,b");
7421                       popB (pushedB);
7422                     }
7423                   else
7424                     {
7425                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7426                       emitcode("anl", "a,b");
7427                     }
7428                 }
7429               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7430                 {
7431                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7432                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7433                   emitcode ("anl", "a,b");
7434                 }
7435               else if (aopGetUsesAcc (left, offset))
7436                 {
7437                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7438                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7439                 }
7440               else
7441                 {
7442                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7443                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7444                 }
7445
7446               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7447               offset++;
7448             }
7449           if (size)
7450             {
7451               CLRC;
7452               emitLabel (tlbl);
7453               outBitC (result);
7454             }
7455           else if (ifx)
7456             jmpTrueOrFalse (ifx, tlbl);
7457           else
7458             emitLabel (tlbl);
7459         }
7460       else
7461         {
7462           for (; (size--); offset++)
7463             {
7464               // normal case
7465               // result = left & right
7466               if (AOP_TYPE (right) == AOP_LIT)
7467                 {
7468                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7469                   if (bytelit == 0x0FF)
7470                     {
7471                       aopPut (result,
7472                               aopGet (left, offset, FALSE, FALSE, NULL),
7473                               offset);
7474                       continue;
7475                     }
7476                   else if (bytelit == 0)
7477                     {
7478                       /* dummy read of volatile operand */
7479                       if (isOperandVolatile (left, FALSE))
7480                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7481                       aopPut (result, zero, offset);
7482                       continue;
7483                     }
7484                   else if (AOP_TYPE (left) == AOP_ACC)
7485                     {
7486                       if (!offset)
7487                         {
7488                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7489                           aopPut (result, "a", offset);
7490                           continue;
7491                         }
7492                       else
7493                         {
7494                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7495                           aopPut (result, "b", offset);
7496                           continue;
7497                         }
7498                     }
7499                 }
7500               // faster than result <- left, anl result,right
7501               // and better if result is SFR
7502               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7503                   && AOP_TYPE(left)==AOP_ACC)
7504                 {
7505                   if (offset)
7506                     emitcode("mov", "a,b");
7507                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7508                 }
7509               else if (AOP_TYPE(left)==AOP_ACC)
7510                 {
7511                   if (!offset)
7512                     {
7513                       bool pushedB = pushB ();
7514                       emitcode("mov", "b,a");
7515                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7516                       emitcode("anl", "a,b");
7517                       popB (pushedB);
7518                     }
7519                   else
7520                     {
7521                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7522                       emitcode("anl", "a,b");
7523                     }
7524                 }
7525               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7526                 {
7527                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7528                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7529                   emitcode ("anl", "a,b");
7530                 }
7531               else if (aopGetUsesAcc (left, offset))
7532                 {
7533                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7534                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7535                 }
7536               else
7537                 {
7538                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7539                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7540                 }
7541               aopPut (result, "a", offset);
7542             }
7543         }
7544     }
7545
7546 release:
7547   freeAsmop (result, NULL, ic, TRUE);
7548   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7549   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7550 }
7551
7552 /*-----------------------------------------------------------------*/
7553 /* genOr  - code for or                                            */
7554 /*-----------------------------------------------------------------*/
7555 static void
7556 genOr (iCode * ic, iCode * ifx)
7557 {
7558   operand *left, *right, *result;
7559   int size, offset = 0;
7560   unsigned long lit = 0L;
7561   int bytelit = 0;
7562   bool     pushResult;
7563
7564   D (emitcode (";", "genOr"));
7565
7566   AOP_OP_3_NOFATAL (ic, pushResult);
7567   AOP_SET_LOCALS (ic);
7568
7569   if (pushResult)
7570   {
7571       genFarFarLogicOp(ic, "orl");
7572       return;
7573   }
7574
7575
7576 #ifdef DEBUG_TYPE
7577   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7578             AOP_TYPE (result),
7579             AOP_TYPE (left), AOP_TYPE (right));
7580   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7581             AOP_SIZE (result),
7582             AOP_SIZE (left), AOP_SIZE (right));
7583 #endif
7584
7585   /* if left is a literal & right is not then exchange them */
7586   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7587 #ifdef LOGIC_OPS_BROKEN
7588    || AOP_NEEDSACC (left) // I think this is a net loss now.
7589 #endif
7590       )
7591     {
7592       operand *tmp = right;
7593       right = left;
7594       left = tmp;
7595     }
7596
7597   /* if result = right then exchange them */
7598   if (sameRegs (AOP (result), AOP (right)))
7599     {
7600       operand *tmp = right;
7601       right = left;
7602       left = tmp;
7603     }
7604
7605   /* if right is bit then exchange them */
7606   if (AOP_TYPE (right) == AOP_CRY &&
7607       AOP_TYPE (left) != AOP_CRY)
7608     {
7609       operand *tmp = right;
7610       right = left;
7611       left = tmp;
7612     }
7613   if (AOP_TYPE (right) == AOP_LIT)
7614     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7615
7616   size = AOP_SIZE (result);
7617
7618   // if(bit | yy)
7619   // xx = bit | yy;
7620   if (AOP_TYPE (left) == AOP_CRY)
7621     {
7622       if (AOP_TYPE (right) == AOP_LIT)
7623         {
7624           // c = bit | literal;
7625           if (lit)
7626             {
7627               // lit != 0 => result = 1
7628               if (AOP_TYPE (result) == AOP_CRY)
7629                 {
7630                   if (size)
7631                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7632                   else if (ifx)
7633                     continueIfTrue (ifx);
7634                   goto release;
7635                 }
7636               emitcode ("setb", "c");
7637             }
7638           else
7639             {
7640               // lit == 0 => result = left
7641               if (size && sameRegs (AOP (result), AOP (left)))
7642                 goto release;
7643               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7644             }
7645         }
7646       else
7647         {
7648           if (AOP_TYPE (right) == AOP_CRY)
7649             {
7650               // c = bit | bit;
7651               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7652               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7653             }
7654           else
7655             {
7656               // c = bit | val;
7657               symbol *tlbl = newiTempLabel (NULL);
7658               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7659                 emitcode ("setb", "c");
7660               emitcode ("jb", "%s,!tlabel",
7661                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7662               toBoolean (right);
7663               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7664               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7665                 {
7666                   jmpTrueOrFalse (ifx, tlbl);
7667                   goto release;
7668                 }
7669               else
7670                 {
7671                   CLRC;
7672                   emitLabel (tlbl);
7673                 }
7674             }
7675         }
7676       // bit = c
7677       // val = c
7678       if (size)
7679         outBitC (result);
7680       // if(bit | ...)
7681       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7682            genIfxJump (ifx, "c");
7683       goto release;
7684     }
7685
7686   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7687   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7688   if ((AOP_TYPE (right) == AOP_LIT) &&
7689       (AOP_TYPE (result) == AOP_CRY) &&
7690       (AOP_TYPE (left) != AOP_CRY))
7691     {
7692       if (lit)
7693         {
7694           // result = 1
7695           if (size)
7696             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7697           else
7698             continueIfTrue (ifx);
7699           goto release;
7700         }
7701       else
7702         {
7703           // lit = 0, result = boolean(left)
7704           if (size)
7705             emitcode ("setb", "c");
7706           toBoolean (right);
7707           if (size)
7708             {
7709               symbol *tlbl = newiTempLabel (NULL);
7710               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7711               CLRC;
7712               emitLabel (tlbl);
7713             }
7714           else
7715             {
7716               genIfxJump (ifx, "a");
7717               goto release;
7718             }
7719         }
7720       outBitC (result);
7721       goto release;
7722     }
7723
7724   /* if left is same as result */
7725   if (sameRegs (AOP (result), AOP (left)))
7726     {
7727       for (; size--; offset++)
7728         {
7729           if (AOP_TYPE (right) == AOP_LIT)
7730             {
7731               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7732               if (bytelit == 0)
7733                 {
7734                   /* dummy read of volatile operand */
7735                   if (isOperandVolatile (left, FALSE))
7736                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7737                   else
7738                     continue;
7739                 }
7740               else if (bytelit == 0x0FF)
7741                 {
7742                   aopPut (result, "#0xFF", offset);
7743                 }
7744               else if (IS_AOP_PREG (left))
7745                 {
7746                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7747                   emitcode ("orl", "a,%s",
7748                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7749                   aopPut (result, "a", offset);
7750                 }
7751               else
7752                 {
7753                   emitcode ("orl", "%s,%s",
7754                             aopGet (left, offset, FALSE, TRUE, NULL),
7755                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7756                 }
7757             }
7758           else
7759             {
7760               if (AOP_TYPE (left) == AOP_ACC)
7761                 {
7762                   if (offset)
7763                     emitcode("mov", "a,b");
7764                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7765                 }
7766               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7767                 {
7768                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7769                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7770                   emitcode ("orl", "a,b");
7771                   aopPut (result, "a", offset);
7772                 }
7773               else if (aopGetUsesAcc (left, offset))
7774                 {
7775                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7776                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7777                   aopPut (result, "a", offset);
7778                 }
7779               else
7780                 {
7781                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7782                   if (IS_AOP_PREG (left))
7783                     {
7784                       emitcode ("orl", "a,%s",
7785                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7786                       aopPut (result, "a", offset);
7787                     }
7788                   else
7789                     {
7790                       emitcode ("orl", "%s,a",
7791                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7792                     }
7793                 }
7794             }
7795         }
7796     }
7797   else
7798     {
7799       // left & result in different registers
7800       if (AOP_TYPE (result) == AOP_CRY)
7801         {
7802           // result = bit
7803           // if(size), result in bit
7804           // if(!size && ifx), conditional oper: if(left | right)
7805           symbol *tlbl = newiTempLabel (NULL);
7806           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7807           if (size)
7808             emitcode ("setb", "c");
7809           while (sizer--)
7810             {
7811               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7812                   && AOP_TYPE(left)==AOP_ACC)
7813                 {
7814                   if (offset)
7815                     emitcode("mov", "a,b");
7816                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7817                 }
7818               else if (AOP_TYPE(left)==AOP_ACC)
7819                 {
7820                   if (!offset)
7821                     {
7822                       bool pushedB = pushB ();
7823                       emitcode("mov", "b,a");
7824                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7825                       emitcode("orl", "a,b");
7826                       popB (pushedB);
7827                     }
7828                   else
7829                     {
7830                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7831                       emitcode("orl", "a,b");
7832                     }
7833                 }
7834               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7835                 {
7836                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7837                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7838                   emitcode ("orl", "a,b");
7839                 }
7840               else if (aopGetUsesAcc (left, offset))
7841                 {
7842                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7843                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7844                 }
7845               else
7846                 {
7847                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7848                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7849               }
7850
7851               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7852               offset++;
7853             }
7854           if (size)
7855             {
7856               CLRC;
7857               emitLabel (tlbl);
7858               outBitC (result);
7859             }
7860           else if (ifx)
7861             jmpTrueOrFalse (ifx, tlbl);
7862           else
7863             emitLabel (tlbl);
7864         }
7865       else
7866         {
7867             _startLazyDPSEvaluation();
7868           for (; (size--); offset++)
7869             {
7870               // normal case
7871               // result = left | right
7872               if (AOP_TYPE (right) == AOP_LIT)
7873                 {
7874                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7875                   if (bytelit == 0)
7876                     {
7877                       aopPut (result,
7878                               aopGet (left, offset, FALSE, FALSE, NULL),
7879                               offset);
7880                       continue;
7881                     }
7882                   else if (bytelit == 0x0FF)
7883                     {
7884                       /* dummy read of volatile operand */
7885                       if (isOperandVolatile (left, FALSE))
7886                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7887                       aopPut (result, "#0xFF", offset);
7888                       continue;
7889                     }
7890                 }
7891               // faster than result <- left, orl result,right
7892               // and better if result is SFR
7893               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7894                   && AOP_TYPE(left)==AOP_ACC)
7895                 {
7896                   if (offset)
7897                     emitcode("mov", "a,b");
7898                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7899                 }
7900               else if (AOP_TYPE(left)==AOP_ACC)
7901                 {
7902                   if (!offset)
7903                     {
7904                       bool pushedB = pushB ();
7905                       emitcode("mov", "b,a");
7906                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7907                       emitcode("orl", "a,b");
7908                       popB (pushedB);
7909                     }
7910                   else
7911                     {
7912                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7913                       emitcode("orl", "a,b");
7914                     }
7915                 }
7916               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7917                 {
7918                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7919                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7920                   emitcode ("orl", "a,b");
7921                 }
7922               else if (aopGetUsesAcc (left, offset))
7923                 {
7924                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7925                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7926                 }
7927               else
7928                 {
7929                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7930                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7931                 }
7932               aopPut (result, "a", offset);
7933             }
7934             _endLazyDPSEvaluation();
7935         }
7936     }
7937
7938 release:
7939   freeAsmop (result, NULL, ic, TRUE);
7940   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7941   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7942 }
7943
7944 /*-----------------------------------------------------------------*/
7945 /* genXor - code for xclusive or                                   */
7946 /*-----------------------------------------------------------------*/
7947 static void
7948 genXor (iCode * ic, iCode * ifx)
7949 {
7950   operand *left, *right, *result;
7951   int size, offset = 0;
7952   unsigned long lit = 0L;
7953   int bytelit = 0;
7954   bool pushResult;
7955
7956   D (emitcode (";", "genXor"));
7957
7958   AOP_OP_3_NOFATAL (ic, pushResult);
7959   AOP_SET_LOCALS (ic);
7960
7961   if (pushResult)
7962   {
7963       genFarFarLogicOp(ic, "xrl");
7964       return;
7965   }
7966
7967 #ifdef DEBUG_TYPE
7968   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7969             AOP_TYPE (result),
7970             AOP_TYPE (left), AOP_TYPE (right));
7971   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7972             AOP_SIZE (result),
7973             AOP_SIZE (left), AOP_SIZE (right));
7974 #endif
7975
7976   /* if left is a literal & right is not ||
7977      if left needs acc & right does not */
7978   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7979 #ifdef LOGIC_OPS_BROKEN
7980       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7981 #endif
7982      )
7983     {
7984       operand *tmp = right;
7985       right = left;
7986       left = tmp;
7987     }
7988
7989   /* if result = right then exchange them */
7990   if (sameRegs (AOP (result), AOP (right)))
7991     {
7992       operand *tmp = right;
7993       right = left;
7994       left = tmp;
7995     }
7996
7997   /* if right is bit then exchange them */
7998   if (AOP_TYPE (right) == AOP_CRY &&
7999       AOP_TYPE (left) != AOP_CRY)
8000     {
8001       operand *tmp = right;
8002       right = left;
8003       left = tmp;
8004     }
8005   if (AOP_TYPE (right) == AOP_LIT)
8006     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8007
8008   size = AOP_SIZE (result);
8009
8010   // if(bit ^ yy)
8011   // xx = bit ^ yy;
8012   if (AOP_TYPE (left) == AOP_CRY)
8013     {
8014       if (AOP_TYPE (right) == AOP_LIT)
8015         {
8016           // c = bit & literal;
8017           if (lit >> 1)
8018             {
8019               // lit>>1  != 0 => result = 1
8020               if (AOP_TYPE (result) == AOP_CRY)
8021                 {
8022                   if (size)
8023                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8024                   else if (ifx)
8025                     continueIfTrue (ifx);
8026                   goto release;
8027                 }
8028               emitcode ("setb", "c");
8029             }
8030           else
8031             {
8032               // lit == (0 or 1)
8033               if (lit == 0)
8034                 {
8035                   // lit == 0, result = left
8036                   if (size && sameRegs (AOP (result), AOP (left)))
8037                     goto release;
8038                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8039                 }
8040               else
8041                 {
8042                   // lit == 1, result = not(left)
8043                   if (size && sameRegs (AOP (result), AOP (left)))
8044                     {
8045                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8046                       goto release;
8047                     }
8048                   else
8049                     {
8050                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8051                       emitcode ("cpl", "c");
8052                     }
8053                 }
8054             }
8055         }
8056       else
8057         {
8058           // right != literal
8059           symbol *tlbl = newiTempLabel (NULL);
8060           if (AOP_TYPE (right) == AOP_CRY)
8061             {
8062               // c = bit ^ bit;
8063               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8064             }
8065           else
8066             {
8067               int sizer = AOP_SIZE (right);
8068               // c = bit ^ val
8069               // if val>>1 != 0, result = 1
8070               emitcode ("setb", "c");
8071               while (sizer)
8072                 {
8073                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8074                   if (sizer == 1)
8075                     // test the msb of the lsb
8076                     emitcode ("anl", "a,#!constbyte",0xfe);
8077                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8078                   sizer--;
8079                 }
8080               // val = (0,1)
8081               emitcode ("rrc", "a");
8082             }
8083           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8084           emitcode ("cpl", "c");
8085           emitLabel (tlbl);
8086         }
8087       // bit = c
8088       // val = c
8089       if (size)
8090         outBitC (result);
8091       // if(bit | ...)
8092       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8093         genIfxJump (ifx, "c");
8094       goto release;
8095     }
8096
8097   /* if left is same as result */
8098   if (sameRegs (AOP (result), AOP (left)))
8099     {
8100       for (; size--; offset++)
8101         {
8102           if (AOP_TYPE (right) == AOP_LIT)
8103             {
8104               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8105               if (bytelit == 0)
8106                 {
8107                   /* dummy read of volatile operand */
8108                   if (isOperandVolatile (left, FALSE))
8109                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8110                   else
8111                     continue;
8112                 }
8113               else if (IS_AOP_PREG (left))
8114                 {
8115                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8116                   emitcode ("xrl", "a,%s",
8117                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8118                   aopPut (result, "a", offset);
8119                 }
8120               else
8121                 {
8122                   emitcode ("xrl", "%s,%s",
8123                             aopGet (left, offset, FALSE, TRUE, NULL),
8124                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8125                 }
8126             }
8127           else
8128             {
8129               if (AOP_TYPE (left) == AOP_ACC)
8130                 {
8131                   if (offset)
8132                     emitcode("mov", "a,b");
8133                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8134                 }
8135               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8136                 {
8137                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8138                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8139                   emitcode ("xrl", "a,b");
8140                   aopPut (result, "a", offset);
8141                 }
8142               else if (aopGetUsesAcc (left, offset))
8143                 {
8144                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8145                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8146                   aopPut (result, "a", offset);
8147                 }
8148               else
8149                 {
8150                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8151                   if (IS_AOP_PREG (left))
8152                     {
8153                       emitcode ("xrl", "a,%s",
8154                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8155                       aopPut (result, "a", offset);
8156                     }
8157                   else
8158                     emitcode ("xrl", "%s,a",
8159                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8160                 }
8161             }
8162         }
8163     }
8164   else
8165     {
8166       // left & result in different registers
8167       if (AOP_TYPE (result) == AOP_CRY)
8168         {
8169           // result = bit
8170           // if(size), result in bit
8171           // if(!size && ifx), conditional oper: if(left ^ right)
8172           symbol *tlbl = newiTempLabel (NULL);
8173           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8174
8175           if (size)
8176             emitcode ("setb", "c");
8177           while (sizer--)
8178             {
8179               if ((AOP_TYPE (right) == AOP_LIT) &&
8180                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8181                 {
8182                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8183                 }
8184               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8185                   && AOP_TYPE(left)==AOP_ACC)
8186                 {
8187                   if (offset)
8188                     emitcode("mov", "a,b");
8189                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8190                 }
8191               else if (AOP_TYPE(left)==AOP_ACC)
8192                 {
8193                   if (!offset)
8194                     {
8195                       bool pushedB = pushB ();
8196                       emitcode("mov", "b,a");
8197                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8198                       emitcode("xrl", "a,b");
8199                       popB (pushedB);
8200                     }
8201                   else
8202                     {
8203                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8204                       emitcode("xrl", "a,b");
8205                     }
8206                 }
8207               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8208                 {
8209                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8210                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8211                   emitcode ("xrl", "a,b");
8212                 }
8213               else if (aopGetUsesAcc (left, offset))
8214                 {
8215                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8216                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8217                 }
8218               else
8219                 {
8220                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8221                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8222                 }
8223
8224               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8225               offset++;
8226             }
8227           if (size)
8228             {
8229               CLRC;
8230               emitLabel (tlbl);
8231               outBitC (result);
8232             }
8233           else if (ifx)
8234             jmpTrueOrFalse (ifx, tlbl);
8235         }
8236       else
8237         {
8238         for (; (size--); offset++)
8239           {
8240             // normal case
8241             // result = left ^ right
8242             if (AOP_TYPE (right) == AOP_LIT)
8243               {
8244                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8245                 if (bytelit == 0)
8246                   {
8247                     aopPut (result,
8248                             aopGet (left, offset, FALSE, FALSE, NULL),
8249                             offset);
8250                     continue;
8251                   }
8252                 D (emitcode (";", "better literal XOR."));
8253                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8254                 emitcode ("xrl", "a, %s",
8255                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8256               }
8257             else
8258               {
8259                 // faster than result <- left, anl result,right
8260                 // and better if result is SFR
8261                 if (AOP_TYPE (left) == AOP_ACC)
8262                   {
8263                     emitcode ("xrl", "a,%s",
8264                               aopGet (right, offset,
8265                                       FALSE, FALSE, DP2_RESULT_REG));
8266                   }
8267                 else
8268                   {
8269                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8270                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8271                       {
8272                           emitcode("mov", "b,a");
8273                           rOp = "b";
8274                       }
8275
8276                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8277                       emitcode ("xrl", "a,%s", rOp);
8278                   }
8279               }
8280             aopPut (result, "a", offset);
8281           }
8282         }
8283     }
8284
8285 release:
8286   freeAsmop (result, NULL, ic, TRUE);
8287   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8288   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8289 }
8290
8291 /*-----------------------------------------------------------------*/
8292 /* genInline - write the inline code out                           */
8293 /*-----------------------------------------------------------------*/
8294 static void
8295 genInline (iCode * ic)
8296 {
8297   char *buffer, *bp, *bp1;
8298
8299   D (emitcode (";", "genInline"));
8300
8301   _G.inLine += (!options.asmpeep);
8302
8303   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8304
8305   /* emit each line as a code */
8306   while (*bp)
8307     {
8308       if (*bp == '\n')
8309         {
8310           *bp++ = '\0';
8311           emitcode (bp1, "");
8312           bp1 = bp;
8313         }
8314       else
8315         {
8316           /* Add \n for labels, not dirs such as c:\mydir */
8317           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8318             {
8319               bp++;
8320               *bp = '\0';
8321               bp++;
8322               emitcode (bp1, "");
8323               bp1 = bp;
8324             }
8325           else
8326             bp++;
8327         }
8328     }
8329   if (bp1 != bp)
8330     emitcode (bp1, "");
8331   /*     emitcode("",buffer); */
8332   _G.inLine -= (!options.asmpeep);
8333 }
8334
8335 /*-----------------------------------------------------------------*/
8336 /* genRRC - rotate right with carry                                */
8337 /*-----------------------------------------------------------------*/
8338 static void
8339 genRRC (iCode * ic)
8340 {
8341   operand *left, *result;
8342   int     size, offset;
8343   char *l;
8344
8345   D (emitcode (";", "genRRC"));
8346
8347   /* rotate right with carry */
8348   left = IC_LEFT (ic);
8349   result = IC_RESULT (ic);
8350   aopOp (left, ic, FALSE, FALSE);
8351   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8352
8353   /* move it to the result */
8354   size = AOP_SIZE (result);
8355   offset = size - 1;
8356   CLRC;
8357
8358   _startLazyDPSEvaluation ();
8359   while (size--)
8360     {
8361       l = aopGet (left, offset, FALSE, FALSE, NULL);
8362       MOVA (l);
8363       emitcode ("rrc", "a");
8364       if (AOP_SIZE (result) > 1)
8365         aopPut (result, "a", offset--);
8366     }
8367   _endLazyDPSEvaluation ();
8368
8369   /* now we need to put the carry into the
8370      highest order byte of the result */
8371   if (AOP_SIZE (result) > 1)
8372     {
8373       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8374       MOVA (l);
8375     }
8376   emitcode ("mov", "acc.7,c");
8377   aopPut (result, "a", AOP_SIZE (result) - 1);
8378   freeAsmop (result, NULL, ic, TRUE);
8379   freeAsmop (left, NULL, ic, TRUE);
8380 }
8381
8382 /*-----------------------------------------------------------------*/
8383 /* genRLC - generate code for rotate left with carry               */
8384 /*-----------------------------------------------------------------*/
8385 static void
8386 genRLC (iCode * ic)
8387 {
8388   operand *left, *result;
8389   int size, offset;
8390   char *l;
8391
8392   D (emitcode (";", "genRLC"));
8393
8394   /* rotate right with carry */
8395   left = IC_LEFT (ic);
8396   result = IC_RESULT (ic);
8397   aopOp (left, ic, FALSE, FALSE);
8398   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8399
8400   /* move it to the result */
8401   size = AOP_SIZE (result);
8402   offset = 0;
8403   if (size--)
8404     {
8405       l = aopGet (left, offset, FALSE, FALSE, NULL);
8406       MOVA (l);
8407       emitcode ("add", "a,acc");
8408       if (AOP_SIZE (result) > 1)
8409         {
8410           aopPut (result, "a", offset++);
8411         }
8412
8413       _startLazyDPSEvaluation ();
8414       while (size--)
8415         {
8416           l = aopGet (left, offset, FALSE, FALSE, NULL);
8417           MOVA (l);
8418           emitcode ("rlc", "a");
8419           if (AOP_SIZE (result) > 1)
8420             aopPut (result, "a", offset++);
8421         }
8422       _endLazyDPSEvaluation ();
8423     }
8424   /* now we need to put the carry into the
8425      highest order byte of the result */
8426   if (AOP_SIZE (result) > 1)
8427     {
8428       l = aopGet (result, 0, FALSE, FALSE, NULL);
8429       MOVA (l);
8430     }
8431   emitcode ("mov", "acc.0,c");
8432   aopPut (result, "a", 0);
8433   freeAsmop (result, NULL, ic, TRUE);
8434   freeAsmop (left, NULL, ic, TRUE);
8435 }
8436
8437 /*-----------------------------------------------------------------*/
8438 /* genGetHbit - generates code get highest order bit               */
8439 /*-----------------------------------------------------------------*/
8440 static void
8441 genGetHbit (iCode * ic)
8442 {
8443   operand *left, *result;
8444
8445   D (emitcode (";", "genGetHbit"));
8446
8447   left = IC_LEFT (ic);
8448   result = IC_RESULT (ic);
8449   aopOp (left, ic, FALSE, FALSE);
8450   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8451
8452   /* get the highest order byte into a */
8453   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8454   if (AOP_TYPE (result) == AOP_CRY)
8455     {
8456       emitcode ("rlc", "a");
8457       outBitC (result);
8458     }
8459   else
8460     {
8461       emitcode ("rl", "a");
8462       emitcode ("anl", "a,#1");
8463       outAcc (result);
8464     }
8465
8466
8467   freeAsmop (result, NULL, ic, TRUE);
8468   freeAsmop (left, NULL, ic, TRUE);
8469 }
8470
8471 /*-----------------------------------------------------------------*/
8472 /* genSwap - generates code to swap nibbles or bytes               */
8473 /*-----------------------------------------------------------------*/
8474 static void
8475 genSwap (iCode * ic)
8476 {
8477   operand *left, *result;
8478
8479   D(emitcode (";     genSwap",""));
8480
8481   left = IC_LEFT (ic);
8482   result = IC_RESULT (ic);
8483   aopOp (left, ic, FALSE, FALSE);
8484   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8485
8486   _startLazyDPSEvaluation ();
8487   switch (AOP_SIZE (left))
8488     {
8489     case 1: /* swap nibbles in byte */
8490       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8491       emitcode ("swap", "a");
8492       aopPut (result, "a", 0);
8493       break;
8494     case 2: /* swap bytes in word */
8495       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8496         {
8497           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8498           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8499           aopPut (result, "a", 1);
8500         }
8501       else if (operandsEqu (left, result))
8502         {
8503           char * reg = "a";
8504           bool pushedB = FALSE, leftInB = FALSE;
8505
8506           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8507           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8508             {
8509               pushedB = pushB ();
8510               emitcode ("mov", "b,a");
8511               reg = "b";
8512               leftInB = TRUE;
8513             }
8514           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8515           aopPut (result, reg, 1);
8516
8517           if (leftInB)
8518             popB (pushedB);
8519         }
8520       else
8521         {
8522           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8523           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8524         }
8525       break;
8526     default:
8527       wassertl(FALSE, "unsupported SWAP operand size");
8528     }
8529   _endLazyDPSEvaluation ();
8530
8531   freeAsmop (result, NULL, ic, TRUE);
8532   freeAsmop (left, NULL, ic, TRUE);
8533 }
8534
8535 /*-----------------------------------------------------------------*/
8536 /* AccRol - rotate left accumulator by known count                 */
8537 /*-----------------------------------------------------------------*/
8538 static void
8539 AccRol (int shCount)
8540 {
8541   shCount &= 0x0007;            // shCount : 0..7
8542
8543   switch (shCount)
8544     {
8545     case 0:
8546       break;
8547     case 1:
8548       emitcode ("rl", "a");
8549       break;
8550     case 2:
8551       emitcode ("rl", "a");
8552       emitcode ("rl", "a");
8553       break;
8554     case 3:
8555       emitcode ("swap", "a");
8556       emitcode ("rr", "a");
8557       break;
8558     case 4:
8559       emitcode ("swap", "a");
8560       break;
8561     case 5:
8562       emitcode ("swap", "a");
8563       emitcode ("rl", "a");
8564       break;
8565     case 6:
8566       emitcode ("rr", "a");
8567       emitcode ("rr", "a");
8568       break;
8569     case 7:
8570       emitcode ("rr", "a");
8571       break;
8572     }
8573 }
8574
8575 /*-----------------------------------------------------------------*/
8576 /* AccLsh - left shift accumulator by known count                  */
8577 /*-----------------------------------------------------------------*/
8578 static void
8579 AccLsh (int shCount)
8580 {
8581   if (shCount != 0)
8582     {
8583       if (shCount == 1)
8584         emitcode ("add", "a,acc");
8585       else if (shCount == 2)
8586         {
8587           emitcode ("add", "a,acc");
8588           emitcode ("add", "a,acc");
8589         }
8590       else
8591         {
8592           /* rotate left accumulator */
8593           AccRol (shCount);
8594           /* and kill the lower order bits */
8595           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8596         }
8597     }
8598 }
8599
8600 /*-----------------------------------------------------------------*/
8601 /* AccRsh - right shift accumulator by known count                 */
8602 /*-----------------------------------------------------------------*/
8603 static void
8604 AccRsh (int shCount)
8605 {
8606   if (shCount != 0)
8607     {
8608       if (shCount == 1)
8609         {
8610           CLRC;
8611           emitcode ("rrc", "a");
8612         }
8613       else
8614         {
8615           /* rotate right accumulator */
8616           AccRol (8 - shCount);
8617           /* and kill the higher order bits */
8618           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8619         }
8620     }
8621 }
8622
8623 #ifdef BETTER_LITERAL_SHIFT
8624 /*-----------------------------------------------------------------*/
8625 /* AccSRsh - signed right shift accumulator by known count                 */
8626 /*-----------------------------------------------------------------*/
8627 static void
8628 AccSRsh (int shCount)
8629 {
8630   symbol *tlbl;
8631   if (shCount != 0)
8632     {
8633       if (shCount == 1)
8634         {
8635           emitcode ("mov", "c,acc.7");
8636           emitcode ("rrc", "a");
8637         }
8638       else if (shCount == 2)
8639         {
8640           emitcode ("mov", "c,acc.7");
8641           emitcode ("rrc", "a");
8642           emitcode ("mov", "c,acc.7");
8643           emitcode ("rrc", "a");
8644         }
8645       else
8646         {
8647           tlbl = newiTempLabel (NULL);
8648           /* rotate right accumulator */
8649           AccRol (8 - shCount);
8650           /* and kill the higher order bits */
8651           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8652           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8653           emitcode ("orl", "a,#!constbyte",
8654                     (unsigned char) ~SRMask[shCount]);
8655           emitLabel (tlbl);
8656         }
8657     }
8658 }
8659 #endif
8660
8661 #ifdef BETTER_LITERAL_SHIFT
8662 /*-----------------------------------------------------------------*/
8663 /* shiftR1Left2Result - shift right one byte from left to result   */
8664 /*-----------------------------------------------------------------*/
8665 static void
8666 shiftR1Left2Result (operand * left, int offl,
8667                     operand * result, int offr,
8668                     int shCount, int sign)
8669 {
8670   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8671   /* shift right accumulator */
8672   if (sign)
8673     AccSRsh (shCount);
8674   else
8675     AccRsh (shCount);
8676   aopPut (result, "a", offr);
8677 }
8678 #endif
8679
8680 #ifdef BETTER_LITERAL_SHIFT
8681 /*-----------------------------------------------------------------*/
8682 /* shiftL1Left2Result - shift left one byte from left to result    */
8683 /*-----------------------------------------------------------------*/
8684 static void
8685 shiftL1Left2Result (operand * left, int offl,
8686                     operand * result, int offr, int shCount)
8687 {
8688   char *l;
8689   l = aopGet (left, offl, FALSE, FALSE, NULL);
8690   MOVA (l);
8691   /* shift left accumulator */
8692   AccLsh (shCount);
8693   aopPut (result, "a", offr);
8694 }
8695 #endif
8696
8697 #ifdef BETTER_LITERAL_SHIFT
8698 /*-----------------------------------------------------------------*/
8699 /* movLeft2Result - move byte from left to result                  */
8700 /*-----------------------------------------------------------------*/
8701 static void
8702 movLeft2Result (operand * left, int offl,
8703                 operand * result, int offr, int sign)
8704 {
8705   char *l;
8706   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8707   {
8708       l = aopGet (left, offl, FALSE, FALSE, NULL);
8709
8710       if (*l == '@' && (IS_AOP_PREG (result)))
8711       {
8712           emitcode ("mov", "a,%s", l);
8713           aopPut (result, "a", offr);
8714       }
8715       else
8716       {
8717           if (!sign)
8718             {
8719               aopPut (result, l, offr);
8720             }
8721           else
8722             {
8723               /* MSB sign in acc.7 ! */
8724               if (getDataSize (left) == offl + 1)
8725                 {
8726                   MOVA (l);
8727                   aopPut (result, "a", offr);
8728                 }
8729             }
8730       }
8731   }
8732 }
8733 #endif
8734
8735 #ifdef BETTER_LITERAL_SHIFT
8736 /*-----------------------------------------------------------------*/
8737 /* AccAXRrl1 - right rotate a:x by 1                               */
8738 /*-----------------------------------------------------------------*/
8739 static void
8740 AccAXRrl1 (char *x)
8741 {
8742   emitcode ("mov", "c,acc.0");
8743   emitcode ("xch", "a,%s", x);
8744   emitcode ("rrc", "a");
8745   emitcode ("xch", "a,%s", x);
8746   emitcode ("rrc", "a");
8747 }
8748 #endif
8749
8750 #ifdef BETTER_LITERAL_SHIFT
8751 //REMOVE ME!!!
8752 /*-----------------------------------------------------------------*/
8753 /* AccAXLrl1 - left rotate a:x by 1                                */
8754 /*-----------------------------------------------------------------*/
8755 static void
8756 AccAXLrl1 (char *x)
8757 {
8758   emitcode ("mov", "c,acc.7");
8759   emitcode ("xch", "a,%s", x);
8760   emitcode ("rlc", "a");
8761   emitcode ("xch", "a,%s", x);
8762   emitcode ("rlc", "a");
8763 }
8764 #endif
8765
8766 #ifdef BETTER_LITERAL_SHIFT
8767 /*-----------------------------------------------------------------*/
8768 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8769 /*-----------------------------------------------------------------*/
8770 static void
8771 AccAXRsh1 (char *x)
8772 {
8773   emitcode ("rrc", "a");
8774   emitcode ("xch", "a,%s", x);
8775   emitcode ("rrc", "a");
8776   emitcode ("xch", "a,%s", x);
8777 }
8778 #endif
8779
8780 #ifdef BETTER_LITERAL_SHIFT
8781 /*-----------------------------------------------------------------*/
8782 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8783 /*-----------------------------------------------------------------*/
8784 static void
8785 AccAXLsh1 (char *x)
8786 {
8787   emitcode ("xch", "a,%s", x);
8788   emitcode ("add", "a,acc");
8789   emitcode ("xch", "a,%s", x);
8790   emitcode ("rlc", "a");
8791 }
8792 #endif
8793
8794 #ifdef BETTER_LITERAL_SHIFT
8795 /*-----------------------------------------------------------------*/
8796 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8797 /*-----------------------------------------------------------------*/
8798 static void
8799 AccAXLsh (char *x, int shCount)
8800 {
8801   switch (shCount)
8802     {
8803     case 0:
8804       break;
8805     case 1:
8806       AccAXLsh1 (x);
8807       break;
8808     case 2:
8809       AccAXLsh1 (x);
8810       AccAXLsh1 (x);
8811       break;
8812     case 3:
8813     case 4:
8814     case 5:                             // AAAAABBB:CCCCCDDD
8815
8816       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8817
8818       emitcode ("anl", "a,#!constbyte",
8819                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8820
8821       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8822
8823       AccRol (shCount);                 // DDDCCCCC:BBB00000
8824
8825       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8826
8827       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8828
8829       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8830
8831       emitcode ("anl", "a,#!constbyte",
8832                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8833
8834       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8835
8836       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8837
8838       break;
8839     case 6:                             // AAAAAABB:CCCCCCDD
8840       emitcode ("anl", "a,#!constbyte",
8841                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8842 #if 1
8843       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8844       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8845       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8846 #else
8847       emitcode ("mov", "c,acc.0");      // c = B
8848       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8849       emitcode("rrc","a");
8850       emitcode("xch","a,%s", x);
8851       emitcode("rrc","a");
8852       emitcode("mov","c,acc.0"); //<< get correct bit
8853       emitcode("xch","a,%s", x);
8854
8855       emitcode("rrc","a");
8856       emitcode("xch","a,%s", x);
8857       emitcode("rrc","a");
8858       emitcode("xch","a,%s", x);
8859 #endif
8860       break;
8861     case 7:                             // a:x <<= 7
8862
8863       emitcode ("anl", "a,#!constbyte",
8864                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8865
8866       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8867
8868       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8869
8870       break;
8871     default:
8872       break;
8873     }
8874 }
8875 #endif
8876
8877 #ifdef BETTER_LITERAL_SHIFT
8878 //REMOVE ME!!!
8879 /*-----------------------------------------------------------------*/
8880 /* AccAXRsh - right shift a:x known count (0..7)                   */
8881 /*-----------------------------------------------------------------*/
8882 static void
8883 AccAXRsh (char *x, int shCount)
8884 {
8885   switch (shCount)
8886     {
8887     case 0:
8888       break;
8889     case 1:
8890       CLRC;
8891       AccAXRsh1 (x);                    // 0->a:x
8892
8893       break;
8894     case 2:
8895       CLRC;
8896       AccAXRsh1 (x);                    // 0->a:x
8897
8898       CLRC;
8899       AccAXRsh1 (x);                    // 0->a:x
8900
8901       break;
8902     case 3:
8903     case 4:
8904     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8905
8906       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8907
8908       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8909
8910       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8911
8912       emitcode ("anl", "a,#!constbyte",
8913                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8914
8915       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8916
8917       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8918
8919       emitcode ("anl", "a,#!constbyte",
8920                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8921
8922       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8923
8924       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8925
8926       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8927
8928       break;
8929     case 6:                             // AABBBBBB:CCDDDDDD
8930
8931       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8932       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8933
8934       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8935
8936       emitcode ("anl", "a,#!constbyte",
8937                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8938
8939       break;
8940     case 7:                             // ABBBBBBB:CDDDDDDD
8941
8942       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8943
8944       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8945
8946       emitcode ("anl", "a,#!constbyte",
8947                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8948
8949       break;
8950     default:
8951       break;
8952     }
8953 }
8954 #endif
8955
8956 #ifdef BETTER_LITERAL_SHIFT
8957 /*-----------------------------------------------------------------*/
8958 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8959 /*-----------------------------------------------------------------*/
8960 static void
8961 AccAXRshS (char *x, int shCount)
8962 {
8963   symbol *tlbl;
8964   switch (shCount)
8965     {
8966     case 0:
8967       break;
8968     case 1:
8969       emitcode ("mov", "c,acc.7");
8970       AccAXRsh1 (x);                    // s->a:x
8971
8972       break;
8973     case 2:
8974       emitcode ("mov", "c,acc.7");
8975       AccAXRsh1 (x);                    // s->a:x
8976
8977       emitcode ("mov", "c,acc.7");
8978       AccAXRsh1 (x);                    // s->a:x
8979
8980       break;
8981     case 3:
8982     case 4:
8983     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8984
8985       tlbl = newiTempLabel (NULL);
8986       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8987
8988       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8989
8990       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8991
8992       emitcode ("anl", "a,#!constbyte",
8993                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8994
8995       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8996
8997       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8998
8999       emitcode ("anl", "a,#!constbyte",
9000                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9001
9002       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9003
9004       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9005
9006       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9007
9008       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9009       emitcode ("orl", "a,#!constbyte",
9010                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9011
9012       emitLabel (tlbl);
9013       break;                            // SSSSAAAA:BBBCCCCC
9014
9015     case 6:                             // AABBBBBB:CCDDDDDD
9016
9017       tlbl = newiTempLabel (NULL);
9018
9019       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9020       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9021
9022       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9023
9024       emitcode ("anl", "a,#!constbyte",
9025                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9026
9027       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9028       emitcode ("orl", "a,#!constbyte",
9029                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9030
9031       emitLabel (tlbl);
9032       break;
9033     case 7:                             // ABBBBBBB:CDDDDDDD
9034
9035       tlbl = newiTempLabel (NULL);
9036
9037       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9038
9039       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9040
9041       emitcode ("anl", "a,#!constbyte",
9042                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9043
9044       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9045       emitcode ("orl", "a,#!constbyte",
9046                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9047
9048       emitLabel (tlbl);
9049       break;
9050     default:
9051       break;
9052     }
9053 }
9054 #endif
9055
9056 #ifdef BETTER_LITERAL_SHIFT
9057 static void
9058 _loadLeftIntoAx(char    **lsb,
9059                 operand *left,
9060                 operand *result,
9061                 int     offl,
9062                 int     offr)
9063 {
9064   // Get the initial value from left into a pair of registers.
9065   // MSB must be in A, LSB can be any register.
9066   //
9067   // If the result is held in registers, it is an optimization
9068   // if the LSB can be held in the register which will hold the,
9069   // result LSB since this saves us from having to copy it into
9070   // the result following AccAXLsh.
9071   //
9072   // If the result is addressed indirectly, this is not a gain.
9073   if (AOP_NEEDSACC(result))
9074   {
9075        char *leftByte;
9076
9077        _startLazyDPSEvaluation();
9078       if (AOP_TYPE(left) == AOP_DPTR2)
9079        {
9080            // Get MSB in A.
9081            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9082            // get LSB in DP2_RESULT_REG.
9083            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9084            assert(!strcmp(leftByte, DP2_RESULT_REG));
9085        }
9086        else
9087        {
9088            // get LSB into DP2_RESULT_REG
9089            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9090            if (strcmp(leftByte, DP2_RESULT_REG))
9091            {
9092                TR_AP("#7");
9093                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9094            }
9095            // And MSB in A.
9096            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9097            assert(strcmp(leftByte, DP2_RESULT_REG));
9098            MOVA (leftByte);
9099        }
9100        _endLazyDPSEvaluation();
9101        *lsb = DP2_RESULT_REG;
9102   }
9103   else
9104   {
9105       if (sameRegs (AOP (result), AOP (left)) &&
9106         ((offl + MSB16) == offr))
9107       {
9108           /* don't crash result[offr] */
9109           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9110           emitcode ("xch", "a,%s",
9111                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9112       }
9113       else
9114       {
9115           movLeft2Result (left, offl, result, offr, 0);
9116           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9117       }
9118       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9119       assert(strcmp(*lsb,"a"));
9120   }
9121 }
9122
9123 static void
9124 _storeAxResults(char    *lsb,
9125                 operand *result,
9126                 int     offr)
9127 {
9128   _startLazyDPSEvaluation();
9129   if (AOP_NEEDSACC(result))
9130   {
9131       /* We have to explicitly update the result LSB.
9132        */
9133       emitcode ("xch","a,%s", lsb);
9134       aopPut (result, "a", offr);
9135       emitcode ("mov","a,%s", lsb);
9136   }
9137   if (getDataSize (result) > 1)
9138   {
9139       aopPut (result, "a", offr + MSB16);
9140   }
9141   _endLazyDPSEvaluation();
9142 }
9143
9144 /*-----------------------------------------------------------------*/
9145 /* shiftL2Left2Result - shift left two bytes from left to result   */
9146 /*-----------------------------------------------------------------*/
9147 static void
9148 shiftL2Left2Result (operand * left, int offl,
9149                     operand * result, int offr, int shCount)
9150 {
9151   char *lsb;
9152
9153   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9154
9155   AccAXLsh (lsb, shCount);
9156
9157   _storeAxResults(lsb, result, offr);
9158 }
9159 #endif
9160
9161 #ifdef BETTER_LITERAL_SHIFT
9162 /*-----------------------------------------------------------------*/
9163 /* shiftR2Left2Result - shift right two bytes from left to result  */
9164 /*-----------------------------------------------------------------*/
9165 static void
9166 shiftR2Left2Result (operand * left, int offl,
9167                     operand * result, int offr,
9168                     int shCount, int sign)
9169 {
9170   char *lsb;
9171
9172   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9173
9174   /* a:x >> shCount (x = lsb(result)) */
9175   if (sign)
9176   {
9177      AccAXRshS(lsb, shCount);
9178   }
9179   else
9180   {
9181     AccAXRsh(lsb, shCount);
9182   }
9183
9184   _storeAxResults(lsb, result, offr);
9185 }
9186 #endif
9187
9188 /*-----------------------------------------------------------------*/
9189 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9190 /*-----------------------------------------------------------------*/
9191 static void
9192 shiftLLeftOrResult (operand * left, int offl,
9193                     operand * result, int offr, int shCount)
9194 {
9195   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9196   /* shift left accumulator */
9197   AccLsh (shCount);
9198   /* or with result */
9199   emitcode ("orl", "a,%s",
9200             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9201   /* back to result */
9202   aopPut (result, "a", offr);
9203 }
9204
9205 #if 0
9206 //REMOVE ME!!!
9207 /*-----------------------------------------------------------------*/
9208 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9209 /*-----------------------------------------------------------------*/
9210 static void
9211 shiftRLeftOrResult (operand * left, int offl,
9212                     operand * result, int offr, int shCount)
9213 {
9214   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9215   /* shift right accumulator */
9216   AccRsh (shCount);
9217   /* or with result */
9218   emitcode ("orl", "a,%s",
9219             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9220   /* back to result */
9221   aopPut (result, "a", offr);
9222 }
9223 #endif
9224
9225 #ifdef BETTER_LITERAL_SHIFT
9226 /*-----------------------------------------------------------------*/
9227 /* genlshOne - left shift a one byte quantity by known count       */
9228 /*-----------------------------------------------------------------*/
9229 static void
9230 genlshOne (operand * result, operand * left, int shCount)
9231 {
9232   D (emitcode (";", "genlshOne"));
9233
9234   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9235 }
9236 #endif
9237
9238 #ifdef BETTER_LITERAL_SHIFT
9239 /*-----------------------------------------------------------------*/
9240 /* genlshTwo - left shift two bytes by known amount != 0           */
9241 /*-----------------------------------------------------------------*/
9242 static void
9243 genlshTwo (operand * result, operand * left, int shCount)
9244 {
9245   int size;
9246
9247   D (emitcode (";", "genlshTwo"));
9248
9249   size = getDataSize (result);
9250
9251   /* if shCount >= 8 */
9252   if (shCount >= 8)
9253   {
9254       shCount -= 8;
9255
9256       _startLazyDPSEvaluation();
9257
9258       if (size > 1)
9259         {
9260           if (shCount)
9261           {
9262             _endLazyDPSEvaluation();
9263             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9264             aopPut (result, zero, LSB);
9265           }
9266           else
9267           {
9268             movLeft2Result (left, LSB, result, MSB16, 0);
9269             aopPut (result, zero, LSB);
9270             _endLazyDPSEvaluation();
9271           }
9272         }
9273         else
9274         {
9275           aopPut (result, zero, LSB);
9276           _endLazyDPSEvaluation();
9277         }
9278   }
9279
9280   /*  1 <= shCount <= 7 */
9281   else
9282     {
9283       if (size == 1)
9284         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9285       else
9286         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9287     }
9288 }
9289 #endif
9290
9291 #if 0
9292 //REMOVE ME!!!
9293 /*-----------------------------------------------------------------*/
9294 /* shiftLLong - shift left one long from left to result            */
9295 /* offl = LSB or MSB16                                             */
9296 /*-----------------------------------------------------------------*/
9297 static void
9298 shiftLLong (operand * left, operand * result, int offr)
9299 {
9300   char *l;
9301   int size = AOP_SIZE (result);
9302
9303   if (size >= LSB + offr)
9304     {
9305       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9306       MOVA (l);
9307       emitcode ("add", "a,acc");
9308       if (sameRegs (AOP (left), AOP (result)) &&
9309           size >= MSB16 + offr && offr != LSB)
9310         emitcode ("xch", "a,%s",
9311                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9312       else
9313         aopPut (result, "a", LSB + offr);
9314     }
9315
9316   if (size >= MSB16 + offr)
9317     {
9318       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9319         {
9320           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9321           MOVA (l);
9322         }
9323       emitcode ("rlc", "a");
9324       if (sameRegs (AOP (left), AOP (result)) &&
9325           size >= MSB24 + offr && offr != LSB)
9326         emitcode ("xch", "a,%s",
9327                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9328       else
9329         aopPut (result, "a", MSB16 + offr);
9330     }
9331
9332   if (size >= MSB24 + offr)
9333     {
9334       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9335         {
9336           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9337           MOVA (l);
9338         }
9339       emitcode ("rlc", "a");
9340       if (sameRegs (AOP (left), AOP (result)) &&
9341           size >= MSB32 + offr && offr != LSB)
9342         emitcode ("xch", "a,%s",
9343                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9344       else
9345         aopPut (result, "a", MSB24 + offr);
9346     }
9347
9348   if (size > MSB32 + offr)
9349     {
9350       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9351         {
9352           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9353           MOVA (l);
9354         }
9355       emitcode ("rlc", "a");
9356       aopPut (result, "a", MSB32 + offr);
9357     }
9358   if (offr != LSB)
9359     aopPut (result, zero, LSB);
9360 }
9361 #endif
9362
9363 #if 0
9364 //REMOVE ME!!!
9365 /*-----------------------------------------------------------------*/
9366 /* genlshFour - shift four byte by a known amount != 0             */
9367 /*-----------------------------------------------------------------*/
9368 static void
9369 genlshFour (operand * result, operand * left, int shCount)
9370 {
9371   int size;
9372
9373   D (emitcode (";", "genlshFour"));
9374
9375   size = AOP_SIZE (result);
9376
9377   /* if shifting more that 3 bytes */
9378   if (shCount >= 24)
9379     {
9380       shCount -= 24;
9381       if (shCount)
9382         /* lowest order of left goes to the highest
9383            order of the destination */
9384         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9385       else
9386         movLeft2Result (left, LSB, result, MSB32, 0);
9387       aopPut (result, zero, LSB);
9388       aopPut (result, zero, MSB16);
9389       aopPut (result, zero, MSB24);
9390       return;
9391     }
9392
9393   /* more than two bytes */
9394   else if (shCount >= 16)
9395     {
9396       /* lower order two bytes goes to higher order two bytes */
9397       shCount -= 16;
9398       /* if some more remaining */
9399       if (shCount)
9400         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9401       else
9402         {
9403           movLeft2Result (left, MSB16, result, MSB32, 0);
9404           movLeft2Result (left, LSB, result, MSB24, 0);
9405         }
9406       aopPut (result, zero, MSB16);
9407       aopPut (result, zero, LSB);
9408       return;
9409     }
9410
9411   /* if more than 1 byte */
9412   else if (shCount >= 8)
9413     {
9414       /* lower order three bytes goes to higher order  three bytes */
9415       shCount -= 8;
9416       if (size == 2)
9417         {
9418           if (shCount)
9419             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9420           else
9421             movLeft2Result (left, LSB, result, MSB16, 0);
9422         }
9423       else
9424         {                       /* size = 4 */
9425           if (shCount == 0)
9426             {
9427               movLeft2Result (left, MSB24, result, MSB32, 0);
9428               movLeft2Result (left, MSB16, result, MSB24, 0);
9429               movLeft2Result (left, LSB, result, MSB16, 0);
9430               aopPut (result, zero, LSB);
9431             }
9432           else if (shCount == 1)
9433             shiftLLong (left, result, MSB16);
9434           else
9435             {
9436               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9437               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9438               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9439               aopPut (result, zero, LSB);
9440             }
9441         }
9442     }
9443
9444   /* 1 <= shCount <= 7 */
9445   else if (shCount <= 2)
9446     {
9447       shiftLLong (left, result, LSB);
9448       if (shCount == 2)
9449         shiftLLong (result, result, LSB);
9450     }
9451   /* 3 <= shCount <= 7, optimize */
9452   else
9453     {
9454       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9455       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9456       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9457     }
9458 }
9459 #endif
9460
9461 #ifdef BETTER_LITERAL_SHIFT
9462 /*-----------------------------------------------------------------*/
9463 /* genLeftShiftLiteral - left shifting by known count              */
9464 /*-----------------------------------------------------------------*/
9465 static bool
9466 genLeftShiftLiteral (operand * left,
9467                      operand * right,
9468                      operand * result,
9469                      iCode * ic)
9470 {
9471   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9472   int size;
9473
9474   size = getSize (operandType (result));
9475
9476   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9477
9478   /* We only handle certain easy cases so far. */
9479   if ((shCount != 0)
9480    && (shCount < (size * 8))
9481    && (size != 1)
9482    && (size != 2))
9483   {
9484       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9485       return FALSE;
9486   }
9487
9488   freeAsmop (right, NULL, ic, TRUE);
9489
9490   aopOp(left, ic, FALSE, FALSE);
9491   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9492
9493 #if 0 // debug spew
9494   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9495   {
9496         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9497         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9498         {
9499            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9500         }
9501   }
9502   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9503   {
9504         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9505         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9506         {
9507            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9508         }
9509   }
9510 #endif
9511
9512 #if VIEW_SIZE
9513   emitcode ("; shift left ", "result %d, left %d", size,
9514             AOP_SIZE (left));
9515 #endif
9516
9517   /* I suppose that the left size >= result size */
9518   if (shCount == 0)
9519   {
9520         _startLazyDPSEvaluation();
9521         while (size--)
9522         {
9523           movLeft2Result (left, size, result, size, 0);
9524         }
9525         _endLazyDPSEvaluation();
9526   }
9527   else if (shCount >= (size * 8))
9528   {
9529     _startLazyDPSEvaluation();
9530     while (size--)
9531     {
9532       aopPut (result, zero, size);
9533     }
9534     _endLazyDPSEvaluation();
9535   }
9536   else
9537   {
9538       switch (size)
9539         {
9540         case 1:
9541           genlshOne (result, left, shCount);
9542           break;
9543
9544         case 2:
9545           genlshTwo (result, left, shCount);
9546           break;
9547 #if 0
9548         case 4:
9549           genlshFour (result, left, shCount);
9550           break;
9551 #endif
9552         default:
9553           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9554                   "*** ack! mystery literal shift!\n");
9555           break;
9556         }
9557     }
9558   freeAsmop (result, NULL, ic, TRUE);
9559   freeAsmop (left, NULL, ic, TRUE);
9560   return TRUE;
9561 }
9562 #endif
9563
9564 /*-----------------------------------------------------------------*/
9565 /* genLeftShift - generates code for left shifting                 */
9566 /*-----------------------------------------------------------------*/
9567 static void
9568 genLeftShift (iCode * ic)
9569 {
9570   operand *left, *right, *result;
9571   int size, offset;
9572   char *l;
9573   symbol *tlbl, *tlbl1;
9574   bool pushedB;
9575
9576   D (emitcode (";", "genLeftShift"));
9577
9578   right = IC_RIGHT (ic);
9579   left = IC_LEFT (ic);
9580   result = IC_RESULT (ic);
9581
9582   aopOp (right, ic, FALSE, FALSE);
9583
9584
9585 #ifdef BETTER_LITERAL_SHIFT
9586   /* if the shift count is known then do it
9587      as efficiently as possible */
9588   if (AOP_TYPE (right) == AOP_LIT)
9589     {
9590       if (genLeftShiftLiteral (left, right, result, ic))
9591       {
9592         return;
9593       }
9594     }
9595 #endif
9596
9597   /* shift count is unknown then we have to form
9598      a loop get the loop count in B : Note: we take
9599      only the lower order byte since shifting
9600      more that 32 bits make no sense anyway, ( the
9601      largest size of an object can be only 32 bits ) */
9602
9603   pushedB = pushB ();
9604   if (AOP_TYPE (right) == AOP_LIT)
9605   {
9606       /* Really should be handled by genLeftShiftLiteral,
9607        * but since I'm too lazy to fix that today, at least we can make
9608        * some small improvement.
9609        */
9610        emitcode("mov", "b,#!constbyte",
9611                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9612   }
9613   else
9614   {
9615       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9616       emitcode ("inc", "b");
9617   }
9618   freeAsmop (right, NULL, ic, TRUE);
9619   aopOp (left, ic, FALSE, FALSE);
9620   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9621
9622   /* now move the left to the result if they are not the same */
9623   if (!sameRegs (AOP (left), AOP (result)) &&
9624       AOP_SIZE (result) > 1)
9625     {
9626
9627       size = AOP_SIZE (result);
9628       offset = 0;
9629       _startLazyDPSEvaluation ();
9630       while (size--)
9631         {
9632           l = aopGet (left, offset, FALSE, TRUE, NULL);
9633           if (*l == '@' && (IS_AOP_PREG (result)))
9634             {
9635
9636               emitcode ("mov", "a,%s", l);
9637               aopPut (result, "a", offset);
9638             }
9639           else
9640             aopPut (result, l, offset);
9641           offset++;
9642         }
9643       _endLazyDPSEvaluation ();
9644     }
9645
9646   tlbl = newiTempLabel (NULL);
9647   size = AOP_SIZE (result);
9648   offset = 0;
9649   tlbl1 = newiTempLabel (NULL);
9650
9651   /* if it is only one byte then */
9652   if (size == 1)
9653     {
9654       symbol *tlbl1 = newiTempLabel (NULL);
9655
9656       l = aopGet (left, 0, FALSE, FALSE, NULL);
9657       MOVA (l);
9658       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9659       emitLabel (tlbl);
9660       emitcode ("add", "a,acc");
9661       emitLabel (tlbl1);
9662       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9663       popB (pushedB);
9664       aopPut (result, "a", 0);
9665       goto release;
9666     }
9667
9668   reAdjustPreg (AOP (result));
9669
9670   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9671   emitLabel (tlbl);
9672   l = aopGet (result, offset, FALSE, FALSE, NULL);
9673   MOVA (l);
9674   emitcode ("add", "a,acc");
9675   aopPut (result, "a", offset++);
9676   _startLazyDPSEvaluation ();
9677   while (--size)
9678     {
9679       l = aopGet (result, offset, FALSE, FALSE, NULL);
9680       MOVA (l);
9681       emitcode ("rlc", "a");
9682       aopPut (result, "a", offset++);
9683     }
9684   _endLazyDPSEvaluation ();
9685   reAdjustPreg (AOP (result));
9686
9687   emitLabel (tlbl1);
9688   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9689   popB (pushedB);
9690 release:
9691   freeAsmop (result, NULL, ic, TRUE);
9692   freeAsmop (left, NULL, ic, TRUE);
9693 }
9694
9695 #ifdef BETTER_LITERAL_SHIFT
9696 /*-----------------------------------------------------------------*/
9697 /* genrshOne - right shift a one byte quantity by known count      */
9698 /*-----------------------------------------------------------------*/
9699 static void
9700 genrshOne (operand * result, operand * left,
9701            int shCount, int sign)
9702 {
9703   D (emitcode (";", "genrshOne"));
9704
9705   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9706 }
9707 #endif
9708
9709 #ifdef BETTER_LITERAL_SHIFT
9710 /*-----------------------------------------------------------------*/
9711 /* genrshTwo - right shift two bytes by known amount != 0          */
9712 /*-----------------------------------------------------------------*/
9713 static void
9714 genrshTwo (operand * result, operand * left,
9715            int shCount, int sign)
9716 {
9717   D (emitcode (";", "genrshTwo"));
9718
9719   /* if shCount >= 8 */
9720   if (shCount >= 8)
9721     {
9722       shCount -= 8;
9723       _startLazyDPSEvaluation();
9724       if (shCount)
9725         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9726       else
9727         movLeft2Result (left, MSB16, result, LSB, sign);
9728       addSign (result, MSB16, sign);
9729       _endLazyDPSEvaluation();
9730     }
9731
9732   /*  1 <= shCount <= 7 */
9733   else
9734     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9735 }
9736 #endif
9737
9738 /*-----------------------------------------------------------------*/
9739 /* shiftRLong - shift right one long from left to result           */
9740 /* offl = LSB or MSB16                                             */
9741 /*-----------------------------------------------------------------*/
9742 static void
9743 shiftRLong (operand * left, int offl,
9744             operand * result, int sign)
9745 {
9746   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9747
9748   if (overlapping && offl>1)
9749     {
9750       // we are in big trouble, but this shouldn't happen
9751       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9752     }
9753
9754   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9755
9756   if (offl==MSB16)
9757     {
9758       // shift is > 8
9759       if (sign)
9760         {
9761           emitcode ("rlc", "a");
9762           emitcode ("subb", "a,acc");
9763           emitcode ("xch", "a,%s",
9764                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9765         }
9766       else
9767         {
9768           aopPut (result, zero, MSB32);
9769         }
9770     }
9771
9772   if (!sign)
9773     {
9774       emitcode ("clr", "c");
9775     }
9776   else
9777     {
9778       emitcode ("mov", "c,acc.7");
9779     }
9780
9781   emitcode ("rrc", "a");
9782
9783   if (overlapping && offl==MSB16)
9784     {
9785       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9786     }
9787   else
9788     {
9789       aopPut (result, "a", MSB32 - offl);
9790       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9791     }
9792
9793   emitcode ("rrc", "a");
9794
9795   if (overlapping && offl==MSB16)
9796     {
9797       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9798     }
9799   else
9800     {
9801       aopPut (result, "a", MSB24 - offl);
9802       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9803     }
9804
9805   emitcode ("rrc", "a");
9806   if (offl != LSB)
9807     {
9808       aopPut (result, "a", MSB16 - offl);
9809     }
9810   else
9811     {
9812       if (overlapping && offl==MSB16)
9813         {
9814           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9815         }
9816       else
9817         {
9818           aopPut (result, "a", MSB16 - offl);
9819           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9820         }
9821       emitcode ("rrc", "a");
9822       aopPut (result, "a", LSB);
9823     }
9824 }
9825
9826 /*-----------------------------------------------------------------*/
9827 /* genrshFour - shift four byte by a known amount != 0             */
9828 /*-----------------------------------------------------------------*/
9829 static void
9830 genrshFour (operand * result, operand * left,
9831             int shCount, int sign)
9832 {
9833   D (emitcode (";", "genrshFour"));
9834
9835   /* if shifting more that 3 bytes */
9836   if (shCount >= 24)
9837     {
9838       shCount -= 24;
9839       _startLazyDPSEvaluation();
9840       if (shCount)
9841         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9842       else
9843         movLeft2Result (left, MSB32, result, LSB, sign);
9844       addSign (result, MSB16, sign);
9845       _endLazyDPSEvaluation();
9846     }
9847   else if (shCount >= 16)
9848     {
9849       shCount -= 16;
9850       _startLazyDPSEvaluation();
9851       if (shCount)
9852         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9853       else
9854         {
9855           movLeft2Result (left, MSB24, result, LSB, 0);
9856           movLeft2Result (left, MSB32, result, MSB16, sign);
9857         }
9858       addSign (result, MSB24, sign);
9859       _endLazyDPSEvaluation();
9860     }
9861   else if (shCount >= 8)
9862     {
9863       shCount -= 8;
9864       _startLazyDPSEvaluation();
9865       if (shCount == 1)
9866         {
9867             shiftRLong (left, MSB16, result, sign);
9868         }
9869       else if (shCount == 0)
9870         {
9871           movLeft2Result (left, MSB16, result, LSB, 0);
9872           movLeft2Result (left, MSB24, result, MSB16, 0);
9873           movLeft2Result (left, MSB32, result, MSB24, sign);
9874           addSign (result, MSB32, sign);
9875         }
9876       else
9877         {
9878           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9879           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9880           /* the last shift is signed */
9881           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9882           addSign (result, MSB32, sign);
9883         }
9884         _endLazyDPSEvaluation();
9885     }
9886   else
9887     {
9888       /* 1 <= shCount <= 7 */
9889       if (shCount <= 2)
9890         {
9891           shiftRLong (left, LSB, result, sign);
9892           if (shCount == 2)
9893             shiftRLong (result, LSB, result, sign);
9894         }
9895       else
9896         {
9897           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9898           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9899           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9900         }
9901     }
9902 }
9903
9904 #ifdef BETTER_LITERAL_SHIFT
9905 /*-----------------------------------------------------------------*/
9906 /* genRightShiftLiteral - right shifting by known count            */
9907 /*-----------------------------------------------------------------*/
9908 static bool
9909 genRightShiftLiteral (operand * left,
9910                       operand * right,
9911                       operand * result,
9912                       iCode * ic,
9913                       int sign)
9914 {
9915   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9916   int size;
9917
9918   size = getSize (operandType (result));
9919
9920   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9921
9922   /* We only handle certain easy cases so far. */
9923   if ((shCount != 0)
9924    && (shCount < (size * 8))
9925    && (size != 1)
9926    && (size != 2)
9927    && (size != 4))
9928   {
9929       D(emitcode (";", "genRightShiftLiteral wimping out"););
9930       return FALSE;
9931   }
9932
9933   freeAsmop (right, NULL, ic, TRUE);
9934
9935   aopOp (left, ic, FALSE, FALSE);
9936   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9937
9938 #if VIEW_SIZE
9939   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9940             AOP_SIZE (left));
9941 #endif
9942
9943   /* test the LEFT size !!! */
9944
9945   /* I suppose that the left size >= result size */
9946   if (shCount == 0)
9947   {
9948       size = getDataSize (result);
9949       _startLazyDPSEvaluation();
9950       while (size--)
9951         movLeft2Result (left, size, result, size, 0);
9952       _endLazyDPSEvaluation();
9953   }
9954   else if (shCount >= (size * 8))
9955     {
9956       if (sign)
9957         {
9958           /* get sign in acc.7 */
9959           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9960         }
9961       addSign (result, LSB, sign);
9962     }
9963   else
9964     {
9965       switch (size)
9966         {
9967         case 1:
9968           genrshOne (result, left, shCount, sign);
9969           break;
9970
9971         case 2:
9972           genrshTwo (result, left, shCount, sign);
9973           break;
9974 #if 1
9975         case 4:
9976           genrshFour (result, left, shCount, sign);
9977           break;
9978 #endif
9979         default:
9980           break;
9981         }
9982     }
9983   freeAsmop (result, NULL, ic, TRUE);
9984   freeAsmop (left, NULL, ic, TRUE);
9985
9986   return TRUE;
9987 }
9988 #endif
9989
9990 /*-----------------------------------------------------------------*/
9991 /* genSignedRightShift - right shift of signed number              */
9992 /*-----------------------------------------------------------------*/
9993 static void
9994 genSignedRightShift (iCode * ic)
9995 {
9996   operand *right, *left, *result;
9997   int size, offset;
9998   char *l;
9999   symbol *tlbl, *tlbl1;
10000   bool pushedB;
10001
10002   D (emitcode (";", "genSignedRightShift"));
10003
10004   /* we do it the hard way put the shift count in b
10005      and loop thru preserving the sign */
10006
10007   right = IC_RIGHT (ic);
10008   left = IC_LEFT (ic);
10009   result = IC_RESULT (ic);
10010
10011   aopOp (right, ic, FALSE, FALSE);
10012
10013 #ifdef BETTER_LITERAL_SHIFT
10014   if (AOP_TYPE (right) == AOP_LIT)
10015     {
10016       if (genRightShiftLiteral (left, right, result, ic, 1))
10017       {
10018         return;
10019       }
10020     }
10021 #endif
10022   /* shift count is unknown then we have to form
10023      a loop get the loop count in B : Note: we take
10024      only the lower order byte since shifting
10025      more that 32 bits make no sense anyway, ( the
10026      largest size of an object can be only 32 bits ) */
10027
10028   pushedB = pushB ();
10029   if (AOP_TYPE (right) == AOP_LIT)
10030   {
10031       /* Really should be handled by genRightShiftLiteral,
10032        * but since I'm too lazy to fix that today, at least we can make
10033        * some small improvement.
10034        */
10035        emitcode("mov", "b,#!constbyte",
10036                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10037   }
10038   else
10039   {
10040         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10041         emitcode ("inc", "b");
10042   }
10043   freeAsmop (right, NULL, ic, TRUE);
10044   aopOp (left, ic, FALSE, FALSE);
10045   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10046
10047   /* now move the left to the result if they are not the
10048      same */
10049   if (!sameRegs (AOP (left), AOP (result)) &&
10050       AOP_SIZE (result) > 1)
10051     {
10052
10053       size = AOP_SIZE (result);
10054       offset = 0;
10055       _startLazyDPSEvaluation ();
10056       while (size--)
10057         {
10058           l = aopGet (left, offset, FALSE, TRUE, NULL);
10059           if (*l == '@' && IS_AOP_PREG (result))
10060             {
10061
10062               emitcode ("mov", "a,%s", l);
10063               aopPut (result, "a", offset);
10064             }
10065           else
10066             aopPut (result, l, offset);
10067           offset++;
10068         }
10069       _endLazyDPSEvaluation ();
10070     }
10071
10072   /* mov the highest order bit to OVR */
10073   tlbl = newiTempLabel (NULL);
10074   tlbl1 = newiTempLabel (NULL);
10075
10076   size = AOP_SIZE (result);
10077   offset = size - 1;
10078   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10079   emitcode ("rlc", "a");
10080   emitcode ("mov", "ov,c");
10081   /* if it is only one byte then */
10082   if (size == 1)
10083     {
10084       l = aopGet (left, 0, FALSE, FALSE, NULL);
10085       MOVA (l);
10086       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10087       emitLabel (tlbl);
10088       emitcode ("mov", "c,ov");
10089       emitcode ("rrc", "a");
10090       emitLabel (tlbl1);
10091       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10092       popB (pushedB);
10093       aopPut (result, "a", 0);
10094       goto release;
10095     }
10096
10097   reAdjustPreg (AOP (result));
10098   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10099   emitLabel (tlbl);
10100   emitcode ("mov", "c,ov");
10101   _startLazyDPSEvaluation ();
10102   while (size--)
10103     {
10104       l = aopGet (result, offset, FALSE, FALSE, NULL);
10105       MOVA (l);
10106       emitcode ("rrc", "a");
10107       aopPut (result, "a", offset--);
10108     }
10109   _endLazyDPSEvaluation ();
10110   reAdjustPreg (AOP (result));
10111   emitLabel (tlbl1);
10112   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10113   popB (pushedB);
10114
10115 release:
10116   freeAsmop (result, NULL, ic, TRUE);
10117   freeAsmop (left, NULL, ic, TRUE);
10118 }
10119
10120 /*-----------------------------------------------------------------*/
10121 /* genRightShift - generate code for right shifting                */
10122 /*-----------------------------------------------------------------*/
10123 static void
10124 genRightShift (iCode * ic)
10125 {
10126   operand *right, *left, *result;
10127   sym_link *letype;
10128   int size, offset;
10129   char *l;
10130   symbol *tlbl, *tlbl1;
10131   bool pushedB;
10132
10133   D (emitcode (";", "genRightShift"));
10134
10135   /* if signed then we do it the hard way preserve the
10136      sign bit moving it inwards */
10137   letype = getSpec (operandType (IC_LEFT (ic)));
10138
10139   if (!SPEC_USIGN (letype))
10140     {
10141       genSignedRightShift (ic);
10142       return;
10143     }
10144
10145   /* signed & unsigned types are treated the same : i.e. the
10146      signed is NOT propagated inwards : quoting from the
10147      ANSI - standard : "for E1 >> E2, is equivalent to division
10148      by 2**E2 if unsigned or if it has a non-negative value,
10149      otherwise the result is implementation defined ", MY definition
10150      is that the sign does not get propagated */
10151
10152   right = IC_RIGHT (ic);
10153   left = IC_LEFT (ic);
10154   result = IC_RESULT (ic);
10155
10156   aopOp (right, ic, FALSE, FALSE);
10157
10158 #ifdef BETTER_LITERAL_SHIFT
10159   /* if the shift count is known then do it
10160      as efficiently as possible */
10161   if (AOP_TYPE (right) == AOP_LIT)
10162     {
10163       if (genRightShiftLiteral (left, right, result, ic, 0))
10164       {
10165         return;
10166       }
10167     }
10168 #endif
10169
10170   /* shift count is unknown then we have to form
10171      a loop get the loop count in B : Note: we take
10172      only the lower order byte since shifting
10173      more that 32 bits make no sense anyway, ( the
10174      largest size of an object can be only 32 bits ) */
10175
10176   pushedB = pushB ();
10177   if (AOP_TYPE (right) == AOP_LIT)
10178   {
10179       /* Really should be handled by genRightShiftLiteral,
10180        * but since I'm too lazy to fix that today, at least we can make
10181        * some small improvement.
10182        */
10183        emitcode("mov", "b,#!constbyte",
10184                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10185   }
10186   else
10187   {
10188       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10189       emitcode ("inc", "b");
10190   }
10191   freeAsmop (right, NULL, ic, TRUE);
10192   aopOp (left, ic, FALSE, FALSE);
10193   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10194
10195   /* now move the left to the result if they are not the
10196      same */
10197   if (!sameRegs (AOP (left), AOP (result)) &&
10198       AOP_SIZE (result) > 1)
10199     {
10200       size = AOP_SIZE (result);
10201       offset = 0;
10202       _startLazyDPSEvaluation ();
10203       while (size--)
10204         {
10205           l = aopGet (left, offset, FALSE, TRUE, NULL);
10206           if (*l == '@' && IS_AOP_PREG (result))
10207             {
10208
10209               emitcode ("mov", "a,%s", l);
10210               aopPut (result, "a", offset);
10211             }
10212           else
10213             aopPut (result, l, offset);
10214           offset++;
10215         }
10216       _endLazyDPSEvaluation ();
10217     }
10218
10219   tlbl = newiTempLabel (NULL);
10220   tlbl1 = newiTempLabel (NULL);
10221   size = AOP_SIZE (result);
10222   offset = size - 1;
10223
10224   /* if it is only one byte then */
10225   if (size == 1)
10226     {
10227       l = aopGet (left, 0, FALSE, FALSE, NULL);
10228       MOVA (l);
10229       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10230       emitLabel (tlbl);
10231       CLRC;
10232       emitcode ("rrc", "a");
10233       emitLabel (tlbl1);
10234       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10235       popB (pushedB);
10236       aopPut (result, "a", 0);
10237       goto release;
10238     }
10239
10240   reAdjustPreg (AOP (result));
10241   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10242   emitLabel (tlbl);
10243   CLRC;
10244   _startLazyDPSEvaluation ();
10245   while (size--)
10246     {
10247       l = aopGet (result, offset, FALSE, FALSE, NULL);
10248       MOVA (l);
10249       emitcode ("rrc", "a");
10250       aopPut (result, "a", offset--);
10251     }
10252   _endLazyDPSEvaluation ();
10253   reAdjustPreg (AOP (result));
10254
10255   emitLabel (tlbl1);
10256   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10257   popB (pushedB);
10258
10259 release:
10260   freeAsmop (result, NULL, ic, TRUE);
10261   freeAsmop (left, NULL, ic, TRUE);
10262 }
10263
10264 /*-----------------------------------------------------------------*/
10265 /* emitPtrByteGet - emits code to get a byte into A through a      */
10266 /*                  pointer register (R0, R1, or DPTR). The        */
10267 /*                  original value of A can be preserved in B.     */
10268 /*-----------------------------------------------------------------*/
10269 static void
10270 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10271 {
10272   switch (p_type)
10273     {
10274     case IPOINTER:
10275     case POINTER:
10276       if (preserveAinB)
10277         emitcode ("mov", "b,a");
10278       emitcode ("mov", "a,@%s", rname);
10279       break;
10280
10281     case PPOINTER:
10282       if (preserveAinB)
10283         emitcode ("mov", "b,a");
10284       emitcode ("movx", "a,@%s", rname);
10285       break;
10286
10287     case FPOINTER:
10288       if (preserveAinB)
10289         emitcode ("mov", "b,a");
10290       emitcode ("movx", "a,@dptr");
10291       break;
10292
10293     case CPOINTER:
10294       if (preserveAinB)
10295         emitcode ("mov", "b,a");
10296       emitcode ("clr", "a");
10297       emitcode ("movc", "a,@a+dptr");
10298       break;
10299
10300     case GPOINTER:
10301       if (preserveAinB)
10302         {
10303           emitcode ("push", "b");
10304           emitcode ("push", "acc");
10305         }
10306       emitcode ("lcall", "__gptrget");
10307       if (preserveAinB)
10308         emitcode ("pop", "b");
10309       break;
10310     }
10311 }
10312
10313 /*-----------------------------------------------------------------*/
10314 /* emitPtrByteSet - emits code to set a byte from src through a    */
10315 /*                  pointer register (R0, R1, or DPTR).            */
10316 /*-----------------------------------------------------------------*/
10317 static void
10318 emitPtrByteSet (char *rname, int p_type, char *src)
10319 {
10320   switch (p_type)
10321     {
10322     case IPOINTER:
10323     case POINTER:
10324       if (*src=='@')
10325         {
10326           MOVA (src);
10327           emitcode ("mov", "@%s,a", rname);
10328         }
10329       else
10330         emitcode ("mov", "@%s,%s", rname, src);
10331       break;
10332
10333     case PPOINTER:
10334       MOVA (src);
10335       emitcode ("movx", "@%s,a", rname);
10336       break;
10337
10338     case FPOINTER:
10339       MOVA (src);
10340       emitcode ("movx", "@dptr,a");
10341       break;
10342
10343     case GPOINTER:
10344       MOVA (src);
10345       emitcode ("lcall", "__gptrput");
10346       break;
10347     }
10348 }
10349
10350 /*-----------------------------------------------------------------*/
10351 /* genUnpackBits - generates code for unpacking bits               */
10352 /*-----------------------------------------------------------------*/
10353 static void
10354 genUnpackBits (operand * result, char *rname, int ptype)
10355 {
10356   int offset = 0;       /* result byte offset */
10357   int rsize;            /* result size */
10358   int rlen = 0;         /* remaining bitfield length */
10359   sym_link *etype;      /* bitfield type information */
10360   int blen;             /* bitfield length */
10361   int bstr;             /* bitfield starting bit within byte */
10362
10363   D(emitcode (";     genUnpackBits",""));
10364
10365   etype = getSpec (operandType (result));
10366   rsize = getSize (operandType (result));
10367   blen = SPEC_BLEN (etype);
10368   bstr = SPEC_BSTR (etype);
10369
10370   /* If the bitfield length is less than a byte */
10371   if (blen < 8)
10372     {
10373       emitPtrByteGet (rname, ptype, FALSE);
10374       AccRol (8 - bstr);
10375       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10376       if (!SPEC_USIGN (etype))
10377         {
10378           /* signed bitfield */
10379           symbol *tlbl = newiTempLabel (NULL);
10380
10381           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10382           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10383           emitLabel (tlbl);
10384         }
10385       aopPut (result, "a", offset++);
10386       goto finish;
10387     }
10388
10389   /* Bit field did not fit in a byte. Copy all
10390      but the partial byte at the end.  */
10391   for (rlen=blen;rlen>=8;rlen-=8)
10392     {
10393       emitPtrByteGet (rname, ptype, FALSE);
10394       aopPut (result, "a", offset++);
10395       if (rlen>8)
10396         emitcode ("inc", "%s", rname);
10397     }
10398
10399   /* Handle the partial byte at the end */
10400   if (rlen)
10401     {
10402       emitPtrByteGet (rname, ptype, FALSE);
10403       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10404       if (!SPEC_USIGN (etype))
10405         {
10406           /* signed bitfield */
10407           symbol *tlbl = newiTempLabel (NULL);
10408
10409           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10410           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10411           emitLabel (tlbl);
10412         }
10413       aopPut (result, "a", offset++);
10414     }
10415
10416 finish:
10417   if (offset < rsize)
10418     {
10419       char *source;
10420
10421       if (SPEC_USIGN (etype))
10422         source = zero;
10423       else
10424         {
10425           /* signed bitfield: sign extension with 0x00 or 0xff */
10426           emitcode ("rlc", "a");
10427           emitcode ("subb", "a,acc");
10428
10429           source = "a";
10430         }
10431       rsize -= offset;
10432       while (rsize--)
10433         aopPut (result, source, offset++);
10434     }
10435 }
10436
10437
10438 /*-----------------------------------------------------------------*/
10439 /* genDataPointerGet - generates code when ptr offset is known     */
10440 /*-----------------------------------------------------------------*/
10441 static void
10442 genDataPointerGet (operand * left,
10443                    operand * result,
10444                    iCode * ic)
10445 {
10446   char *l;
10447   char buffer[256];
10448   int size, offset = 0;
10449   aopOp (result, ic, TRUE, FALSE);
10450
10451   /* get the string representation of the name */
10452   l = aopGet (left, 0, FALSE, TRUE, NULL);
10453   size = AOP_SIZE (result);
10454   _startLazyDPSEvaluation ();
10455   while (size--)
10456     {
10457         if (offset)
10458         {
10459             SNPRINTF (buffer, sizeof(buffer),
10460                       "(%s + %d)", l + 1, offset);
10461         }
10462         else
10463         {
10464             SNPRINTF (buffer, sizeof(buffer),
10465                       "%s", l + 1);
10466         }
10467       aopPut (result, buffer, offset++);
10468     }
10469   _endLazyDPSEvaluation ();
10470
10471   freeAsmop (result, NULL, ic, TRUE);
10472   freeAsmop (left, NULL, ic, TRUE);
10473 }
10474
10475 /*-----------------------------------------------------------------*/
10476 /* genNearPointerGet - emitcode for near pointer fetch             */
10477 /*-----------------------------------------------------------------*/
10478 static void
10479 genNearPointerGet (operand * left,
10480                    operand * result,
10481                    iCode * ic,
10482                    iCode *pi)
10483 {
10484   asmop *aop = NULL;
10485   regs *preg;
10486   char *rname;
10487   sym_link *rtype, *retype, *letype;
10488   sym_link *ltype = operandType (left);
10489   char buffer[80];
10490
10491   rtype = operandType (result);
10492   retype = getSpec (rtype);
10493   letype = getSpec (ltype);
10494
10495   aopOp (left, ic, FALSE, FALSE);
10496
10497   /* if left is rematerialisable and
10498      result is not bitfield variable type and
10499      the left is pointer to data space i.e
10500      lower 128 bytes of space */
10501   if (AOP_TYPE (left) == AOP_IMMD &&
10502       !IS_BITFIELD (retype) &&
10503       !IS_BITFIELD (letype) &&
10504       DCL_TYPE (ltype) == POINTER)
10505     {
10506       genDataPointerGet (left, result, ic);
10507       return;
10508     }
10509
10510   /* if the value is already in a pointer register
10511      then don't need anything more */
10512   if (!AOP_INPREG (AOP (left)))
10513     {
10514       /* otherwise get a free pointer register */
10515       aop = newAsmop (0);
10516       preg = getFreePtr (ic, &aop, FALSE);
10517       emitcode ("mov", "%s,%s",
10518                 preg->name,
10519                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10520       rname = preg->name;
10521     }
10522   else
10523     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10524
10525   freeAsmop (left, NULL, ic, TRUE);
10526   aopOp (result, ic, FALSE, FALSE);
10527
10528   /* if bitfield then unpack the bits */
10529   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10530     genUnpackBits (result, rname, POINTER);
10531   else
10532     {
10533       /* we have can just get the values */
10534       int size = AOP_SIZE (result);
10535       int offset = 0;
10536
10537       while (size--)
10538         {
10539           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10540             {
10541
10542               emitcode ("mov", "a,@%s", rname);
10543               aopPut (result, "a", offset);
10544             }
10545           else
10546             {
10547               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10548               aopPut (result, buffer, offset);
10549             }
10550           offset++;
10551           if (size || pi)
10552             emitcode ("inc", "%s", rname);
10553         }
10554     }
10555
10556   /* now some housekeeping stuff */
10557   if (aop)      /* we had to allocate for this iCode */
10558     {
10559       if (pi) { /* post increment present */
10560         aopPut (left, rname, 0);
10561       }
10562       freeAsmop (NULL, aop, ic, TRUE);
10563     }
10564   else
10565     {
10566       /* we did not allocate which means left
10567          already in a pointer register, then
10568          if size > 0 && this could be used again
10569          we have to point it back to where it
10570          belongs */
10571       if (AOP_SIZE (result) > 1 &&
10572           !OP_SYMBOL (left)->remat &&
10573           (OP_SYMBOL (left)->liveTo > ic->seq ||
10574            ic->depth) &&
10575           !pi)
10576         {
10577           int size = AOP_SIZE (result) - 1;
10578           while (size--)
10579             emitcode ("dec", "%s", rname);
10580         }
10581     }
10582
10583   /* done */
10584   freeAsmop (result, NULL, ic, TRUE);
10585   if (pi) pi->generated = 1;
10586 }
10587
10588 /*-----------------------------------------------------------------*/
10589 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10590 /*-----------------------------------------------------------------*/
10591 static void
10592 genPagedPointerGet (operand * left,
10593                     operand * result,
10594                     iCode * ic,
10595                     iCode * pi)
10596 {
10597   asmop *aop = NULL;
10598   regs *preg;
10599   char *rname;
10600   sym_link *rtype, *retype, *letype;
10601
10602   rtype = operandType (result);
10603   retype = getSpec (rtype);
10604   letype = getSpec (operandType (left));
10605   aopOp (left, ic, FALSE, FALSE);
10606
10607   /* if the value is already in a pointer register
10608      then don't need anything more */
10609   if (!AOP_INPREG (AOP (left)))
10610     {
10611       /* otherwise get a free pointer register */
10612       aop = newAsmop (0);
10613       preg = getFreePtr (ic, &aop, FALSE);
10614       emitcode ("mov", "%s,%s",
10615                 preg->name,
10616                 aopGet (left, 0, FALSE, TRUE, NULL));
10617       rname = preg->name;
10618     }
10619   else
10620     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10621
10622   freeAsmop (left, NULL, ic, TRUE);
10623   aopOp (result, ic, FALSE, FALSE);
10624
10625   /* if bitfield then unpack the bits */
10626   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10627     genUnpackBits (result, rname, PPOINTER);
10628   else
10629     {
10630       /* we have can just get the values */
10631       int size = AOP_SIZE (result);
10632       int offset = 0;
10633
10634       while (size--)
10635         {
10636
10637           emitcode ("movx", "a,@%s", rname);
10638           aopPut (result, "a", offset);
10639
10640           offset++;
10641
10642           if (size || pi)
10643             emitcode ("inc", "%s", rname);
10644         }
10645     }
10646
10647   /* now some housekeeping stuff */
10648   if (aop)      /* we had to allocate for this iCode */
10649     {
10650       if (pi)
10651         aopPut (left, rname, 0);
10652       freeAsmop (NULL, aop, ic, TRUE);
10653     }
10654   else
10655     {
10656       /* we did not allocate which means left
10657          already in a pointer register, then
10658          if size > 0 && this could be used again
10659          we have to point it back to where it
10660          belongs */
10661       if (AOP_SIZE (result) > 1 &&
10662           !OP_SYMBOL (left)->remat &&
10663           (OP_SYMBOL (left)->liveTo > ic->seq ||
10664            ic->depth) &&
10665           !pi)
10666         {
10667           int size = AOP_SIZE (result) - 1;
10668           while (size--)
10669             emitcode ("dec", "%s", rname);
10670         }
10671     }
10672
10673   /* done */
10674   freeAsmop (result, NULL, ic, TRUE);
10675   if (pi) pi->generated = 1;
10676 }
10677
10678 /*-----------------------------------------------------------------*/
10679 /* genFarPointerGet - get value from far space                     */
10680 /*-----------------------------------------------------------------*/
10681 static void
10682 genFarPointerGet (operand * left,
10683                   operand * result, iCode * ic, iCode *pi)
10684 {
10685   int size, offset, dopi=1;
10686   sym_link *retype = getSpec (operandType (result));
10687   sym_link *letype = getSpec (operandType (left));
10688   D (emitcode (";", "genFarPointerGet"););
10689
10690   aopOp (left, ic, FALSE, FALSE);
10691
10692   /* if the operand is already in dptr
10693      then we do nothing else we move the value to dptr */
10694   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10695     {
10696       /* if this is rematerializable */
10697       if (AOP_TYPE (left) == AOP_IMMD)
10698         {
10699           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10700         }
10701       else
10702         {
10703           /* we need to get it byte by byte */
10704           _startLazyDPSEvaluation ();
10705           if (AOP_TYPE (left) != AOP_DPTR)
10706             {
10707               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10708               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10709               if (options.model == MODEL_FLAT24)
10710                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10711             }
10712           else
10713             {
10714               /* We need to generate a load to DPTR indirect through DPTR. */
10715               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10716               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10717               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10718               if (options.model == MODEL_FLAT24)
10719                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10720               emitcode ("pop", "dph");
10721               emitcode ("pop", "dpl");
10722               dopi =0;
10723             }
10724           _endLazyDPSEvaluation ();
10725         }
10726     }
10727   /* so dptr now contains the address */
10728   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10729
10730   /* if bit then unpack */
10731   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10732       if (AOP_INDPTRn(left)) {
10733           genSetDPTR(AOP(left)->aopu.dptr);
10734       }
10735       genUnpackBits (result, "dptr", FPOINTER);
10736       if (AOP_INDPTRn(left)) {
10737           genSetDPTR(0);
10738       }
10739   } else
10740     {
10741       size = AOP_SIZE (result);
10742       offset = 0;
10743
10744       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10745           while (size--) {
10746               genSetDPTR(AOP(left)->aopu.dptr);
10747               emitcode ("movx", "a,@dptr");
10748               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10749                   emitcode ("inc", "dptr");
10750               genSetDPTR (0);
10751               aopPut (result, "a", offset++);
10752           }
10753       } else {
10754           _startLazyDPSEvaluation ();
10755           while (size--) {
10756               if (AOP_INDPTRn(left)) {
10757                   genSetDPTR(AOP(left)->aopu.dptr);
10758               } else {
10759                   genSetDPTR (0);
10760               }
10761               _flushLazyDPS ();
10762
10763               emitcode ("movx", "a,@dptr");
10764               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10765                   emitcode ("inc", "dptr");
10766
10767               aopPut (result, "a", offset++);
10768           }
10769           _endLazyDPSEvaluation ();
10770       }
10771     }
10772   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10773       if (!AOP_INDPTRn(left)) {
10774           _startLazyDPSEvaluation ();
10775           aopPut (left, "dpl", 0);
10776           aopPut (left, "dph", 1);
10777           if (options.model == MODEL_FLAT24)
10778               aopPut (left, "dpx", 2);
10779           _endLazyDPSEvaluation ();
10780       }
10781     pi->generated = 1;
10782   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10783              AOP_SIZE(result) > 1 &&
10784              IS_SYMOP(left) &&
10785              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10786
10787       size = AOP_SIZE (result) - 1;
10788       if (AOP_INDPTRn(left)) {
10789           genSetDPTR(AOP(left)->aopu.dptr);
10790       }
10791       while (size--) emitcode ("lcall","__decdptr");
10792       if (AOP_INDPTRn(left)) {
10793           genSetDPTR(0);
10794       }
10795   }
10796
10797   freeAsmop (result, NULL, ic, TRUE);
10798   freeAsmop (left, NULL, ic, TRUE);
10799 }
10800
10801 /*-----------------------------------------------------------------*/
10802 /* genCodePointerGet - get value from code space                   */
10803 /*-----------------------------------------------------------------*/
10804 static void
10805 genCodePointerGet (operand * left,
10806                     operand * result, iCode * ic, iCode *pi)
10807 {
10808   int size, offset, dopi=1;
10809   sym_link *retype = getSpec (operandType (result));
10810
10811   aopOp (left, ic, FALSE, FALSE);
10812
10813   /* if the operand is already in dptr
10814      then we do nothing else we move the value to dptr */
10815   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10816     {
10817       /* if this is rematerializable */
10818       if (AOP_TYPE (left) == AOP_IMMD)
10819         {
10820           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10821         }
10822       else
10823         {                       /* we need to get it byte by byte */
10824           _startLazyDPSEvaluation ();
10825           if (AOP_TYPE (left) != AOP_DPTR)
10826             {
10827               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10828               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10829               if (options.model == MODEL_FLAT24)
10830                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10831             }
10832           else
10833             {
10834               /* We need to generate a load to DPTR indirect through DPTR. */
10835               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10836               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10837               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10838               if (options.model == MODEL_FLAT24)
10839                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10840               emitcode ("pop", "dph");
10841               emitcode ("pop", "dpl");
10842               dopi=0;
10843             }
10844           _endLazyDPSEvaluation ();
10845         }
10846     }
10847   /* so dptr now contains the address */
10848   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10849
10850   /* if bit then unpack */
10851   if (IS_BITFIELD (retype)) {
10852       if (AOP_INDPTRn(left)) {
10853           genSetDPTR(AOP(left)->aopu.dptr);
10854       }
10855       genUnpackBits (result, "dptr", CPOINTER);
10856       if (AOP_INDPTRn(left)) {
10857           genSetDPTR(0);
10858       }
10859   } else
10860     {
10861       size = AOP_SIZE (result);
10862       offset = 0;
10863       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10864           while (size--) {
10865               genSetDPTR(AOP(left)->aopu.dptr);
10866               emitcode ("clr", "a");
10867               emitcode ("movc", "a,@a+dptr");
10868               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10869                   emitcode ("inc", "dptr");
10870               genSetDPTR (0);
10871               aopPut (result, "a", offset++);
10872           }
10873       } else {
10874           _startLazyDPSEvaluation ();
10875           while (size--)
10876               {
10877                   if (AOP_INDPTRn(left)) {
10878                       genSetDPTR(AOP(left)->aopu.dptr);
10879                   } else {
10880                       genSetDPTR (0);
10881                   }
10882                   _flushLazyDPS ();
10883
10884                   emitcode ("clr", "a");
10885                   emitcode ("movc", "a,@a+dptr");
10886                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10887                       emitcode ("inc", "dptr");
10888                   aopPut (result, "a", offset++);
10889               }
10890           _endLazyDPSEvaluation ();
10891       }
10892     }
10893   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10894       if (!AOP_INDPTRn(left)) {
10895           _startLazyDPSEvaluation ();
10896
10897           aopPut (left, "dpl", 0);
10898           aopPut (left, "dph", 1);
10899           if (options.model == MODEL_FLAT24)
10900               aopPut (left, "dpx", 2);
10901
10902           _endLazyDPSEvaluation ();
10903       }
10904       pi->generated = 1;
10905   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10906              AOP_SIZE(result) > 1 &&
10907              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10908
10909       size = AOP_SIZE (result) - 1;
10910       if (AOP_INDPTRn(left)) {
10911           genSetDPTR(AOP(left)->aopu.dptr);
10912       }
10913       while (size--) emitcode ("lcall","__decdptr");
10914       if (AOP_INDPTRn(left)) {
10915           genSetDPTR(0);
10916       }
10917   }
10918
10919   freeAsmop (result, NULL, ic, TRUE);
10920   freeAsmop (left, NULL, ic, TRUE);
10921 }
10922
10923 /*-----------------------------------------------------------------*/
10924 /* genGenPointerGet - get value from generic pointer space         */
10925 /*-----------------------------------------------------------------*/
10926 static void
10927 genGenPointerGet (operand * left,
10928                   operand * result, iCode * ic, iCode * pi)
10929 {
10930   int size, offset;
10931   bool pushedB;
10932   sym_link *retype = getSpec (operandType (result));
10933   sym_link *letype = getSpec (operandType (left));
10934
10935   D (emitcode (";", "genGenPointerGet"));
10936
10937   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10938
10939   pushedB = pushB ();
10940   /* if the operand is already in dptr
10941      then we do nothing else we move the value to dptr */
10942   if (AOP_TYPE (left) != AOP_STR)
10943     {
10944       /* if this is rematerializable */
10945       if (AOP_TYPE (left) == AOP_IMMD)
10946         {
10947           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10948           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10949             {
10950               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10951             }
10952           else
10953             {
10954               emitcode ("mov", "b,#%d", pointerCode (retype));
10955             }
10956         }
10957       else
10958         {                       /* we need to get it byte by byte */
10959           _startLazyDPSEvaluation ();
10960           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10961           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10962           if (options.model == MODEL_FLAT24) {
10963               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10964               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10965           } else {
10966               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10967           }
10968           _endLazyDPSEvaluation ();
10969         }
10970     }
10971
10972   /* so dptr-b now contains the address */
10973   aopOp (result, ic, FALSE, TRUE);
10974
10975   /* if bit then unpack */
10976   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10977   {
10978     genUnpackBits (result, "dptr", GPOINTER);
10979   }
10980   else
10981     {
10982         size = AOP_SIZE (result);
10983         offset = 0;
10984
10985         while (size--)
10986         {
10987             if (size)
10988             {
10989                 // Get two bytes at a time, results in _AP & A.
10990                 // dptr will be incremented ONCE by __gptrgetWord.
10991                 //
10992                 // Note: any change here must be coordinated
10993                 // with the implementation of __gptrgetWord
10994                 // in device/lib/_gptrget.c
10995                 emitcode ("lcall", "__gptrgetWord");
10996                 aopPut (result, DP2_RESULT_REG, offset++);
10997                 aopPut (result, "a", offset++);
10998                 size--;
10999             }
11000             else
11001             {
11002                 // Only one byte to get.
11003                 emitcode ("lcall", "__gptrget");
11004                 aopPut (result, "a", offset++);
11005             }
11006
11007             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11008             {
11009                 emitcode ("inc", "dptr");
11010             }
11011         }
11012     }
11013
11014   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11015     _startLazyDPSEvaluation ();
11016
11017     aopPut (left, "dpl", 0);
11018     aopPut (left, "dph", 1);
11019     if (options.model == MODEL_FLAT24) {
11020         aopPut (left, "dpx", 2);
11021         aopPut (left, "b", 3);
11022     } else  aopPut (left, "b", 2);
11023
11024     _endLazyDPSEvaluation ();
11025
11026     pi->generated = 1;
11027   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11028              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11029
11030       size = AOP_SIZE (result) - 1;
11031       while (size--) emitcode ("lcall","__decdptr");
11032   }
11033   popB (pushedB);
11034
11035   freeAsmop (result, NULL, ic, TRUE);
11036   freeAsmop (left, NULL, ic, TRUE);
11037 }
11038
11039 /*-----------------------------------------------------------------*/
11040 /* genPointerGet - generate code for pointer get                   */
11041 /*-----------------------------------------------------------------*/
11042 static void
11043 genPointerGet (iCode * ic, iCode *pi)
11044 {
11045   operand *left, *result;
11046   sym_link *type, *etype;
11047   int p_type;
11048
11049   D (emitcode (";", "genPointerGet"));
11050
11051   left = IC_LEFT (ic);
11052   result = IC_RESULT (ic);
11053
11054   /* depending on the type of pointer we need to
11055      move it to the correct pointer register */
11056   type = operandType (left);
11057   etype = getSpec (type);
11058   /* if left is of type of pointer then it is simple */
11059   if (IS_PTR (type) && !IS_FUNC (type->next))
11060     p_type = DCL_TYPE (type);
11061   else
11062     {
11063       /* we have to go by the storage class */
11064       p_type = PTR_TYPE (SPEC_OCLS (etype));
11065     }
11066
11067   /* special case when cast remat */
11068   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11069       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11070     {
11071       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11072       type = operandType (left);
11073       p_type = DCL_TYPE (type);
11074     }
11075   /* now that we have the pointer type we assign
11076      the pointer values */
11077   switch (p_type)
11078     {
11079
11080     case POINTER:
11081     case IPOINTER:
11082       genNearPointerGet (left, result, ic, pi);
11083       break;
11084
11085     case PPOINTER:
11086       genPagedPointerGet (left, result, ic, pi);
11087       break;
11088
11089     case FPOINTER:
11090       genFarPointerGet (left, result, ic, pi);
11091       break;
11092
11093     case CPOINTER:
11094       genCodePointerGet (left, result, ic, pi);
11095       break;
11096
11097     case GPOINTER:
11098       genGenPointerGet (left, result, ic, pi);
11099       break;
11100     }
11101 }
11102
11103
11104 /*-----------------------------------------------------------------*/
11105 /* genPackBits - generates code for packed bit storage             */
11106 /*-----------------------------------------------------------------*/
11107 static void
11108 genPackBits (sym_link * etype,
11109              operand * right,
11110              char *rname, int p_type)
11111 {
11112   int offset = 0;       /* source byte offset */
11113   int rlen = 0;         /* remaining bitfield length */
11114   int blen;             /* bitfield length */
11115   int bstr;             /* bitfield starting bit within byte */
11116   int litval;           /* source literal value (if AOP_LIT) */
11117   unsigned char mask;   /* bitmask within current byte */
11118
11119   D(emitcode (";     genPackBits",""));
11120
11121   blen = SPEC_BLEN (etype);
11122   bstr = SPEC_BSTR (etype);
11123
11124   /* If the bitfield length is less than a byte */
11125   if (blen < 8)
11126     {
11127       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11128               (unsigned char) (0xFF >> (8 - bstr)));
11129
11130       if (AOP_TYPE (right) == AOP_LIT)
11131         {
11132           /* Case with a bitfield length <8 and literal source
11133           */
11134           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11135           litval <<= bstr;
11136           litval &= (~mask) & 0xff;
11137           emitPtrByteGet (rname, p_type, FALSE);
11138           if ((mask|litval)!=0xff)
11139             emitcode ("anl","a,#!constbyte", mask);
11140           if (litval)
11141             emitcode ("orl","a,#!constbyte", litval);
11142         }
11143       else
11144         {
11145           if ((blen==1) && (p_type!=GPOINTER))
11146             {
11147               /* Case with a bitfield length == 1 and no generic pointer
11148               */
11149               if (AOP_TYPE (right) == AOP_CRY)
11150                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11151               else
11152                 {
11153                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11154                   emitcode ("rrc","a");
11155                 }
11156               emitPtrByteGet (rname, p_type, FALSE);
11157               emitcode ("mov","acc.%d,c",bstr);
11158             }
11159           else
11160             {
11161               bool pushedB;
11162               /* Case with a bitfield length < 8 and arbitrary source
11163               */
11164               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11165               /* shift and mask source value */
11166               AccLsh (bstr);
11167               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11168
11169               pushedB = pushB ();
11170               /* transfer A to B and get next byte */
11171               emitPtrByteGet (rname, p_type, TRUE);
11172
11173               emitcode ("anl", "a,#!constbyte", mask);
11174               emitcode ("orl", "a,b");
11175               if (p_type == GPOINTER)
11176                 emitcode ("pop", "b");
11177
11178               popB (pushedB);
11179            }
11180         }
11181
11182       emitPtrByteSet (rname, p_type, "a");
11183       return;
11184     }
11185
11186   /* Bit length is greater than 7 bits. In this case, copy  */
11187   /* all except the partial byte at the end                 */
11188   for (rlen=blen;rlen>=8;rlen-=8)
11189     {
11190       emitPtrByteSet (rname, p_type,
11191                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11192       if (rlen>8)
11193         emitcode ("inc", "%s", rname);
11194     }
11195
11196   /* If there was a partial byte at the end */
11197   if (rlen)
11198     {
11199       mask = (((unsigned char) -1 << rlen) & 0xff);
11200
11201       if (AOP_TYPE (right) == AOP_LIT)
11202         {
11203           /* Case with partial byte and literal source
11204           */
11205           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11206           litval >>= (blen-rlen);
11207           litval &= (~mask) & 0xff;
11208           emitPtrByteGet (rname, p_type, FALSE);
11209           if ((mask|litval)!=0xff)
11210             emitcode ("anl","a,#!constbyte", mask);
11211           if (litval)
11212             emitcode ("orl","a,#!constbyte", litval);
11213         }
11214       else
11215         {
11216           bool pushedB;
11217           /* Case with partial byte and arbitrary source
11218           */
11219           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11220           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11221
11222           pushedB = pushB ();
11223           /* transfer A to B and get next byte */
11224           emitPtrByteGet (rname, p_type, TRUE);
11225
11226           emitcode ("anl", "a,#!constbyte", mask);
11227           emitcode ("orl", "a,b");
11228           if (p_type == GPOINTER)
11229             emitcode ("pop", "b");
11230
11231           popB (pushedB);
11232         }
11233       emitPtrByteSet (rname, p_type, "a");
11234     }
11235 }
11236
11237
11238 /*-----------------------------------------------------------------*/
11239 /* genDataPointerSet - remat pointer to data space                 */
11240 /*-----------------------------------------------------------------*/
11241 static void
11242 genDataPointerSet (operand * right,
11243                    operand * result,
11244                    iCode * ic)
11245 {
11246   int size, offset = 0;
11247   char *l, buffer[256];
11248
11249   D (emitcode (";", "genDataPointerSet"));
11250
11251   aopOp (right, ic, FALSE, FALSE);
11252
11253   l = aopGet (result, 0, FALSE, TRUE, NULL);
11254   size = AOP_SIZE (right);
11255   while (size--)
11256     {
11257       if (offset)
11258           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11259       else
11260           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11261       emitcode ("mov", "%s,%s", buffer,
11262                 aopGet (right, offset++, FALSE, FALSE, NULL));
11263     }
11264
11265   freeAsmop (result, NULL, ic, TRUE);
11266   freeAsmop (right, NULL, ic, TRUE);
11267 }
11268
11269 /*-----------------------------------------------------------------*/
11270 /* genNearPointerSet - emitcode for near pointer put                */
11271 /*-----------------------------------------------------------------*/
11272 static void
11273 genNearPointerSet (operand * right,
11274                    operand * result,
11275                    iCode * ic,
11276                    iCode * pi)
11277 {
11278   asmop *aop = NULL;
11279   char *rname, *l;
11280   sym_link *retype, *letype;
11281   sym_link *ptype = operandType (result);
11282
11283   D (emitcode (";", "genNearPointerSet"));
11284
11285   retype = getSpec (operandType (right));
11286   letype = getSpec (ptype);
11287
11288   aopOp (result, ic, FALSE, FALSE);
11289
11290   /* if the result is rematerializable &
11291      in data space & not a bit variable */
11292   if (AOP_TYPE (result) == AOP_IMMD &&
11293       DCL_TYPE (ptype) == POINTER &&
11294       !IS_BITVAR (retype) &&
11295       !IS_BITVAR (letype))
11296     {
11297       genDataPointerSet (right, result, ic);
11298       return;
11299     }
11300
11301   /* if the value is already in a pointer register
11302      then don't need anything more */
11303   if (!AOP_INPREG (AOP (result)))
11304     {
11305       /* otherwise get a free pointer register */
11306       regs *preg;
11307
11308       aop = newAsmop (0);
11309       preg = getFreePtr (ic, &aop, FALSE);
11310       emitcode ("mov", "%s,%s",
11311                 preg->name,
11312                 aopGet (result, 0, FALSE, TRUE, NULL));
11313       rname = preg->name;
11314     }
11315   else
11316     {
11317       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11318     }
11319
11320   aopOp (right, ic, FALSE, FALSE);
11321
11322   /* if bitfield then unpack the bits */
11323   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11324     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11325   else
11326     {
11327       /* we can just get the values */
11328       int size = AOP_SIZE (right);
11329       int offset = 0;
11330
11331       while (size--)
11332         {
11333           l = aopGet (right, offset, FALSE, TRUE, NULL);
11334           if ((*l == '@') || (strcmp (l, "acc") == 0))
11335             {
11336               MOVA (l);
11337               emitcode ("mov", "@%s,a", rname);
11338             }
11339           else
11340             emitcode ("mov", "@%s,%s", rname, l);
11341           if (size || pi)
11342             emitcode ("inc", "%s", rname);
11343           offset++;
11344         }
11345     }
11346
11347   /* now some housekeeping stuff */
11348   if (aop)      /* we had to allocate for this iCode */
11349     {
11350       if (pi)
11351         aopPut (result, rname, 0);
11352       freeAsmop (NULL, aop, ic, TRUE);
11353     }
11354   else
11355     {
11356       /* we did not allocate which means left
11357          already in a pointer register, then
11358          if size > 0 && this could be used again
11359          we have to point it back to where it
11360          belongs */
11361       if (AOP_SIZE (right) > 1 &&
11362           !OP_SYMBOL (result)->remat &&
11363           (OP_SYMBOL (result)->liveTo > ic->seq ||
11364            ic->depth) &&
11365           !pi)
11366         {
11367           int size = AOP_SIZE (right) - 1;
11368           while (size--)
11369             emitcode ("dec", "%s", rname);
11370         }
11371     }
11372
11373   /* done */
11374   if (pi) pi->generated = 1;
11375   freeAsmop (result, NULL, ic, TRUE);
11376   freeAsmop (right, NULL, ic, TRUE);
11377 }
11378
11379 /*-----------------------------------------------------------------*/
11380 /* genPagedPointerSet - emitcode for Paged pointer put             */
11381 /*-----------------------------------------------------------------*/
11382 static void
11383 genPagedPointerSet (operand * right,
11384                     operand * result,
11385                     iCode * ic,
11386                     iCode *pi)
11387 {
11388   asmop *aop = NULL;
11389   char *rname, *l;
11390   sym_link *retype, *letype;
11391
11392   D (emitcode (";", "genPagedPointerSet"));
11393
11394   retype = getSpec (operandType (right));
11395   letype = getSpec (operandType (result));
11396
11397   aopOp (result, ic, FALSE, FALSE);
11398
11399   /* if the value is already in a pointer register
11400      then don't need anything more */
11401   if (!AOP_INPREG (AOP (result)))
11402     {
11403       /* otherwise get a free pointer register */
11404       regs *preg;
11405
11406       aop = newAsmop (0);
11407       preg = getFreePtr (ic, &aop, FALSE);
11408       emitcode ("mov", "%s,%s",
11409                 preg->name,
11410                 aopGet (result, 0, FALSE, TRUE, NULL));
11411       rname = preg->name;
11412     }
11413   else
11414     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11415
11416   aopOp (right, ic, FALSE, FALSE);
11417
11418   /* if bitfield then unpack the bits */
11419   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11420     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11421   else
11422     {
11423       /* we have can just get the values */
11424       int size = AOP_SIZE (right);
11425       int offset = 0;
11426
11427       while (size--)
11428         {
11429           l = aopGet (right, offset, FALSE, TRUE, NULL);
11430           MOVA (l);
11431           emitcode ("movx", "@%s,a", rname);
11432
11433           if (size || pi)
11434             emitcode ("inc", "%s", rname);
11435
11436           offset++;
11437         }
11438     }
11439
11440   /* now some housekeeping stuff */
11441   if (aop)
11442     {
11443       if (pi)
11444         aopPut (result, rname, 0);
11445       /* we had to allocate for this iCode */
11446       freeAsmop (NULL, aop, ic, TRUE);
11447     }
11448   else
11449     {
11450       /* we did not allocate which means left
11451          already in a pointer register, then
11452          if size > 0 && this could be used again
11453          we have to point it back to where it
11454          belongs */
11455       if (AOP_SIZE (right) > 1 &&
11456           !OP_SYMBOL (result)->remat &&
11457           (OP_SYMBOL (result)->liveTo > ic->seq ||
11458            ic->depth) &&
11459           !pi)
11460         {
11461           int size = AOP_SIZE (right) - 1;
11462           while (size--)
11463             emitcode ("dec", "%s", rname);
11464         }
11465     }
11466
11467   /* done */
11468   if (pi) pi->generated = 1;
11469   freeAsmop (result, NULL, ic, TRUE);
11470   freeAsmop (right, NULL, ic, TRUE);
11471 }
11472
11473 /*-----------------------------------------------------------------*/
11474 /* genFarPointerSet - set value from far space                     */
11475 /*-----------------------------------------------------------------*/
11476 static void
11477 genFarPointerSet (operand * right,
11478                   operand * result, iCode * ic, iCode *pi)
11479 {
11480   int size, offset, dopi=1;
11481   sym_link *retype = getSpec (operandType (right));
11482   sym_link *letype = getSpec (operandType (result));
11483
11484   aopOp (result, ic, FALSE, FALSE);
11485
11486   /* if the operand is already in dptr
11487      then we do nothing else we move the value to dptr */
11488   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11489     {
11490       /* if this is remateriazable */
11491       if (AOP_TYPE (result) == AOP_IMMD)
11492         emitcode ("mov", "dptr,%s",
11493                   aopGet (result, 0, TRUE, FALSE, NULL));
11494       else
11495         {
11496           /* we need to get it byte by byte */
11497           _startLazyDPSEvaluation ();
11498           if (AOP_TYPE (result) != AOP_DPTR)
11499             {
11500               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11501               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11502               if (options.model == MODEL_FLAT24)
11503                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11504             }
11505           else
11506             {
11507               /* We need to generate a load to DPTR indirect through DPTR. */
11508               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11509
11510               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11511               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11512               if (options.model == MODEL_FLAT24)
11513                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11514               emitcode ("pop", "dph");
11515               emitcode ("pop", "dpl");
11516               dopi=0;
11517             }
11518           _endLazyDPSEvaluation ();
11519         }
11520     }
11521   /* so dptr now contains the address */
11522   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11523
11524   /* if bit then unpack */
11525   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11526   {
11527       if (AOP_INDPTRn(result)) {
11528           genSetDPTR(AOP(result)->aopu.dptr);
11529       }
11530       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11531       if (AOP_INDPTRn(result)) {
11532           genSetDPTR(0);
11533       }
11534   } else {
11535       size = AOP_SIZE (right);
11536       offset = 0;
11537       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11538           while (size--) {
11539               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11540
11541               genSetDPTR(AOP(result)->aopu.dptr);
11542               emitcode ("movx", "@dptr,a");
11543               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11544                   emitcode ("inc", "dptr");
11545               genSetDPTR (0);
11546           }
11547       } else {
11548           _startLazyDPSEvaluation ();
11549           while (size--) {
11550               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11551
11552               if (AOP_INDPTRn(result)) {
11553                   genSetDPTR(AOP(result)->aopu.dptr);
11554               } else {
11555                   genSetDPTR (0);
11556               }
11557               _flushLazyDPS ();
11558
11559               emitcode ("movx", "@dptr,a");
11560               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11561                   emitcode ("inc", "dptr");
11562           }
11563           _endLazyDPSEvaluation ();
11564       }
11565   }
11566
11567   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11568       if (!AOP_INDPTRn(result)) {
11569           _startLazyDPSEvaluation ();
11570
11571           aopPut (result,"dpl",0);
11572           aopPut (result,"dph",1);
11573           if (options.model == MODEL_FLAT24)
11574               aopPut (result,"dpx",2);
11575
11576           _endLazyDPSEvaluation ();
11577       }
11578       pi->generated=1;
11579   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11580              AOP_SIZE(right) > 1 &&
11581              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11582
11583       size = AOP_SIZE (right) - 1;
11584       if (AOP_INDPTRn(result)) {
11585           genSetDPTR(AOP(result)->aopu.dptr);
11586       }
11587       while (size--) emitcode ("lcall","__decdptr");
11588       if (AOP_INDPTRn(result)) {
11589           genSetDPTR(0);
11590       }
11591   }
11592   freeAsmop (result, NULL, ic, TRUE);
11593   freeAsmop (right, NULL, ic, TRUE);
11594 }
11595
11596 /*-----------------------------------------------------------------*/
11597 /* genGenPointerSet - set value from generic pointer space         */
11598 /*-----------------------------------------------------------------*/
11599 static void
11600 genGenPointerSet (operand * right,
11601                   operand * result, iCode * ic, iCode *pi)
11602 {
11603   int size, offset;
11604   bool pushedB;
11605   sym_link *retype = getSpec (operandType (right));
11606   sym_link *letype = getSpec (operandType (result));
11607
11608   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11609
11610   pushedB = pushB ();
11611   /* if the operand is already in dptr
11612      then we do nothing else we move the value to dptr */
11613   if (AOP_TYPE (result) != AOP_STR)
11614     {
11615       _startLazyDPSEvaluation ();
11616       /* if this is remateriazable */
11617       if (AOP_TYPE (result) == AOP_IMMD)
11618         {
11619           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11620           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11621           {
11622               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11623           }
11624           else
11625           {
11626               emitcode ("mov",
11627                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11628           }
11629         }
11630       else
11631         {                       /* we need to get it byte by byte */
11632           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11633           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11634           if (options.model == MODEL_FLAT24) {
11635             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11636             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11637           } else {
11638             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11639           }
11640         }
11641       _endLazyDPSEvaluation ();
11642     }
11643   /* so dptr + b now contains the address */
11644   aopOp (right, ic, FALSE, TRUE);
11645
11646   /* if bit then unpack */
11647   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11648     {
11649         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11650     }
11651   else
11652     {
11653         size = AOP_SIZE (right);
11654         offset = 0;
11655
11656         _startLazyDPSEvaluation ();
11657         while (size--)
11658         {
11659             if (size)
11660             {
11661                 // Set two bytes at a time, passed in _AP & A.
11662                 // dptr will be incremented ONCE by __gptrputWord.
11663                 //
11664                 // Note: any change here must be coordinated
11665                 // with the implementation of __gptrputWord
11666                 // in device/lib/_gptrput.c
11667                 emitcode("mov", "_ap, %s",
11668                          aopGet (right, offset++, FALSE, FALSE, NULL));
11669                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11670
11671                 genSetDPTR (0);
11672                 _flushLazyDPS ();
11673                 emitcode ("lcall", "__gptrputWord");
11674                 size--;
11675             }
11676             else
11677             {
11678                 // Only one byte to put.
11679                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11680
11681                 genSetDPTR (0);
11682                 _flushLazyDPS ();
11683                 emitcode ("lcall", "__gptrput");
11684             }
11685
11686             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11687             {
11688                 emitcode ("inc", "dptr");
11689             }
11690         }
11691         _endLazyDPSEvaluation ();
11692     }
11693
11694   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11695       _startLazyDPSEvaluation ();
11696
11697       aopPut (result, "dpl",0);
11698       aopPut (result, "dph",1);
11699       if (options.model == MODEL_FLAT24) {
11700           aopPut (result, "dpx",2);
11701           aopPut (result, "b",3);
11702       } else {
11703           aopPut (result, "b",2);
11704       }
11705       _endLazyDPSEvaluation ();
11706
11707       pi->generated=1;
11708   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11709              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11710
11711       size = AOP_SIZE (right) - 1;
11712       while (size--) emitcode ("lcall","__decdptr");
11713   }
11714   popB (pushedB);
11715
11716   freeAsmop (result, NULL, ic, TRUE);
11717   freeAsmop (right, NULL, ic, TRUE);
11718 }
11719
11720 /*-----------------------------------------------------------------*/
11721 /* genPointerSet - stores the value into a pointer location        */
11722 /*-----------------------------------------------------------------*/
11723 static void
11724 genPointerSet (iCode * ic, iCode *pi)
11725 {
11726   operand *right, *result;
11727   sym_link *type, *etype;
11728   int p_type;
11729
11730   D (emitcode (";", "genPointerSet"));
11731
11732   right = IC_RIGHT (ic);
11733   result = IC_RESULT (ic);
11734
11735   /* depending on the type of pointer we need to
11736      move it to the correct pointer register */
11737   type = operandType (result);
11738   etype = getSpec (type);
11739   /* if left is of type of pointer then it is simple */
11740   if (IS_PTR (type) && !IS_FUNC (type->next))
11741     {
11742       p_type = DCL_TYPE (type);
11743     }
11744   else
11745     {
11746       /* we have to go by the storage class */
11747       p_type = PTR_TYPE (SPEC_OCLS (etype));
11748     }
11749
11750   /* special case when cast remat */
11751   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11752       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11753           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11754           type = operandType (result);
11755           p_type = DCL_TYPE (type);
11756   }
11757
11758   /* now that we have the pointer type we assign
11759      the pointer values */
11760   switch (p_type)
11761     {
11762
11763     case POINTER:
11764     case IPOINTER:
11765       genNearPointerSet (right, result, ic, pi);
11766       break;
11767
11768     case PPOINTER:
11769       genPagedPointerSet (right, result, ic, pi);
11770       break;
11771
11772     case FPOINTER:
11773       genFarPointerSet (right, result, ic, pi);
11774       break;
11775
11776     case GPOINTER:
11777       genGenPointerSet (right, result, ic, pi);
11778       break;
11779
11780     default:
11781       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11782               "genPointerSet: illegal pointer type");
11783     }
11784 }
11785
11786 /*-----------------------------------------------------------------*/
11787 /* genIfx - generate code for Ifx statement                        */
11788 /*-----------------------------------------------------------------*/
11789 static void
11790 genIfx (iCode * ic, iCode * popIc)
11791 {
11792   operand *cond = IC_COND (ic);
11793   int isbit = 0;
11794   char *dup = NULL;
11795
11796   D (emitcode (";", "genIfx"));
11797
11798   aopOp (cond, ic, FALSE, FALSE);
11799
11800   /* get the value into acc */
11801   if (AOP_TYPE (cond) != AOP_CRY)
11802     {
11803       toBoolean (cond);
11804     }
11805   else
11806     {
11807       isbit = 1;
11808       if (AOP(cond)->aopu.aop_dir)
11809         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11810     }
11811
11812   /* the result is now in the accumulator or a directly addressable bit */
11813   freeAsmop (cond, NULL, ic, TRUE);
11814
11815   /* if there was something to be popped then do it */
11816   if (popIc)
11817     genIpop (popIc);
11818
11819   /* if the condition is a bit variable */
11820   if (isbit && dup)
11821     genIfxJump (ic, dup);
11822   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11823     genIfxJump (ic, SPIL_LOC (cond)->rname);
11824   else if (isbit && !IS_ITEMP (cond))
11825     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11826   else
11827     genIfxJump (ic, "a");
11828
11829   ic->generated = 1;
11830 }
11831
11832 /*-----------------------------------------------------------------*/
11833 /* genAddrOf - generates code for address of                       */
11834 /*-----------------------------------------------------------------*/
11835 static void
11836 genAddrOf (iCode * ic)
11837 {
11838   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11839   int size, offset;
11840
11841   D (emitcode (";", "genAddrOf"));
11842
11843   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11844
11845   /* if the operand is on the stack then we
11846      need to get the stack offset of this
11847      variable */
11848   if (sym->onStack)
11849   {
11850
11851       /* if 10 bit stack */
11852       if (options.stack10bit) {
11853           char buff[10];
11854           int  offset;
11855
11856           tsprintf(buff, sizeof(buff),
11857                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11858           /* if it has an offset then we need to compute it */
11859 /*        emitcode ("subb", "a,#!constbyte", */
11860 /*                  -((sym->stack < 0) ? */
11861 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11862 /*                    ((short) sym->stack)) & 0xff); */
11863 /*        emitcode ("mov","b,a"); */
11864 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11865 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11866 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11867           if (sym->stack) {
11868               emitcode ("mov", "a,_bpx");
11869               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11870                                              ((char) (sym->stack - _G.nRegsSaved)) :
11871                                              ((char) sym->stack )) & 0xff);
11872               emitcode ("mov", "b,a");
11873               emitcode ("mov", "a,_bpx+1");
11874
11875               offset = (((sym->stack < 0) ?
11876                          ((short) (sym->stack - _G.nRegsSaved)) :
11877                          ((short) sym->stack )) >> 8) & 0xff;
11878
11879               emitcode ("addc","a,#!constbyte", offset);
11880
11881               aopPut (IC_RESULT (ic), "b", 0);
11882               aopPut (IC_RESULT (ic), "a", 1);
11883               aopPut (IC_RESULT (ic), buff, 2);
11884           } else {
11885               /* we can just move _bp */
11886               aopPut (IC_RESULT (ic), "_bpx", 0);
11887               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11888               aopPut (IC_RESULT (ic), buff, 2);
11889           }
11890       } else {
11891           /* if it has an offset then we need to compute it */
11892           if (sym->stack)
11893             {
11894               emitcode ("mov", "a,_bp");
11895               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11896               aopPut (IC_RESULT (ic), "a", 0);
11897             }
11898           else
11899             {
11900               /* we can just move _bp */
11901               aopPut (IC_RESULT (ic), "_bp", 0);
11902             }
11903           /* fill the result with zero */
11904           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11905
11906
11907           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11908               fprintf (stderr,
11909                        "*** warning: pointer to stack var truncated.\n");
11910           }
11911
11912           offset = 1;
11913           while (size--)
11914             {
11915               aopPut (IC_RESULT (ic), zero, offset++);
11916             }
11917       }
11918       goto release;
11919   }
11920
11921   /* object not on stack then we need the name */
11922   size = AOP_SIZE (IC_RESULT (ic));
11923   offset = 0;
11924
11925   while (size--)
11926     {
11927       char s[SDCC_NAME_MAX];
11928       if (offset) {
11929           switch (offset) {
11930           case 1:
11931               tsprintf(s, sizeof(s), "#!his",sym->rname);
11932               break;
11933           case 2:
11934               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11935               break;
11936           case 3:
11937               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11938               break;
11939           default: /* should not need this (just in case) */
11940               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11941                        sym->rname,
11942                        offset * 8);
11943           }
11944       }
11945       else
11946       {
11947           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11948       }
11949
11950       aopPut (IC_RESULT (ic), s, offset++);
11951     }
11952
11953 release:
11954   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11955
11956 }
11957
11958 #if 0 // obsolete, and buggy for != xdata
11959 /*-----------------------------------------------------------------*/
11960 /* genArrayInit - generates code for address of                       */
11961 /*-----------------------------------------------------------------*/
11962 static void
11963 genArrayInit (iCode * ic)
11964 {
11965     literalList *iLoop;
11966     int         ix, count;
11967     int         elementSize = 0, eIndex;
11968     unsigned    val, lastVal;
11969     sym_link    *type;
11970     operand     *left=IC_LEFT(ic);
11971
11972     D (emitcode (";", "genArrayInit"));
11973
11974     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11975
11976     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11977     {
11978         // Load immediate value into DPTR.
11979         emitcode("mov", "dptr, %s",
11980              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11981     }
11982     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11983     {
11984 #if 0
11985       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11986               "Unexpected operand to genArrayInit.\n");
11987       exit(1);
11988 #else
11989       // a regression because of SDCCcse.c:1.52
11990       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11991       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11992       if (options.model == MODEL_FLAT24)
11993         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11994 #endif
11995     }
11996
11997     type = operandType(IC_LEFT(ic));
11998
11999     if (type && type->next)
12000     {
12001         elementSize = getSize(type->next);
12002     }
12003     else
12004     {
12005         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12006                                 "can't determine element size in genArrayInit.\n");
12007         exit(1);
12008     }
12009
12010     iLoop = IC_ARRAYILIST(ic);
12011     lastVal = 0xffff;
12012
12013     while (iLoop)
12014     {
12015         bool firstpass = TRUE;
12016
12017         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12018                  iLoop->count, (int)iLoop->literalValue, elementSize);
12019
12020         ix = iLoop->count;
12021
12022         while (ix)
12023         {
12024             symbol *tlbl = NULL;
12025
12026             count = ix > 256 ? 256 : ix;
12027
12028             if (count > 1)
12029             {
12030                 tlbl = newiTempLabel (NULL);
12031                 if (firstpass || (count & 0xff))
12032                 {
12033                     emitcode("mov", "b, #!constbyte", count & 0xff);
12034                 }
12035
12036                 emitLabel (tlbl);
12037             }
12038
12039             firstpass = FALSE;
12040
12041             for (eIndex = 0; eIndex < elementSize; eIndex++)
12042             {
12043                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12044                 if (val != lastVal)
12045                 {
12046                     emitcode("mov", "a, #!constbyte", val);
12047                     lastVal = val;
12048                 }
12049
12050                 emitcode("movx", "@dptr, a");
12051                 emitcode("inc", "dptr");
12052             }
12053
12054             if (count > 1)
12055             {
12056                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12057             }
12058
12059             ix -= count;
12060         }
12061
12062         iLoop = iLoop->next;
12063     }
12064
12065     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12066 }
12067 #endif
12068
12069 /*-----------------------------------------------------------------*/
12070 /* genFarFarAssign - assignment when both are in far space         */
12071 /*-----------------------------------------------------------------*/
12072 static void
12073 genFarFarAssign (operand * result, operand * right, iCode * ic)
12074 {
12075   int size = AOP_SIZE (right);
12076   int offset = 0;
12077   symbol *rSym = NULL;
12078
12079   if (size == 1)
12080   {
12081       /* quick & easy case. */
12082       D (emitcode(";","genFarFarAssign (1 byte case)"));
12083       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12084       freeAsmop (right, NULL, ic, FALSE);
12085       /* now assign DPTR to result */
12086       _G.accInUse++;
12087       aopOp(result, ic, FALSE, FALSE);
12088       _G.accInUse--;
12089       aopPut (result, "a", 0);
12090       freeAsmop(result, NULL, ic, FALSE);
12091       return;
12092   }
12093
12094   /* See if we've got an underlying symbol to abuse. */
12095   if (IS_SYMOP(result) && OP_SYMBOL(result))
12096   {
12097       if (IS_TRUE_SYMOP(result))
12098       {
12099           rSym = OP_SYMBOL(result);
12100       }
12101       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12102       {
12103           rSym = OP_SYMBOL(result)->usl.spillLoc;
12104       }
12105   }
12106
12107   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12108   {
12109       /* We can use the '390 auto-toggle feature to good effect here. */
12110
12111       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12112       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12113       emitcode ("mov", "dptr,#%s", rSym->rname);
12114       /* DP2 = result, DP1 = right, DP1 is current. */
12115       while (size)
12116       {
12117           emitcode("movx", "a,@dptr");
12118           emitcode("movx", "@dptr,a");
12119           if (--size)
12120           {
12121                emitcode("inc", "dptr");
12122                emitcode("inc", "dptr");
12123           }
12124       }
12125       emitcode("mov", "dps,#0");
12126       freeAsmop (right, NULL, ic, FALSE);
12127 #if 0
12128 some alternative code for processors without auto-toggle
12129 no time to test now, so later well put in...kpb
12130         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12131         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12132         emitcode ("mov", "dptr,#%s", rSym->rname);
12133         /* DP2 = result, DP1 = right, DP1 is current. */
12134         while (size)
12135         {
12136           --size;
12137           emitcode("movx", "a,@dptr");
12138           if (size)
12139             emitcode("inc", "dptr");
12140           emitcode("inc", "dps");
12141           emitcode("movx", "@dptr,a");
12142           if (size)
12143             emitcode("inc", "dptr");
12144           emitcode("inc", "dps");
12145         }
12146         emitcode("mov", "dps,#0");
12147         freeAsmop (right, NULL, ic, FALSE);
12148 #endif
12149   }
12150   else
12151   {
12152       D (emitcode (";", "genFarFarAssign"));
12153       aopOp (result, ic, TRUE, TRUE);
12154
12155       _startLazyDPSEvaluation ();
12156
12157       while (size--)
12158         {
12159           aopPut (result,
12160                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12161           offset++;
12162         }
12163       _endLazyDPSEvaluation ();
12164       freeAsmop (result, NULL, ic, FALSE);
12165       freeAsmop (right, NULL, ic, FALSE);
12166   }
12167 }
12168
12169 /*-----------------------------------------------------------------*/
12170 /* genAssign - generate code for assignment                        */
12171 /*-----------------------------------------------------------------*/
12172 static void
12173 genAssign (iCode * ic)
12174 {
12175   operand *result, *right;
12176   int size, offset;
12177   unsigned long lit = 0L;
12178
12179   D (emitcode (";", "genAssign"));
12180
12181   result = IC_RESULT (ic);
12182   right = IC_RIGHT (ic);
12183
12184   /* if they are the same */
12185   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12186     return;
12187
12188   aopOp (right, ic, FALSE, FALSE);
12189
12190   emitcode (";", "genAssign: resultIsFar = %s",
12191             isOperandInFarSpace (result) ?
12192             "TRUE" : "FALSE");
12193
12194   /* special case both in far space */
12195   if ((AOP_TYPE (right) == AOP_DPTR ||
12196        AOP_TYPE (right) == AOP_DPTR2) &&
12197   /* IS_TRUE_SYMOP(result)       && */
12198       isOperandInFarSpace (result))
12199     {
12200       genFarFarAssign (result, right, ic);
12201       return;
12202     }
12203
12204   aopOp (result, ic, TRUE, FALSE);
12205
12206   /* if they are the same registers */
12207   if (sameRegs (AOP (right), AOP (result)))
12208     goto release;
12209
12210   /* if the result is a bit */
12211   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12212     {
12213       /* if the right size is a literal then
12214          we know what the value is */
12215       if (AOP_TYPE (right) == AOP_LIT)
12216         {
12217           if (((int) operandLitValue (right)))
12218             aopPut (result, one, 0);
12219           else
12220             aopPut (result, zero, 0);
12221           goto release;
12222         }
12223
12224       /* the right is also a bit variable */
12225       if (AOP_TYPE (right) == AOP_CRY)
12226         {
12227           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12228           aopPut (result, "c", 0);
12229           goto release;
12230         }
12231
12232       /* we need to or */
12233       toBoolean (right);
12234       aopPut (result, "a", 0);
12235       goto release;
12236     }
12237
12238   /* bit variables done */
12239   /* general case */
12240   size = AOP_SIZE (result);
12241   offset = 0;
12242   if (AOP_TYPE (right) == AOP_LIT)
12243     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12244
12245   if ((size > 1) &&
12246       (AOP_TYPE (result) != AOP_REG) &&
12247       (AOP_TYPE (right) == AOP_LIT) &&
12248       !IS_FLOAT (operandType (right)))
12249     {
12250       _startLazyDPSEvaluation ();
12251       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12252         {
12253           aopPut (result,
12254                   aopGet (right, offset, FALSE, FALSE, NULL),
12255                   offset);
12256           offset++;
12257           size--;
12258         }
12259       /* And now fill the rest with zeros. */
12260       if (size)
12261         {
12262           emitcode ("clr", "a");
12263         }
12264       while (size--)
12265         {
12266           aopPut (result, "a", offset++);
12267         }
12268       _endLazyDPSEvaluation ();
12269     }
12270   else
12271     {
12272       _startLazyDPSEvaluation ();
12273       while (size--)
12274         {
12275           aopPut (result,
12276                   aopGet (right, offset, FALSE, FALSE, NULL),
12277                   offset);
12278           offset++;
12279         }
12280       _endLazyDPSEvaluation ();
12281     }
12282
12283 release:
12284   freeAsmop (result, NULL, ic, TRUE);
12285   freeAsmop (right, NULL, ic, TRUE);
12286 }
12287
12288 /*-----------------------------------------------------------------*/
12289 /* genJumpTab - generates code for jump table                      */
12290 /*-----------------------------------------------------------------*/
12291 static void
12292 genJumpTab (iCode * ic)
12293 {
12294   symbol *jtab;
12295   char *l;
12296
12297   D (emitcode (";", "genJumpTab"));
12298
12299   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12300   /* get the condition into accumulator */
12301   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12302   MOVA (l);
12303   /* multiply by four! */
12304   emitcode ("add", "a,acc");
12305   emitcode ("add", "a,acc");
12306   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12307
12308   jtab = newiTempLabel (NULL);
12309   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12310   emitcode ("jmp", "@a+dptr");
12311   emitLabel (jtab);
12312   /* now generate the jump labels */
12313   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12314        jtab = setNextItem (IC_JTLABELS (ic)))
12315     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12316
12317 }
12318
12319 /*-----------------------------------------------------------------*/
12320 /* genCast - gen code for casting                                  */
12321 /*-----------------------------------------------------------------*/
12322 static void
12323 genCast (iCode * ic)
12324 {
12325   operand *result = IC_RESULT (ic);
12326   sym_link *ctype = operandType (IC_LEFT (ic));
12327   sym_link *rtype = operandType (IC_RIGHT (ic));
12328   operand *right = IC_RIGHT (ic);
12329   int size, offset;
12330
12331   D (emitcode (";", "genCast"));
12332
12333   /* if they are equivalent then do nothing */
12334   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12335     return;
12336
12337   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12338   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12339
12340   /* if the result is a bit (and not a bitfield) */
12341   if (IS_BIT (OP_SYMBOL (result)->type))
12342     {
12343       /* if the right size is a literal then
12344          we know what the value is */
12345       if (AOP_TYPE (right) == AOP_LIT)
12346         {
12347           if (((int) operandLitValue (right)))
12348             aopPut (result, one, 0);
12349           else
12350             aopPut (result, zero, 0);
12351
12352           goto release;
12353         }
12354
12355       /* the right is also a bit variable */
12356       if (AOP_TYPE (right) == AOP_CRY)
12357         {
12358           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12359           aopPut (result, "c", 0);
12360           goto release;
12361         }
12362
12363       /* we need to or */
12364       toBoolean (right);
12365       aopPut (result, "a", 0);
12366       goto release;
12367     }
12368
12369   /* if they are the same size : or less */
12370   if (AOP_SIZE (result) <= AOP_SIZE (right))
12371     {
12372
12373       /* if they are in the same place */
12374       if (sameRegs (AOP (right), AOP (result)))
12375         goto release;
12376
12377       /* if they in different places then copy */
12378       size = AOP_SIZE (result);
12379       offset = 0;
12380       _startLazyDPSEvaluation ();
12381       while (size--)
12382         {
12383           aopPut (result,
12384                   aopGet (right, offset, FALSE, FALSE, NULL),
12385                   offset);
12386           offset++;
12387         }
12388       _endLazyDPSEvaluation ();
12389       goto release;
12390     }
12391
12392   /* if the result is of type pointer */
12393   if (IS_PTR (ctype))
12394     {
12395
12396       int p_type;
12397       sym_link *type = operandType (right);
12398
12399       /* pointer to generic pointer */
12400       if (IS_GENPTR (ctype))
12401         {
12402           if (IS_PTR (type))
12403             {
12404               p_type = DCL_TYPE (type);
12405             }
12406           else
12407             {
12408 #if OLD_CAST_BEHAVIOR
12409               /* KV: we are converting a non-pointer type to
12410                * a generic pointer. This (ifdef'd out) code
12411                * says that the resulting generic pointer
12412                * should have the same class as the storage
12413                * location of the non-pointer variable.
12414                *
12415                * For example, converting an int (which happens
12416                * to be stored in DATA space) to a pointer results
12417                * in a DATA generic pointer; if the original int
12418                * in XDATA space, so will be the resulting pointer.
12419                *
12420                * I don't like that behavior, and thus this change:
12421                * all such conversions will be forced to XDATA and
12422                * throw a warning. If you want some non-XDATA
12423                * type, or you want to suppress the warning, you
12424                * must go through an intermediate cast, like so:
12425                *
12426                * char _generic *gp = (char _xdata *)(intVar);
12427                */
12428               sym_link *etype = getSpec (type);
12429
12430               /* we have to go by the storage class */
12431               if (SPEC_OCLS (etype) != generic)
12432                 {
12433                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12434                 }
12435               else
12436 #endif
12437                 {
12438                   /* Converting unknown class (i.e. register variable)
12439                    * to generic pointer. This is not good, but
12440                    * we'll make a guess (and throw a warning).
12441                    */
12442                   p_type = FPOINTER;
12443                   werror (W_INT_TO_GEN_PTR_CAST);
12444                 }
12445             }
12446
12447           /* the first two bytes are known */
12448           size = GPTRSIZE - 1;
12449           offset = 0;
12450           _startLazyDPSEvaluation ();
12451           while (size--)
12452             {
12453               aopPut (result,
12454                       aopGet (right, offset, FALSE, FALSE, NULL),
12455                       offset);
12456               offset++;
12457             }
12458           _endLazyDPSEvaluation ();
12459
12460           /* the last byte depending on type */
12461             {
12462                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12463                 char gpValStr[10];
12464
12465                 if (gpVal == -1)
12466                 {
12467                     // pointerTypeToGPByte will have bitched.
12468                     exit(1);
12469                 }
12470
12471                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12472                 aopPut (result, gpValStr, GPTRSIZE - 1);
12473             }
12474           goto release;
12475         }
12476
12477       /* just copy the pointers */
12478       size = AOP_SIZE (result);
12479       offset = 0;
12480       _startLazyDPSEvaluation ();
12481       while (size--)
12482         {
12483           aopPut (result,
12484                   aopGet (right, offset, FALSE, FALSE, NULL),
12485                   offset);
12486           offset++;
12487         }
12488       _endLazyDPSEvaluation ();
12489       goto release;
12490     }
12491
12492   /* so we now know that the size of destination is greater
12493      than the size of the source */
12494   /* we move to result for the size of source */
12495   size = AOP_SIZE (right);
12496   offset = 0;
12497   _startLazyDPSEvaluation ();
12498   while (size--)
12499     {
12500       aopPut (result,
12501               aopGet (right, offset, FALSE, FALSE, NULL),
12502               offset);
12503       offset++;
12504     }
12505   _endLazyDPSEvaluation ();
12506
12507   /* now depending on the sign of the source && destination */
12508   size = AOP_SIZE (result) - AOP_SIZE (right);
12509   /* if unsigned or not an integral type */
12510   /* also, if the source is a bit, we don't need to sign extend, because
12511    * it can't possibly have set the sign bit.
12512    */
12513   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12514     {
12515       while (size--)
12516         {
12517           aopPut (result, zero, offset++);
12518         }
12519     }
12520   else
12521     {
12522       /* we need to extend the sign :{ */
12523       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12524                         FALSE, FALSE, NULL));
12525       emitcode ("rlc", "a");
12526       emitcode ("subb", "a,acc");
12527       while (size--)
12528         aopPut (result, "a", offset++);
12529     }
12530
12531   /* we are done hurray !!!! */
12532
12533 release:
12534   freeAsmop (right, NULL, ic, TRUE);
12535   freeAsmop (result, NULL, ic, TRUE);
12536
12537 }
12538
12539 /*-----------------------------------------------------------------*/
12540 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12541 /*-----------------------------------------------------------------*/
12542 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12543 {
12544     operand *from , *to , *count;
12545     symbol *lbl;
12546     bitVect *rsave;
12547     int i;
12548
12549     /* we know it has to be 3 parameters */
12550     assert (nparms == 3);
12551
12552     rsave = newBitVect(16);
12553     /* save DPTR if it needs to be saved */
12554     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12555             if (bitVectBitValue(ic->rMask,i))
12556                     rsave = bitVectSetBit(rsave,i);
12557     }
12558     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12559                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12560     savermask(rsave);
12561
12562     to = parms[0];
12563     from = parms[1];
12564     count = parms[2];
12565
12566     aopOp (from, ic->next, FALSE, FALSE);
12567
12568     /* get from into DPTR1 */
12569     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12570     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12571     if (options.model == MODEL_FLAT24) {
12572         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12573     }
12574
12575     freeAsmop (from, NULL, ic, FALSE);
12576     aopOp (to, ic, FALSE, FALSE);
12577     /* get "to" into DPTR */
12578     /* if the operand is already in dptr
12579        then we do nothing else we move the value to dptr */
12580     if (AOP_TYPE (to) != AOP_STR) {
12581         /* if already in DPTR then we need to push */
12582         if (AOP_TYPE(to) == AOP_DPTR) {
12583             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12584             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12585             if (options.model == MODEL_FLAT24)
12586                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12587             emitcode ("pop", "dph");
12588             emitcode ("pop", "dpl");
12589         } else {
12590             _startLazyDPSEvaluation ();
12591             /* if this is remateriazable */
12592             if (AOP_TYPE (to) == AOP_IMMD) {
12593                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12594             } else {                    /* we need to get it byte by byte */
12595                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12596                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12597                 if (options.model == MODEL_FLAT24) {
12598                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12599                 }
12600             }
12601             _endLazyDPSEvaluation ();
12602         }
12603     }
12604     freeAsmop (to, NULL, ic, FALSE);
12605     _G.dptrInUse = _G.dptr1InUse = 1;
12606     aopOp (count, ic->next->next, FALSE,FALSE);
12607     lbl =newiTempLabel(NULL);
12608
12609     /* now for the actual copy */
12610     if (AOP_TYPE(count) == AOP_LIT &&
12611         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12612         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12613         if (fromc) {
12614             emitcode ("lcall","__bi_memcpyc2x_s");
12615         } else {
12616             emitcode ("lcall","__bi_memcpyx2x_s");
12617         }
12618         freeAsmop (count, NULL, ic, FALSE);
12619     } else {
12620         symbol *lbl1 = newiTempLabel(NULL);
12621
12622         emitcode (";"," Auto increment but no djnz");
12623         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12624         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12625         freeAsmop (count, NULL, ic, FALSE);
12626         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12627         emitcode ("","!tlabeldef",lbl->key+100);
12628         if (fromc) {
12629             emitcode ("clr","a");
12630             emitcode ("movc", "a,@a+dptr");
12631         } else
12632             emitcode ("movx", "a,@dptr");
12633         emitcode ("movx", "@dptr,a");
12634         emitcode ("inc", "dptr");
12635         emitcode ("inc", "dptr");
12636         emitcode ("mov","a,b");
12637         emitcode ("orl","a,_ap");
12638         emitcode ("jz","!tlabel",lbl1->key+100);
12639         emitcode ("mov","a,_ap");
12640         emitcode ("add","a,#!constbyte",0xFF);
12641         emitcode ("mov","_ap,a");
12642         emitcode ("mov","a,b");
12643         emitcode ("addc","a,#!constbyte",0xFF);
12644         emitcode ("mov","b,a");
12645         emitcode ("sjmp","!tlabel",lbl->key+100);
12646         emitcode ("","!tlabeldef",lbl1->key+100);
12647     }
12648     emitcode ("mov", "dps,#0");
12649     _G.dptrInUse = _G.dptr1InUse = 0;
12650     unsavermask(rsave);
12651
12652 }
12653
12654 /*-----------------------------------------------------------------*/
12655 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12656 /*-----------------------------------------------------------------*/
12657 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12658 {
12659     operand *from , *to , *count;
12660     symbol *lbl,*lbl2;
12661     bitVect *rsave;
12662     int i;
12663
12664     /* we know it has to be 3 parameters */
12665     assert (nparms == 3);
12666
12667     rsave = newBitVect(16);
12668     /* save DPTR if it needs to be saved */
12669     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12670             if (bitVectBitValue(ic->rMask,i))
12671                     rsave = bitVectSetBit(rsave,i);
12672     }
12673     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12674                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12675     savermask(rsave);
12676
12677     to = parms[0];
12678     from = parms[1];
12679     count = parms[2];
12680
12681     aopOp (from, ic->next, FALSE, FALSE);
12682
12683     /* get from into DPTR1 */
12684     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12685     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12686     if (options.model == MODEL_FLAT24) {
12687         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12688     }
12689
12690     freeAsmop (from, NULL, ic, FALSE);
12691     aopOp (to, ic, FALSE, FALSE);
12692     /* get "to" into DPTR */
12693     /* if the operand is already in dptr
12694        then we do nothing else we move the value to dptr */
12695     if (AOP_TYPE (to) != AOP_STR) {
12696         /* if already in DPTR then we need to push */
12697         if (AOP_TYPE(to) == AOP_DPTR) {
12698             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12699             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12700             if (options.model == MODEL_FLAT24)
12701                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12702             emitcode ("pop", "dph");
12703             emitcode ("pop", "dpl");
12704         } else {
12705             _startLazyDPSEvaluation ();
12706             /* if this is remateriazable */
12707             if (AOP_TYPE (to) == AOP_IMMD) {
12708                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12709             } else {                    /* we need to get it byte by byte */
12710                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12711                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12712                 if (options.model == MODEL_FLAT24) {
12713                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12714                 }
12715             }
12716             _endLazyDPSEvaluation ();
12717         }
12718     }
12719     freeAsmop (to, NULL, ic, FALSE);
12720     _G.dptrInUse = _G.dptr1InUse = 1;
12721     aopOp (count, ic->next->next, FALSE,FALSE);
12722     lbl =newiTempLabel(NULL);
12723     lbl2 =newiTempLabel(NULL);
12724
12725     /* now for the actual compare */
12726     if (AOP_TYPE(count) == AOP_LIT &&
12727         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12728         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12729         if (fromc)
12730             emitcode("lcall","__bi_memcmpc2x_s");
12731         else
12732             emitcode("lcall","__bi_memcmpx2x_s");
12733         freeAsmop (count, NULL, ic, FALSE);
12734         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12735         aopPut(IC_RESULT(ic),"a",0);
12736         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12737     } else {
12738         symbol *lbl1 = newiTempLabel(NULL);
12739
12740         emitcode("push","ar0");
12741         emitcode (";"," Auto increment but no djnz");
12742         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12743         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12744         freeAsmop (count, NULL, ic, FALSE);
12745         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12746         emitcode ("","!tlabeldef",lbl->key+100);
12747         if (fromc) {
12748             emitcode ("clr","a");
12749             emitcode ("movc", "a,@a+dptr");
12750         } else
12751             emitcode ("movx", "a,@dptr");
12752         emitcode ("mov","r0,a");
12753         emitcode ("movx", "a,@dptr");
12754         emitcode ("clr","c");
12755         emitcode ("subb","a,r0");
12756         emitcode ("jnz","!tlabel",lbl2->key+100);
12757         emitcode ("inc", "dptr");
12758         emitcode ("inc", "dptr");
12759         emitcode ("mov","a,b");
12760         emitcode ("orl","a,_ap");
12761         emitcode ("jz","!tlabel",lbl1->key+100);
12762         emitcode ("mov","a,_ap");
12763         emitcode ("add","a,#!constbyte",0xFF);
12764         emitcode ("mov","_ap,a");
12765         emitcode ("mov","a,b");
12766         emitcode ("addc","a,#!constbyte",0xFF);
12767         emitcode ("mov","b,a");
12768         emitcode ("sjmp","!tlabel",lbl->key+100);
12769         emitcode ("","!tlabeldef",lbl1->key+100);
12770         emitcode ("clr","a");
12771         emitcode ("","!tlabeldef",lbl2->key+100);
12772         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12773         aopPut(IC_RESULT(ic),"a",0);
12774         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12775         emitcode("pop","ar0");
12776         emitcode ("mov", "dps,#0");
12777     }
12778     _G.dptrInUse = _G.dptr1InUse = 0;
12779     unsavermask(rsave);
12780
12781 }
12782
12783 /*-----------------------------------------------------------------*/
12784 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12785 /* port, first parameter output area second parameter pointer to   */
12786 /* port third parameter count                                      */
12787 /*-----------------------------------------------------------------*/
12788 static void genInp( iCode *ic, int nparms, operand **parms)
12789 {
12790     operand *from , *to , *count;
12791     symbol *lbl;
12792     bitVect *rsave;
12793     int i;
12794
12795     /* we know it has to be 3 parameters */
12796     assert (nparms == 3);
12797
12798     rsave = newBitVect(16);
12799     /* save DPTR if it needs to be saved */
12800     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12801             if (bitVectBitValue(ic->rMask,i))
12802                     rsave = bitVectSetBit(rsave,i);
12803     }
12804     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12805                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12806     savermask(rsave);
12807
12808     to = parms[0];
12809     from = parms[1];
12810     count = parms[2];
12811
12812     aopOp (from, ic->next, FALSE, FALSE);
12813
12814     /* get from into DPTR1 */
12815     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12816     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12817     if (options.model == MODEL_FLAT24) {
12818         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12819     }
12820
12821     freeAsmop (from, NULL, ic, FALSE);
12822     aopOp (to, ic, FALSE, FALSE);
12823     /* get "to" into DPTR */
12824     /* if the operand is already in dptr
12825        then we do nothing else we move the value to dptr */
12826     if (AOP_TYPE (to) != AOP_STR) {
12827         /* if already in DPTR then we need to push */
12828         if (AOP_TYPE(to) == AOP_DPTR) {
12829             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12830             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12831             if (options.model == MODEL_FLAT24)
12832                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12833             emitcode ("pop", "dph");
12834             emitcode ("pop", "dpl");
12835         } else {
12836             _startLazyDPSEvaluation ();
12837             /* if this is remateriazable */
12838             if (AOP_TYPE (to) == AOP_IMMD) {
12839                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12840             } else {                    /* we need to get it byte by byte */
12841                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12842                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12843                 if (options.model == MODEL_FLAT24) {
12844                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12845                 }
12846             }
12847             _endLazyDPSEvaluation ();
12848         }
12849     }
12850     freeAsmop (to, NULL, ic, FALSE);
12851
12852     _G.dptrInUse = _G.dptr1InUse = 1;
12853     aopOp (count, ic->next->next, FALSE,FALSE);
12854     lbl =newiTempLabel(NULL);
12855
12856     /* now for the actual copy */
12857     if (AOP_TYPE(count) == AOP_LIT &&
12858         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12859         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12860         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12861         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12862         freeAsmop (count, NULL, ic, FALSE);
12863         emitcode ("","!tlabeldef",lbl->key+100);
12864         emitcode ("movx", "a,@dptr");   /* read data from port */
12865         emitcode ("dec","dps");         /* switch to DPTR */
12866         emitcode ("movx", "@dptr,a");   /* save into location */
12867         emitcode ("inc", "dptr");       /* point to next area */
12868         emitcode ("inc","dps");         /* switch to DPTR2 */
12869         emitcode ("djnz","b,!tlabel",lbl->key+100);
12870     } else {
12871         symbol *lbl1 = newiTempLabel(NULL);
12872
12873         emitcode (";"," Auto increment but no djnz");
12874         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12875         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12876         freeAsmop (count, NULL, ic, FALSE);
12877         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12878         emitcode ("","!tlabeldef",lbl->key+100);
12879         emitcode ("movx", "a,@dptr");
12880         emitcode ("dec","dps");         /* switch to DPTR */
12881         emitcode ("movx", "@dptr,a");
12882         emitcode ("inc", "dptr");
12883         emitcode ("inc","dps");         /* switch to DPTR2 */
12884 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12885 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12886         emitcode ("mov","a,b");
12887         emitcode ("orl","a,_ap");
12888         emitcode ("jz","!tlabel",lbl1->key+100);
12889         emitcode ("mov","a,_ap");
12890         emitcode ("add","a,#!constbyte",0xFF);
12891         emitcode ("mov","_ap,a");
12892         emitcode ("mov","a,b");
12893         emitcode ("addc","a,#!constbyte",0xFF);
12894         emitcode ("mov","b,a");
12895         emitcode ("sjmp","!tlabel",lbl->key+100);
12896         emitcode ("","!tlabeldef",lbl1->key+100);
12897     }
12898     emitcode ("mov", "dps,#0");
12899     _G.dptrInUse = _G.dptr1InUse = 0;
12900     unsavermask(rsave);
12901
12902 }
12903
12904 /*-----------------------------------------------------------------*/
12905 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12906 /* port, first parameter output area second parameter pointer to   */
12907 /* port third parameter count                                      */
12908 /*-----------------------------------------------------------------*/
12909 static void genOutp( iCode *ic, int nparms, operand **parms)
12910 {
12911     operand *from , *to , *count;
12912     symbol *lbl;
12913     bitVect *rsave;
12914     int i;
12915
12916     /* we know it has to be 3 parameters */
12917     assert (nparms == 3);
12918
12919     rsave = newBitVect(16);
12920     /* save DPTR if it needs to be saved */
12921     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12922             if (bitVectBitValue(ic->rMask,i))
12923                     rsave = bitVectSetBit(rsave,i);
12924     }
12925     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12926                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12927     savermask(rsave);
12928
12929     to = parms[0];
12930     from = parms[1];
12931     count = parms[2];
12932
12933     aopOp (from, ic->next, FALSE, FALSE);
12934
12935     /* get from into DPTR1 */
12936     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12937     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12938     if (options.model == MODEL_FLAT24) {
12939         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12940     }
12941
12942     freeAsmop (from, NULL, ic, FALSE);
12943     aopOp (to, ic, FALSE, FALSE);
12944     /* get "to" into DPTR */
12945     /* if the operand is already in dptr
12946        then we do nothing else we move the value to dptr */
12947     if (AOP_TYPE (to) != AOP_STR) {
12948         /* if already in DPTR then we need to push */
12949         if (AOP_TYPE(to) == AOP_DPTR) {
12950             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12951             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12952             if (options.model == MODEL_FLAT24)
12953                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12954             emitcode ("pop", "dph");
12955             emitcode ("pop", "dpl");
12956         } else {
12957             _startLazyDPSEvaluation ();
12958             /* if this is remateriazable */
12959             if (AOP_TYPE (to) == AOP_IMMD) {
12960                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12961             } else {                    /* we need to get it byte by byte */
12962                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12963                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12964                 if (options.model == MODEL_FLAT24) {
12965                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12966                 }
12967             }
12968             _endLazyDPSEvaluation ();
12969         }
12970     }
12971     freeAsmop (to, NULL, ic, FALSE);
12972
12973     _G.dptrInUse = _G.dptr1InUse = 1;
12974     aopOp (count, ic->next->next, FALSE,FALSE);
12975     lbl =newiTempLabel(NULL);
12976
12977     /* now for the actual copy */
12978     if (AOP_TYPE(count) == AOP_LIT &&
12979         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12980         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12981         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12982         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12983         emitcode ("","!tlabeldef",lbl->key+100);
12984         emitcode ("movx", "a,@dptr");   /* read data from port */
12985         emitcode ("inc","dps");         /* switch to DPTR2 */
12986         emitcode ("movx", "@dptr,a");   /* save into location */
12987         emitcode ("inc", "dptr");       /* point to next area */
12988         emitcode ("dec","dps");         /* switch to DPTR */
12989         emitcode ("djnz","b,!tlabel",lbl->key+100);
12990         freeAsmop (count, NULL, ic, FALSE);
12991     } else {
12992         symbol *lbl1 = newiTempLabel(NULL);
12993
12994         emitcode (";"," Auto increment but no djnz");
12995         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12996         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12997         freeAsmop (count, NULL, ic, FALSE);
12998         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12999         emitcode ("","!tlabeldef",lbl->key+100);
13000         emitcode ("movx", "a,@dptr");
13001         emitcode ("inc", "dptr");
13002         emitcode ("inc","dps");         /* switch to DPTR2 */
13003         emitcode ("movx", "@dptr,a");
13004         emitcode ("dec","dps");         /* switch to DPTR */
13005         emitcode ("mov","a,b");
13006         emitcode ("orl","a,_ap");
13007         emitcode ("jz","!tlabel",lbl1->key+100);
13008         emitcode ("mov","a,_ap");
13009         emitcode ("add","a,#!constbyte",0xFF);
13010         emitcode ("mov","_ap,a");
13011         emitcode ("mov","a,b");
13012         emitcode ("addc","a,#!constbyte",0xFF);
13013         emitcode ("mov","b,a");
13014         emitcode ("sjmp","!tlabel",lbl->key+100);
13015         emitcode ("","!tlabeldef",lbl1->key+100);
13016     }
13017     emitcode ("mov", "dps,#0");
13018     _G.dptrInUse = _G.dptr1InUse = 0;
13019     unsavermask(rsave);
13020
13021 }
13022
13023 /*-----------------------------------------------------------------*/
13024 /* genSwapW - swap lower & high order bytes                        */
13025 /*-----------------------------------------------------------------*/
13026 static void genSwapW(iCode *ic, int nparms, operand **parms)
13027 {
13028     operand *dest;
13029     operand *src;
13030     assert (nparms==1);
13031
13032     src = parms[0];
13033     dest=IC_RESULT(ic);
13034
13035     assert(getSize(operandType(src))==2);
13036
13037     aopOp (src, ic, FALSE, FALSE);
13038     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13039     _G.accInUse++;
13040     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13041     _G.accInUse--;
13042     freeAsmop (src, NULL, ic, FALSE);
13043
13044     aopOp (dest,ic, FALSE, FALSE);
13045     aopPut(dest,"b",0);
13046     aopPut(dest,"a",1);
13047     freeAsmop (dest, NULL, ic, FALSE);
13048 }
13049
13050 /*-----------------------------------------------------------------*/
13051 /* genMemsetX - gencode for memSetX data                           */
13052 /*-----------------------------------------------------------------*/
13053 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13054 {
13055     operand *to , *val , *count;
13056     symbol *lbl;
13057     char *l;
13058     int i;
13059     bitVect *rsave;
13060
13061     /* we know it has to be 3 parameters */
13062     assert (nparms == 3);
13063
13064     to = parms[0];
13065     val = parms[1];
13066     count = parms[2];
13067
13068     /* save DPTR if it needs to be saved */
13069     rsave = newBitVect(16);
13070     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13071             if (bitVectBitValue(ic->rMask,i))
13072                     rsave = bitVectSetBit(rsave,i);
13073     }
13074     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13075                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13076     savermask(rsave);
13077
13078     aopOp (to, ic, FALSE, FALSE);
13079     /* get "to" into DPTR */
13080     /* if the operand is already in dptr
13081        then we do nothing else we move the value to dptr */
13082     if (AOP_TYPE (to) != AOP_STR) {
13083         /* if already in DPTR then we need to push */
13084         if (AOP_TYPE(to) == AOP_DPTR) {
13085             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13086             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13087             if (options.model == MODEL_FLAT24)
13088                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13089             emitcode ("pop", "dph");
13090             emitcode ("pop", "dpl");
13091         } else {
13092             _startLazyDPSEvaluation ();
13093             /* if this is remateriazable */
13094             if (AOP_TYPE (to) == AOP_IMMD) {
13095                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13096             } else {                    /* we need to get it byte by byte */
13097                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13098                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13099                 if (options.model == MODEL_FLAT24) {
13100                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13101                 }
13102             }
13103             _endLazyDPSEvaluation ();
13104         }
13105     }
13106     freeAsmop (to, NULL, ic, FALSE);
13107
13108     aopOp (val, ic->next->next, FALSE,FALSE);
13109     aopOp (count, ic->next->next, FALSE,FALSE);
13110     lbl =newiTempLabel(NULL);
13111     /* now for the actual copy */
13112     if (AOP_TYPE(count) == AOP_LIT &&
13113         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13114         l = aopGet(val, 0, FALSE, FALSE, NULL);
13115         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13116         MOVA(l);
13117         emitcode ("","!tlabeldef",lbl->key+100);
13118         emitcode ("movx", "@dptr,a");
13119         emitcode ("inc", "dptr");
13120         emitcode ("djnz","b,!tlabel",lbl->key+100);
13121     } else {
13122         symbol *lbl1 = newiTempLabel(NULL);
13123
13124         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13125         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13126         emitcode ("","!tlabeldef",lbl->key+100);
13127         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13128         emitcode ("movx", "@dptr,a");
13129         emitcode ("inc", "dptr");
13130         emitcode ("mov","a,b");
13131         emitcode ("orl","a,_ap");
13132         emitcode ("jz","!tlabel",lbl1->key+100);
13133         emitcode ("mov","a,_ap");
13134         emitcode ("add","a,#!constbyte",0xFF);
13135         emitcode ("mov","_ap,a");
13136         emitcode ("mov","a,b");
13137         emitcode ("addc","a,#!constbyte",0xFF);
13138         emitcode ("mov","b,a");
13139         emitcode ("sjmp","!tlabel",lbl->key+100);
13140         emitcode ("","!tlabeldef",lbl1->key+100);
13141     }
13142     freeAsmop (count, NULL, ic, FALSE);
13143     unsavermask(rsave);
13144 }
13145
13146 /*-----------------------------------------------------------------*/
13147 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13148 /*-----------------------------------------------------------------*/
13149 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13150 {
13151         bitVect *rsave ;
13152         operand *pnum, *result;
13153         int i;
13154
13155         assert (nparms==1);
13156         /* save registers that need to be saved */
13157         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13158                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13159
13160         pnum = parms[0];
13161         aopOp (pnum, ic, FALSE, FALSE);
13162         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13163         freeAsmop (pnum, NULL, ic, FALSE);
13164         emitcode ("lcall","NatLib_LoadPrimitive");
13165         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13166         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13167             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13168                 for (i = (size-1) ; i >= 0 ; i-- ) {
13169                         emitcode ("push","a%s",javaRet[i]);
13170                 }
13171                 for (i=0; i < size ; i++ ) {
13172                         emitcode ("pop","a%s",
13173                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13174                 }
13175         } else {
13176                 for (i = 0 ; i < size ; i++ ) {
13177                         aopPut(result,javaRet[i],i);
13178                 }
13179         }
13180         freeAsmop (result, NULL, ic, FALSE);
13181         unsavermask(rsave);
13182 }
13183
13184 /*-----------------------------------------------------------------*/
13185 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13186 /*-----------------------------------------------------------------*/
13187 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13188 {
13189         bitVect *rsave ;
13190         operand *pnum, *result;
13191         int size = 3;
13192         int i;
13193
13194         assert (nparms==1);
13195         /* save registers that need to be saved */
13196         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13197                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13198
13199         pnum = parms[0];
13200         aopOp (pnum, ic, FALSE, FALSE);
13201         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13202         freeAsmop (pnum, NULL, ic, FALSE);
13203         emitcode ("lcall","NatLib_LoadPointer");
13204         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13205         if (AOP_TYPE(result)!=AOP_STR) {
13206                 for (i = 0 ; i < size ; i++ ) {
13207                         aopPut(result,fReturn[i],i);
13208                 }
13209         }
13210         freeAsmop (result, NULL, ic, FALSE);
13211         unsavermask(rsave);
13212 }
13213
13214 /*-----------------------------------------------------------------*/
13215 /* genNatLibInstallStateBlock -                                    */
13216 /*-----------------------------------------------------------------*/
13217 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13218                                        operand **parms, const char *name)
13219 {
13220         bitVect *rsave ;
13221         operand *psb, *handle;
13222         assert (nparms==2);
13223
13224         /* save registers that need to be saved */
13225         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13226                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13227         psb = parms[0];
13228         handle = parms[1];
13229
13230         /* put pointer to state block into DPTR1 */
13231         aopOp (psb, ic, FALSE, FALSE);
13232         if (AOP_TYPE (psb) == AOP_IMMD) {
13233                 emitcode ("mov","dps,#1");
13234                 emitcode ("mov", "dptr,%s",
13235                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13236                 emitcode ("mov","dps,#0");
13237         } else {
13238                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13239                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13240                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13241         }
13242         freeAsmop (psb, NULL, ic, FALSE);
13243
13244         /* put libraryID into DPTR */
13245         emitcode ("mov","dptr,#LibraryID");
13246
13247         /* put handle into r3:r2 */
13248         aopOp (handle, ic, FALSE, FALSE);
13249         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13250                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13251                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13252                 emitcode ("pop","ar3");
13253                 emitcode ("pop","ar2");
13254         } else {
13255                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13256                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13257         }
13258         freeAsmop (psb, NULL, ic, FALSE);
13259
13260         /* make the call */
13261         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13262
13263         /* put return value into place*/
13264         _G.accInUse++;
13265         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13266         _G.accInUse--;
13267         aopPut(IC_RESULT(ic),"a",0);
13268         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13269         unsavermask(rsave);
13270 }
13271
13272 /*-----------------------------------------------------------------*/
13273 /* genNatLibRemoveStateBlock -                                     */
13274 /*-----------------------------------------------------------------*/
13275 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13276 {
13277         bitVect *rsave ;
13278
13279         assert(nparms==0);
13280
13281         /* save registers that need to be saved */
13282         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13283                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13284
13285         /* put libraryID into DPTR */
13286         emitcode ("mov","dptr,#LibraryID");
13287         /* make the call */
13288         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13289         unsavermask(rsave);
13290 }
13291
13292 /*-----------------------------------------------------------------*/
13293 /* genNatLibGetStateBlock -                                        */
13294 /*-----------------------------------------------------------------*/
13295 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13296                                    operand **parms,const char *name)
13297 {
13298         bitVect *rsave ;
13299         symbol *lbl = newiTempLabel(NULL);
13300
13301         assert(nparms==0);
13302         /* save registers that need to be saved */
13303         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13304                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13305
13306         /* put libraryID into DPTR */
13307         emitcode ("mov","dptr,#LibraryID");
13308         /* make the call */
13309         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13310         emitcode ("jnz","!tlabel",lbl->key+100);
13311
13312         /* put return value into place */
13313         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13314         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13315                 emitcode ("push","ar3");
13316                 emitcode ("push","ar2");
13317                 emitcode ("pop","%s",
13318                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13319                 emitcode ("pop","%s",
13320                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13321         } else {
13322                 aopPut(IC_RESULT(ic),"r2",0);
13323                 aopPut(IC_RESULT(ic),"r3",1);
13324         }
13325         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13326         emitcode ("","!tlabeldef",lbl->key+100);
13327         unsavermask(rsave);
13328 }
13329
13330 /*-----------------------------------------------------------------*/
13331 /* genMMMalloc -                                                   */
13332 /*-----------------------------------------------------------------*/
13333 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13334                          int size, const char *name)
13335 {
13336         bitVect *rsave ;
13337         operand *bsize;
13338         symbol *rsym;
13339         symbol *lbl = newiTempLabel(NULL);
13340
13341         assert (nparms == 1);
13342         /* save registers that need to be saved */
13343         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13344                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13345
13346         bsize=parms[0];
13347         aopOp (bsize,ic,FALSE,FALSE);
13348
13349         /* put the size in R4-R2 */
13350         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13351                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13352                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13353                 if (size==3) {
13354                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13355                         emitcode("pop","ar4");
13356                 }
13357                 emitcode("pop","ar3");
13358                 emitcode("pop","ar2");
13359         } else {
13360                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13361                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13362                 if (size==3) {
13363                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13364                 }
13365         }
13366         freeAsmop (bsize, NULL, ic, FALSE);
13367
13368         /* make the call */
13369         emitcode ("lcall","MM_%s",name);
13370         emitcode ("jz","!tlabel",lbl->key+100);
13371         emitcode ("mov","r2,#!constbyte",0xff);
13372         emitcode ("mov","r3,#!constbyte",0xff);
13373         emitcode ("","!tlabeldef",lbl->key+100);
13374         /* we don't care about the pointer : we just save the handle */
13375         rsym = OP_SYMBOL(IC_RESULT(ic));
13376         if (rsym->liveFrom != rsym->liveTo) {
13377                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13378                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13379                         emitcode ("push","ar3");
13380                         emitcode ("push","ar2");
13381                         emitcode ("pop","%s",
13382                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13383                         emitcode ("pop","%s",
13384                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13385                 } else {
13386                         aopPut(IC_RESULT(ic),"r2",0);
13387                         aopPut(IC_RESULT(ic),"r3",1);
13388                 }
13389                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13390         }
13391         unsavermask(rsave);
13392 }
13393
13394 /*-----------------------------------------------------------------*/
13395 /* genMMDeref -                                                    */
13396 /*-----------------------------------------------------------------*/
13397 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13398 {
13399         bitVect *rsave ;
13400         operand *handle;
13401
13402         assert (nparms == 1);
13403         /* save registers that need to be saved */
13404         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13405                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13406
13407         handle=parms[0];
13408         aopOp (handle,ic,FALSE,FALSE);
13409
13410         /* put the size in R4-R2 */
13411         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13412                 emitcode("push","%s",
13413                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13414                 emitcode("push","%s",
13415                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13416                 emitcode("pop","ar3");
13417                 emitcode("pop","ar2");
13418         } else {
13419                 emitcode ("mov","r2,%s",
13420                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13421                 emitcode ("mov","r3,%s",
13422                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13423         }
13424         freeAsmop (handle, NULL, ic, FALSE);
13425
13426         /* make the call */
13427         emitcode ("lcall","MM_Deref");
13428
13429         {
13430                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13431                 if (rsym->liveFrom != rsym->liveTo) {
13432                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13433                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13434                             _startLazyDPSEvaluation ();
13435
13436                             aopPut(IC_RESULT(ic),"dpl",0);
13437                             aopPut(IC_RESULT(ic),"dph",1);
13438                             aopPut(IC_RESULT(ic),"dpx",2);
13439
13440                             _endLazyDPSEvaluation ();
13441
13442                         }
13443                 }
13444         }
13445         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13446         unsavermask(rsave);
13447 }
13448
13449 /*-----------------------------------------------------------------*/
13450 /* genMMUnrestrictedPersist -                                      */
13451 /*-----------------------------------------------------------------*/
13452 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13453 {
13454         bitVect *rsave ;
13455         operand *handle;
13456
13457         assert (nparms == 1);
13458         /* save registers that need to be saved */
13459         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13460                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13461
13462         handle=parms[0];
13463         aopOp (handle,ic,FALSE,FALSE);
13464
13465         /* put the size in R3-R2 */
13466         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13467                 emitcode("push","%s",
13468                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13469                 emitcode("push","%s",
13470                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13471                 emitcode("pop","ar3");
13472                 emitcode("pop","ar2");
13473         } else {
13474                 emitcode ("mov","r2,%s",
13475                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13476                 emitcode ("mov","r3,%s",
13477                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13478         }
13479         freeAsmop (handle, NULL, ic, FALSE);
13480
13481         /* make the call */
13482         emitcode ("lcall","MM_UnrestrictedPersist");
13483
13484         {
13485                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13486                 if (rsym->liveFrom != rsym->liveTo) {
13487                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13488                         aopPut(IC_RESULT(ic),"a",0);
13489                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13490                 }
13491         }
13492         unsavermask(rsave);
13493 }
13494
13495 /*-----------------------------------------------------------------*/
13496 /* genSystemExecJavaProcess -                                      */
13497 /*-----------------------------------------------------------------*/
13498 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13499 {
13500         bitVect *rsave ;
13501         operand *handle, *pp;
13502
13503         assert (nparms==2);
13504         /* save registers that need to be saved */
13505         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13506                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13507
13508         pp = parms[0];
13509         handle = parms[1];
13510
13511         /* put the handle in R3-R2 */
13512         aopOp (handle,ic,FALSE,FALSE);
13513         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13514                 emitcode("push","%s",
13515                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13516                 emitcode("push","%s",
13517                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13518                 emitcode("pop","ar3");
13519                 emitcode("pop","ar2");
13520         } else {
13521                 emitcode ("mov","r2,%s",
13522                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13523                 emitcode ("mov","r3,%s",
13524                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13525         }
13526         freeAsmop (handle, NULL, ic, FALSE);
13527
13528         /* put pointer in DPTR */
13529         aopOp (pp,ic,FALSE,FALSE);
13530         if (AOP_TYPE(pp) == AOP_IMMD) {
13531                 emitcode ("mov", "dptr,%s",
13532                           aopGet (pp, 0, TRUE, FALSE, NULL));
13533         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13534                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13535                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13536                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13537         }
13538         freeAsmop (handle, NULL, ic, FALSE);
13539
13540         /* make the call */
13541         emitcode ("lcall","System_ExecJavaProcess");
13542
13543         /* put result in place */
13544         {
13545                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13546                 if (rsym->liveFrom != rsym->liveTo) {
13547                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13548                         aopPut(IC_RESULT(ic),"a",0);
13549                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13550                 }
13551         }
13552
13553         unsavermask(rsave);
13554 }
13555
13556 /*-----------------------------------------------------------------*/
13557 /* genSystemRTCRegisters -                                         */
13558 /*-----------------------------------------------------------------*/
13559 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13560                                   char *name)
13561 {
13562         bitVect *rsave ;
13563         operand *pp;
13564
13565         assert (nparms==1);
13566         /* save registers that need to be saved */
13567         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13568                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13569
13570         pp=parms[0];
13571         /* put pointer in DPTR */
13572         aopOp (pp,ic,FALSE,FALSE);
13573         if (AOP_TYPE (pp) == AOP_IMMD) {
13574                 emitcode ("mov","dps,#1");
13575                 emitcode ("mov", "dptr,%s",
13576                           aopGet (pp, 0, TRUE, FALSE, NULL));
13577                 emitcode ("mov","dps,#0");
13578         } else {
13579                 emitcode ("mov","dpl1,%s",
13580                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13581                 emitcode ("mov","dph1,%s",
13582                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13583                 emitcode ("mov","dpx1,%s",
13584                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13585         }
13586         freeAsmop (pp, NULL, ic, FALSE);
13587
13588         /* make the call */
13589         emitcode ("lcall","System_%sRTCRegisters",name);
13590
13591         unsavermask(rsave);
13592 }
13593
13594 /*-----------------------------------------------------------------*/
13595 /* genSystemThreadSleep -                                          */
13596 /*-----------------------------------------------------------------*/
13597 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13598 {
13599         bitVect *rsave ;
13600         operand *to, *s;
13601
13602         assert (nparms==1);
13603         /* save registers that need to be saved */
13604         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13605                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13606
13607         to = parms[0];
13608         aopOp(to,ic,FALSE,FALSE);
13609         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13610             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13611                 emitcode ("push","%s",
13612                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13613                 emitcode ("push","%s",
13614                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13615                 emitcode ("push","%s",
13616                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13617                 emitcode ("push","%s",
13618                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13619                 emitcode ("pop","ar3");
13620                 emitcode ("pop","ar2");
13621                 emitcode ("pop","ar1");
13622                 emitcode ("pop","ar0");
13623         } else {
13624                 emitcode ("mov","r0,%s",
13625                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13626                 emitcode ("mov","r1,%s",
13627                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13628                 emitcode ("mov","r2,%s",
13629                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13630                 emitcode ("mov","r3,%s",
13631                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13632         }
13633         freeAsmop (to, NULL, ic, FALSE);
13634
13635         /* suspend in acc */
13636         s = parms[1];
13637         aopOp(s,ic,FALSE,FALSE);
13638         emitcode ("mov","a,%s",
13639                   aopGet(s,0,FALSE,TRUE,NULL));
13640         freeAsmop (s, NULL, ic, FALSE);
13641
13642         /* make the call */
13643         emitcode ("lcall","System_%s",name);
13644
13645         unsavermask(rsave);
13646 }
13647
13648 /*-----------------------------------------------------------------*/
13649 /* genSystemThreadResume -                                         */
13650 /*-----------------------------------------------------------------*/
13651 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13652 {
13653         bitVect *rsave ;
13654         operand *tid,*pid;
13655
13656         assert (nparms==2);
13657         /* save registers that need to be saved */
13658         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13659                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13660
13661         tid = parms[0];
13662         pid = parms[1];
13663
13664         /* PID in R0 */
13665         aopOp(pid,ic,FALSE,FALSE);
13666         emitcode ("mov","r0,%s",
13667                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13668         freeAsmop (pid, NULL, ic, FALSE);
13669
13670         /* tid into ACC */
13671         aopOp(tid,ic,FALSE,FALSE);
13672         emitcode ("mov","a,%s",
13673                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13674         freeAsmop (tid, NULL, ic, FALSE);
13675
13676         emitcode ("lcall","System_ThreadResume");
13677
13678         /* put result into place */
13679         {
13680                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13681                 if (rsym->liveFrom != rsym->liveTo) {
13682                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13683                         aopPut(IC_RESULT(ic),"a",0);
13684                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13685                 }
13686         }
13687         unsavermask(rsave);
13688 }
13689
13690 /*-----------------------------------------------------------------*/
13691 /* genSystemProcessResume -                                        */
13692 /*-----------------------------------------------------------------*/
13693 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13694 {
13695         bitVect *rsave ;
13696         operand *pid;
13697
13698         assert (nparms==1);
13699         /* save registers that need to be saved */
13700         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13701                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13702
13703         pid = parms[0];
13704
13705         /* pid into ACC */
13706         aopOp(pid,ic,FALSE,FALSE);
13707         emitcode ("mov","a,%s",
13708                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13709         freeAsmop (pid, NULL, ic, FALSE);
13710
13711         emitcode ("lcall","System_ProcessResume");
13712
13713         unsavermask(rsave);
13714 }
13715
13716 /*-----------------------------------------------------------------*/
13717 /* genSystem -                                                     */
13718 /*-----------------------------------------------------------------*/
13719 static void genSystem (iCode *ic,int nparms,char *name)
13720 {
13721         assert(nparms == 0);
13722
13723         emitcode ("lcall","System_%s",name);
13724 }
13725
13726 /*-----------------------------------------------------------------*/
13727 /* genSystemPoll -                                                  */
13728 /*-----------------------------------------------------------------*/
13729 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13730 {
13731         bitVect *rsave ;
13732         operand *fp;
13733
13734         assert (nparms==1);
13735         /* save registers that need to be saved */
13736         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13737                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13738
13739         fp = parms[0];
13740         aopOp (fp,ic,FALSE,FALSE);
13741         if (AOP_TYPE (fp) == AOP_IMMD) {
13742                 emitcode ("mov", "dptr,%s",
13743                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13744         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13745                 emitcode ("mov","dpl,%s",
13746                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13747                 emitcode ("mov","dph,%s",
13748                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13749                 emitcode ("mov","dpx,%s",
13750                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13751         }
13752         freeAsmop (fp, NULL, ic, FALSE);
13753
13754         emitcode ("lcall","System_%sPoll",name);
13755
13756         /* put result into place */
13757         {
13758                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13759                 if (rsym->liveFrom != rsym->liveTo) {
13760                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13761                         aopPut(IC_RESULT(ic),"a",0);
13762                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13763                 }
13764         }
13765         unsavermask(rsave);
13766 }
13767
13768 /*-----------------------------------------------------------------*/
13769 /* genSystemGetCurrentID -                                         */
13770 /*-----------------------------------------------------------------*/
13771 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13772 {
13773         assert (nparms==0);
13774
13775         emitcode ("lcall","System_GetCurrent%sId",name);
13776         /* put result into place */
13777         {
13778                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13779                 if (rsym->liveFrom != rsym->liveTo) {
13780                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13781                         aopPut(IC_RESULT(ic),"a",0);
13782                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13783                 }
13784         }
13785 }
13786
13787 /*-----------------------------------------------------------------*/
13788 /* genDjnz - generate decrement & jump if not zero instrucion      */
13789 /*-----------------------------------------------------------------*/
13790 static int
13791 genDjnz (iCode * ic, iCode * ifx)
13792 {
13793   symbol *lbl, *lbl1;
13794   if (!ifx)
13795     return 0;
13796
13797   /* if the if condition has a false label
13798      then we cannot save */
13799   if (IC_FALSE (ifx))
13800     return 0;
13801
13802   /* if the minus is not of the form a = a - 1 */
13803   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13804       !IS_OP_LITERAL (IC_RIGHT (ic)))
13805     return 0;
13806
13807   if (operandLitValue (IC_RIGHT (ic)) != 1)
13808     return 0;
13809
13810   /* if the size of this greater than one then no
13811      saving */
13812   if (getSize (operandType (IC_RESULT (ic))) > 1)
13813     return 0;
13814
13815   /* otherwise we can save BIG */
13816
13817   D (emitcode (";", "genDjnz"));
13818
13819   lbl = newiTempLabel (NULL);
13820   lbl1 = newiTempLabel (NULL);
13821
13822   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13823
13824   if (AOP_NEEDSACC(IC_RESULT(ic)))
13825   {
13826       /* If the result is accessed indirectly via
13827        * the accumulator, we must explicitly write
13828        * it back after the decrement.
13829        */
13830       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13831
13832       if (strcmp(rByte, "a"))
13833       {
13834            /* Something is hopelessly wrong */
13835            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13836                    __FILE__, __LINE__);
13837            /* We can just give up; the generated code will be inefficient,
13838             * but what the hey.
13839             */
13840            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13841            return 0;
13842       }
13843       emitcode ("dec", "%s", rByte);
13844       aopPut (IC_RESULT (ic), rByte, 0);
13845       emitcode ("jnz", "!tlabel", lbl->key + 100);
13846   }
13847   else if (IS_AOP_PREG (IC_RESULT (ic)))
13848     {
13849       emitcode ("dec", "%s",
13850                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13851       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13852       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13853       ifx->generated = 1;
13854       emitcode ("jnz", "!tlabel", lbl->key + 100);
13855     }
13856   else
13857     {
13858       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13859                 lbl->key + 100);
13860     }
13861   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13862   emitLabel (lbl);
13863   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13864   emitLabel (lbl1);
13865
13866   if (!ifx->generated)
13867       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13868   ifx->generated = 1;
13869   return 1;
13870 }
13871
13872 /*-----------------------------------------------------------------*/
13873 /* genReceive - generate code for a receive iCode                  */
13874 /*-----------------------------------------------------------------*/
13875 static void
13876 genReceive (iCode * ic)
13877 {
13878     int size = getSize (operandType (IC_RESULT (ic)));
13879     int offset = 0;
13880     int rb1off ;
13881
13882     D (emitcode (";", "genReceive"));
13883
13884     if (ic->argreg == 1)
13885     {
13886         /* first parameter */
13887         if (AOP_IS_STR(IC_RESULT(ic)))
13888         {
13889             /* Nothing to do: it's already in the proper place. */
13890             return;
13891         }
13892         else
13893         {
13894             bool useDp2;
13895
13896             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13897                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13898                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13899
13900             _G.accInUse++;
13901             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13902             _G.accInUse--;
13903
13904             /* Sanity checking... */
13905             if (AOP_USESDPTR(IC_RESULT(ic)))
13906             {
13907                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13908                         "genReceive got unexpected DPTR.");
13909             }
13910             assignResultValue (IC_RESULT (ic), NULL);
13911         }
13912     }
13913     else if (ic->argreg > 12)
13914     { /* bit parameters */
13915       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13916         {
13917           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13918           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13919           outBitC(IC_RESULT (ic));
13920         }
13921     }
13922     else
13923     {
13924         /* second receive onwards */
13925         /* this gets a little tricky since unused receives will be
13926          eliminated, we have saved the reg in the type field . and
13927          we use that to figure out which register to use */
13928         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13929         rb1off = ic->argreg;
13930         while (size--)
13931         {
13932             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13933         }
13934     }
13935     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13936 }
13937
13938 /*-----------------------------------------------------------------*/
13939 /* genDummyRead - generate code for dummy read of volatiles        */
13940 /*-----------------------------------------------------------------*/
13941 static void
13942 genDummyRead (iCode * ic)
13943 {
13944   operand *op;
13945   int size, offset;
13946
13947   D (emitcode(";", "genDummyRead"));
13948
13949   op = IC_RIGHT (ic);
13950   if (op && IS_SYMOP (op))
13951     {
13952       aopOp (op, ic, FALSE, FALSE);
13953
13954       /* if the result is a bit */
13955       if (AOP_TYPE (op) == AOP_CRY)
13956         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13957       else
13958         {
13959           /* bit variables done */
13960           /* general case */
13961           size = AOP_SIZE (op);
13962           offset = 0;
13963           while (size--)
13964           {
13965             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13966             offset++;
13967           }
13968         }
13969
13970       freeAsmop (op, NULL, ic, TRUE);
13971     }
13972
13973   op = IC_LEFT (ic);
13974   if (op && IS_SYMOP (op))
13975     {
13976       aopOp (op, ic, FALSE, FALSE);
13977
13978       /* if the result is a bit */
13979       if (AOP_TYPE (op) == AOP_CRY)
13980         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13981       else
13982         {
13983           /* bit variables done */
13984           /* general case */
13985           size = AOP_SIZE (op);
13986           offset = 0;
13987           while (size--)
13988           {
13989             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13990             offset++;
13991           }
13992         }
13993
13994       freeAsmop (op, NULL, ic, TRUE);
13995     }
13996 }
13997
13998 /*-----------------------------------------------------------------*/
13999 /* genCritical - generate code for start of a critical sequence    */
14000 /*-----------------------------------------------------------------*/
14001 static void
14002 genCritical (iCode *ic)
14003 {
14004   symbol *tlbl = newiTempLabel (NULL);
14005
14006   D (emitcode(";", "genCritical"));
14007
14008   if (IC_RESULT (ic))
14009     {
14010       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14011       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14012       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14013       aopPut (IC_RESULT (ic), zero, 0);
14014       emitLabel (tlbl);
14015       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14016     }
14017   else
14018     {
14019       emitcode ("setb", "c");
14020       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14021       emitcode ("clr", "c");
14022       emitLabel (tlbl);
14023       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14024     }
14025 }
14026
14027 /*-----------------------------------------------------------------*/
14028 /* genEndCritical - generate code for end of a critical sequence   */
14029 /*-----------------------------------------------------------------*/
14030 static void
14031 genEndCritical (iCode *ic)
14032 {
14033   D(emitcode(";     genEndCritical",""));
14034
14035   if (IC_RIGHT (ic))
14036     {
14037       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14038       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14039         {
14040           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14041           emitcode ("mov", "ea,c");
14042         }
14043       else
14044         {
14045           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14046           emitcode ("rrc", "a");
14047           emitcode ("mov", "ea,c");
14048         }
14049       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14050     }
14051   else
14052     {
14053       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14054       emitcode ("mov", "ea,c");
14055     }
14056 }
14057
14058
14059
14060 /*-----------------------------------------------------------------*/
14061 /* genBuiltIn - calls the appropriate function to  generating code */
14062 /* for a built in function                                         */
14063 /*-----------------------------------------------------------------*/
14064 static void genBuiltIn (iCode *ic)
14065 {
14066         operand *bi_parms[MAX_BUILTIN_ARGS];
14067         int nbi_parms;
14068         iCode *bi_iCode;
14069         symbol *bif;
14070
14071         /* get all the arguments for a built in function */
14072         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14073
14074         /* which function is it */
14075         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14076         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14077                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14078         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14079                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14080         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14081                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14082         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14083                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14084         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14085                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14086         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14087                 genInp(bi_iCode,nbi_parms,bi_parms);
14088         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14089                 genOutp(bi_iCode,nbi_parms,bi_parms);
14090         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14091                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14092                 /* JavaNative builtIns */
14093         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14094                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14095         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14096                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14097         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14098                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14099         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14100                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14101         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14102                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14103         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14104                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14105         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14106                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14107         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14108                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14109         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14110                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14111         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14112                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14113         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14114                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14115         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14116                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14117         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14118                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14119         } else if (strcmp(bif->name,"MM_Free")==0) {
14120                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14121         } else if (strcmp(bif->name,"MM_Deref")==0) {
14122                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14123         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14124                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14125         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14126                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14127         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14128                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14129         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14130                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14131         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14132                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14133         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14134                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14135         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14136                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14137         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14138                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14139         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14140                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14141         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14142                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14143         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14144                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14145         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14146                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14147         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14148                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14149         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14150                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14151         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14152                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14153         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14154                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14155         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14156                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14157         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14158                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14159         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14160                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14161         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14162                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14163         } else {
14164                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14165                 return ;
14166         }
14167         return ;
14168 }
14169
14170 /*-----------------------------------------------------------------*/
14171 /* gen390Code - generate code for Dallas 390 based controllers     */
14172 /*-----------------------------------------------------------------*/
14173 void
14174 gen390Code (iCode * lic)
14175 {
14176   iCode *ic;
14177   int cln = 0;
14178
14179   _G.currentFunc = NULL;
14180   lineHead = lineCurr = NULL;
14181   dptrn[1][0] = "dpl1";
14182   dptrn[1][1] = "dph1";
14183   dptrn[1][2] = "dpx1";
14184
14185   if (options.model == MODEL_FLAT24) {
14186     fReturnSizeDS390 = 5;
14187     fReturn = fReturn24;
14188   } else {
14189     fReturnSizeDS390 = 4;
14190     fReturn = fReturn16;
14191     options.stack10bit=0;
14192   }
14193 #if 1
14194   /* print the allocation information */
14195   if (allocInfo && currFunc)
14196     printAllocInfo (currFunc, codeOutFile);
14197 #endif
14198   /* if debug information required */
14199   if (options.debug && currFunc)
14200     {
14201       debugFile->writeFunction (currFunc, lic);
14202     }
14203   /* stack pointer name */
14204   if (options.useXstack)
14205     spname = "_spx";
14206   else
14207     spname = "sp";
14208
14209
14210   for (ic = lic; ic; ic = ic->next)
14211     {
14212       _G.current_iCode = ic;
14213
14214       if (ic->lineno && cln != ic->lineno)
14215         {
14216           if (options.debug)
14217             {
14218               debugFile->writeCLine (ic);
14219             }
14220           if (!options.noCcodeInAsm) {
14221             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14222                       printCLine(ic->filename, ic->lineno));
14223           }
14224           cln = ic->lineno;
14225         }
14226       if (options.iCodeInAsm) {
14227         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14228       }
14229       /* if the result is marked as
14230          spilt and rematerializable or code for
14231          this has already been generated then
14232          do nothing */
14233       if (resultRemat (ic) || ic->generated)
14234         continue;
14235
14236       /* depending on the operation */
14237       switch (ic->op)
14238         {
14239         case '!':
14240           genNot (ic);
14241           break;
14242
14243         case '~':
14244           genCpl (ic);
14245           break;
14246
14247         case UNARYMINUS:
14248           genUminus (ic);
14249           break;
14250
14251         case IPUSH:
14252           genIpush (ic);
14253           break;
14254
14255         case IPOP:
14256           /* IPOP happens only when trying to restore a
14257              spilt live range, if there is an ifx statement
14258              following this pop then the if statement might
14259              be using some of the registers being popped which
14260              would destory the contents of the register so
14261              we need to check for this condition and handle it */
14262           if (ic->next &&
14263               ic->next->op == IFX &&
14264               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14265             genIfx (ic->next, ic);
14266           else
14267             genIpop (ic);
14268           break;
14269
14270         case CALL:
14271           genCall (ic);
14272           break;
14273
14274         case PCALL:
14275           genPcall (ic);
14276           break;
14277
14278         case FUNCTION:
14279           genFunction (ic);
14280           break;
14281
14282         case ENDFUNCTION:
14283           genEndFunction (ic);
14284           break;
14285
14286         case RETURN:
14287           genRet (ic);
14288           break;
14289
14290         case LABEL:
14291           genLabel (ic);
14292           break;
14293
14294         case GOTO:
14295           genGoto (ic);
14296           break;
14297
14298         case '+':
14299           genPlus (ic);
14300           break;
14301
14302         case '-':
14303           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14304             genMinus (ic);
14305           break;
14306
14307         case '*':
14308           genMult (ic);
14309           break;
14310
14311         case '/':
14312           genDiv (ic);
14313           break;
14314
14315         case '%':
14316           genMod (ic);
14317           break;
14318
14319         case '>':
14320           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14321           break;
14322
14323         case '<':
14324           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14325           break;
14326
14327         case LE_OP:
14328         case GE_OP:
14329         case NE_OP:
14330
14331           /* note these two are xlated by algebraic equivalence
14332              during parsing SDCC.y */
14333           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14334                   "got '>=' or '<=' shouldn't have come here");
14335           break;
14336
14337         case EQ_OP:
14338           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14339           break;
14340
14341         case AND_OP:
14342           genAndOp (ic);
14343           break;
14344
14345         case OR_OP:
14346           genOrOp (ic);
14347           break;
14348
14349         case '^':
14350           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14351           break;
14352
14353         case '|':
14354           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14355           break;
14356
14357         case BITWISEAND:
14358           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14359           break;
14360
14361         case INLINEASM:
14362           genInline (ic);
14363           break;
14364
14365         case RRC:
14366           genRRC (ic);
14367           break;
14368
14369         case RLC:
14370           genRLC (ic);
14371           break;
14372
14373         case GETHBIT:
14374           genGetHbit (ic);
14375           break;
14376
14377         case LEFT_OP:
14378           genLeftShift (ic);
14379           break;
14380
14381         case RIGHT_OP:
14382           genRightShift (ic);
14383           break;
14384
14385         case GET_VALUE_AT_ADDRESS:
14386           genPointerGet (ic,
14387                          hasInc (IC_LEFT (ic), ic,
14388                                  getSize (operandType (IC_RESULT (ic)))));
14389           break;
14390
14391         case '=':
14392           if (POINTER_SET (ic))
14393             genPointerSet (ic,
14394                            hasInc (IC_RESULT (ic), ic,
14395                                    getSize (operandType (IC_RIGHT (ic)))));
14396           else
14397             genAssign (ic);
14398           break;
14399
14400         case IFX:
14401           genIfx (ic, NULL);
14402           break;
14403
14404         case ADDRESS_OF:
14405           genAddrOf (ic);
14406           break;
14407
14408         case JUMPTABLE:
14409           genJumpTab (ic);
14410           break;
14411
14412         case CAST:
14413           genCast (ic);
14414           break;
14415
14416         case RECEIVE:
14417           genReceive (ic);
14418           break;
14419
14420         case SEND:
14421           if (ic->builtinSEND)
14422             genBuiltIn(ic);
14423           else
14424             addSet (&_G.sendSet, ic);
14425           break;
14426
14427         case DUMMY_READ_VOLATILE:
14428           genDummyRead (ic);
14429           break;
14430
14431         case CRITICAL:
14432           genCritical (ic);
14433           break;
14434
14435         case ENDCRITICAL:
14436           genEndCritical (ic);
14437           break;
14438
14439         case SWAP:
14440           genSwap (ic);
14441           break;
14442
14443 #if 0 // obsolete, and buggy for != xdata
14444         case ARRAYINIT:
14445             genArrayInit(ic);
14446             break;
14447 #endif
14448
14449         default:
14450           ic = ic;
14451         }
14452     }
14453
14454
14455   /* now we are ready to call the
14456      peep hole optimizer */
14457   if (!options.nopeep)
14458     peepHole (&lineHead);
14459
14460   /* now do the actual printing */
14461   printLine (lineHead, codeOutFile);
14462   return;
14463 }