* src/port.h: added mem.cabs_name to PORT
[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     case AOP_DPTR2:
1412     case AOP_DPTRn:
1413       return TRUE;
1414     case AOP_IMMD:
1415       return FALSE;
1416     case AOP_DIR:
1417       return FALSE;
1418     case AOP_REG:
1419       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1420       return FALSE;
1421     case AOP_CRY:
1422       return TRUE;
1423     case AOP_ACC:
1424       if (offset)
1425         return FALSE;
1426       return TRUE;
1427     case AOP_LIT:
1428       return FALSE;
1429     case AOP_STR:
1430       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1431         return TRUE;
1432       return FALSE;
1433     case AOP_DUMMY:
1434       return FALSE;
1435     default:
1436       /* Error case --- will have been caught already */
1437       wassert(0);
1438       return FALSE;
1439     }
1440 }
1441
1442 /*-------------------------------------------------------------------*/
1443 /* aopGet - for fetching value of the aop                            */
1444 /*                                                                   */
1445 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1446 /* in the accumulator. Set it to the name of a free register         */
1447 /* if acc must be preserved; the register will be used to preserve   */
1448 /* acc temporarily and to return the result byte.                    */
1449 /*-------------------------------------------------------------------*/
1450 static char *
1451 aopGet (operand * oper,
1452         int   offset,
1453         bool  bit16,
1454         bool  dname,
1455         char  *saveAcc)
1456 {
1457   asmop * aop = AOP (oper);
1458
1459   /* offset is greater than
1460      size then zero */
1461   if (offset > (aop->size - 1) &&
1462       aop->type != AOP_LIT)
1463     return zero;
1464
1465   /* depending on type */
1466   switch (aop->type)
1467     {
1468     case AOP_DUMMY:
1469       return zero;
1470
1471     case AOP_R0:
1472     case AOP_R1:
1473       /* if we need to increment it */
1474       while (offset > aop->coff)
1475         {
1476           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1477           aop->coff++;
1478         }
1479
1480       while (offset < aop->coff)
1481         {
1482           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1483           aop->coff--;
1484         }
1485
1486       aop->coff = offset;
1487       if (aop->paged)
1488         {
1489           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1490           return (dname ? "acc" : "a");
1491         }
1492       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1493       return Safe_strdup(buffer);
1494
1495     case AOP_DPTRn:
1496         assert(offset <= 3);
1497         return dptrn[aop->aopu.dptr][offset];
1498
1499     case AOP_DPTR:
1500     case AOP_DPTR2:
1501
1502       if (aop->type == AOP_DPTR2)
1503         {
1504           genSetDPTR (1);
1505         }
1506
1507       if (saveAcc)
1508         {
1509             TR_AP("#1");
1510 //          if (aop->type != AOP_DPTR2)
1511 //          {
1512 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1513 //              emitcode(";", "spanky: saveAcc for DPTR");
1514 //          }
1515
1516             emitcode ("xch", "a, %s", saveAcc);
1517         }
1518
1519       _flushLazyDPS ();
1520
1521       while (offset > aop->coff)
1522         {
1523           emitcode ("inc", "dptr");
1524           aop->coff++;
1525         }
1526
1527       while (offset < aop->coff)
1528         {
1529           emitcode ("lcall", "__decdptr");
1530           aop->coff--;
1531         }
1532
1533       aop->coff = offset;
1534       if (aop->code)
1535         {
1536           emitcode ("clr", "a");
1537           emitcode ("movc", "a,@a+dptr");
1538         }
1539       else
1540         {
1541           emitcode ("movx", "a,@dptr");
1542         }
1543
1544       if (aop->type == AOP_DPTR2)
1545         {
1546           genSetDPTR (0);
1547         }
1548
1549       if (saveAcc)
1550         {
1551           TR_AP("#2");
1552           emitcode ("xch", "a, %s", saveAcc);
1553 //        if (strcmp(saveAcc, "_ap"))
1554 //          {
1555 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1556 //          }
1557
1558           return saveAcc;
1559         }
1560       return (dname ? "acc" : "a");
1561
1562     case AOP_IMMD:
1563       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1564         {
1565           SNPRINTF(buffer, sizeof(buffer),
1566                    "%s",aop->aopu.aop_immd.aop_immd2);
1567         }
1568       else if (bit16)
1569         {
1570           SNPRINTF(buffer, sizeof(buffer),
1571                    "#%s", aop->aopu.aop_immd.aop_immd1);
1572         }
1573       else if (offset)
1574         {
1575           switch (offset) {
1576           case 1:
1577               tsprintf(buffer, sizeof(buffer),
1578                        "#!his",aop->aopu.aop_immd.aop_immd1);
1579               break;
1580           case 2:
1581               tsprintf(buffer, sizeof(buffer),
1582                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1583               break;
1584           case 3:
1585               tsprintf(buffer, sizeof(buffer),
1586                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1587               break;
1588           default: /* should not need this (just in case) */
1589               SNPRINTF (buffer, sizeof(buffer),
1590                         "#(%s >> %d)",
1591                        aop->aopu.aop_immd.aop_immd1,
1592                        offset * 8);
1593           }
1594         }
1595       else
1596         {
1597           SNPRINTF (buffer, sizeof(buffer),
1598                     "#%s",
1599                     aop->aopu.aop_immd.aop_immd1);
1600         }
1601       return Safe_strdup(buffer);
1602
1603     case AOP_DIR:
1604       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1605         {
1606           SNPRINTF (buffer, sizeof(buffer),
1607                     "(%s >> %d)",
1608                     aop->aopu.aop_dir, offset * 8);
1609         }
1610       else if (offset)
1611         {
1612           SNPRINTF (buffer, sizeof(buffer),
1613                     "(%s + %d)",
1614                    aop->aopu.aop_dir,
1615                    offset);
1616         }
1617       else
1618         {
1619           SNPRINTF (buffer, sizeof(buffer),
1620                     "%s",
1621                     aop->aopu.aop_dir);
1622         }
1623
1624       return Safe_strdup(buffer);
1625
1626     case AOP_REG:
1627       if (dname)
1628         return aop->aopu.aop_reg[offset]->dname;
1629       else
1630         return aop->aopu.aop_reg[offset]->name;
1631
1632     case AOP_CRY:
1633       emitcode ("clr", "a");
1634       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1635       emitcode ("rlc", "a");
1636       return (dname ? "acc" : "a");
1637
1638     case AOP_ACC:
1639       if (!offset && dname)
1640         return "acc";
1641       return aop->aopu.aop_str[offset];
1642
1643     case AOP_LIT:
1644       return aopLiteral (aop->aopu.aop_lit, offset);
1645
1646     case AOP_STR:
1647       aop->coff = offset;
1648       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1649           dname)
1650         return "acc";
1651
1652       return aop->aopu.aop_str[offset];
1653
1654     }
1655
1656   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1657           "aopget got unsupported aop->type");
1658   exit (1);
1659
1660   return NULL;  // not reached, but makes compiler happy.
1661 }
1662
1663 /*-----------------------------------------------------------------*/
1664 /* aopPut - puts a string for a aop and indicates if acc is in use */
1665 /*-----------------------------------------------------------------*/
1666 static bool
1667 aopPut (operand * result, const char *s, int offset)
1668 {
1669   bool bvolatile = isOperandVolatile (result, FALSE);
1670   bool accuse = FALSE;
1671   asmop * aop = AOP (result);
1672
1673   if (aop->size && offset > (aop->size - 1))
1674     {
1675       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1676               "aopPut got offset > aop->size");
1677       exit (1);
1678     }
1679
1680   /* will assign value to value */
1681   /* depending on where it is ofcourse */
1682   switch (aop->type)
1683     {
1684     case AOP_DUMMY:
1685       MOVA (s);         /* read s in case it was volatile */
1686       accuse = TRUE;
1687       break;
1688
1689     case AOP_DIR:
1690       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1691         {
1692           SNPRINTF (buffer, sizeof(buffer),
1693                     "(%s >> %d)",
1694                     aop->aopu.aop_dir, offset * 8);
1695         }
1696       else if (offset)
1697         {
1698           SNPRINTF (buffer, sizeof(buffer),
1699                     "(%s + %d)",
1700                     aop->aopu.aop_dir, offset);
1701         }
1702       else
1703         {
1704           SNPRINTF (buffer, sizeof(buffer),
1705                     "%s",
1706                     aop->aopu.aop_dir);
1707         }
1708
1709       if (strcmp (buffer, s) || bvolatile)
1710         {
1711           emitcode ("mov", "%s,%s", buffer, s);
1712         }
1713       if (!strcmp (buffer, "acc"))
1714         {
1715           accuse = TRUE;
1716         }
1717       break;
1718
1719     case AOP_REG:
1720       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1721           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1722         {
1723           if (*s == '@' ||
1724               strcmp (s, "r0") == 0 ||
1725               strcmp (s, "r1") == 0 ||
1726               strcmp (s, "r2") == 0 ||
1727               strcmp (s, "r3") == 0 ||
1728               strcmp (s, "r4") == 0 ||
1729               strcmp (s, "r5") == 0 ||
1730               strcmp (s, "r6") == 0 ||
1731               strcmp (s, "r7") == 0)
1732             {
1733               emitcode ("mov", "%s,%s",
1734                         aop->aopu.aop_reg[offset]->dname, s);
1735             }
1736             else
1737             {
1738               emitcode ("mov", "%s,%s",
1739                         aop->aopu.aop_reg[offset]->name, s);
1740             }
1741         }
1742       break;
1743
1744     case AOP_DPTRn:
1745         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1746         break;
1747
1748     case AOP_DPTR:
1749     case AOP_DPTR2:
1750
1751       if (aop->type == AOP_DPTR2)
1752         {
1753           genSetDPTR (1);
1754         }
1755       _flushLazyDPS ();
1756
1757       if (aop->code)
1758         {
1759           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1760                   "aopPut writing to code space");
1761           exit (1);
1762         }
1763
1764       while (offset > aop->coff)
1765         {
1766           aop->coff++;
1767           emitcode ("inc", "dptr");
1768         }
1769
1770       while (offset < aop->coff)
1771         {
1772           aop->coff--;
1773           emitcode ("lcall", "__decdptr");
1774         }
1775
1776       aop->coff = offset;
1777
1778       /* if not in accumulator */
1779       MOVA (s);
1780
1781       emitcode ("movx", "@dptr,a");
1782
1783       if (aop->type == AOP_DPTR2)
1784         {
1785           genSetDPTR (0);
1786         }
1787       break;
1788
1789     case AOP_R0:
1790     case AOP_R1:
1791       while (offset > aop->coff)
1792         {
1793           aop->coff++;
1794           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1795         }
1796       while (offset < aop->coff)
1797         {
1798           aop->coff--;
1799           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1800         }
1801       aop->coff = offset;
1802
1803       if (aop->paged)
1804         {
1805           MOVA (s);
1806           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1807         }
1808       else if (*s == '@')
1809         {
1810           MOVA (s);
1811           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1812         }
1813       else if (strcmp (s, "r0") == 0 ||
1814                strcmp (s, "r1") == 0 ||
1815                strcmp (s, "r2") == 0 ||
1816                strcmp (s, "r3") == 0 ||
1817                strcmp (s, "r4") == 0 ||
1818                strcmp (s, "r5") == 0 ||
1819                strcmp (s, "r6") == 0 ||
1820                strcmp (s, "r7") == 0)
1821         {
1822           char buffer[10];
1823           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1824           emitcode ("mov", "@%s,%s",
1825                     aop->aopu.aop_ptr->name, buffer);
1826         }
1827         else
1828         {
1829             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1830         }
1831       break;
1832
1833     case AOP_STK:
1834       if (strcmp (s, "a") == 0)
1835         emitcode ("push", "acc");
1836       else
1837         if (*s=='@') {
1838           MOVA(s);
1839           emitcode ("push", "acc");
1840         } else {
1841           emitcode ("push", s);
1842         }
1843
1844       break;
1845
1846     case AOP_CRY:
1847       /* if not bit variable */
1848       if (!aop->aopu.aop_dir)
1849         {
1850           /* inefficient: move carry into A and use jz/jnz */
1851           emitcode ("clr", "a");
1852           emitcode ("rlc", "a");
1853           accuse = TRUE;
1854         }
1855       else
1856         {
1857           if (s == zero)
1858             emitcode ("clr", "%s", aop->aopu.aop_dir);
1859           else if (s == one)
1860             emitcode ("setb", "%s", aop->aopu.aop_dir);
1861           else if (!strcmp (s, "c"))
1862             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1863           else if (strcmp (s, aop->aopu.aop_dir))
1864             {
1865               MOVA (s);
1866               /* set C, if a >= 1 */
1867               emitcode ("add", "a,#!constbyte",0xff);
1868               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1869             }
1870         }
1871       break;
1872
1873     case AOP_STR:
1874       aop->coff = offset;
1875       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1876         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1877       break;
1878
1879     case AOP_ACC:
1880       accuse = TRUE;
1881       aop->coff = offset;
1882       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1883         break;
1884
1885       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1886         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1887       break;
1888
1889     default:
1890       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1891               "aopPut got unsupported aop->type");
1892       exit (1);
1893     }
1894
1895     return accuse;
1896 }
1897
1898
1899 /*--------------------------------------------------------------------*/
1900 /* reAdjustPreg - points a register back to where it should (coff==0) */
1901 /*--------------------------------------------------------------------*/
1902 static void
1903 reAdjustPreg (asmop * aop)
1904 {
1905   if ((aop->coff==0) || (aop->size <= 1))
1906     return;
1907
1908   switch (aop->type)
1909     {
1910     case AOP_R0:
1911     case AOP_R1:
1912       while (aop->coff--)
1913         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1914       break;
1915     case AOP_DPTR:
1916     case AOP_DPTR2:
1917       if (aop->type == AOP_DPTR2)
1918         {
1919           genSetDPTR (1);
1920           _flushLazyDPS ();
1921         }
1922       while (aop->coff--)
1923         {
1924           emitcode ("lcall", "__decdptr");
1925         }
1926
1927       if (aop->type == AOP_DPTR2)
1928         {
1929           genSetDPTR (0);
1930         }
1931       break;
1932     }
1933   aop->coff = 0;
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* opIsGptr: returns non-zero if the passed operand is       */
1938 /* a generic pointer type.             */
1939 /*-----------------------------------------------------------------*/
1940 static int
1941 opIsGptr (operand * op)
1942 {
1943   sym_link *type = operandType (op);
1944
1945   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1946     {
1947       return 1;
1948     }
1949   return 0;
1950 }
1951
1952 /*-----------------------------------------------------------------*/
1953 /* getDataSize - get the operand data size                         */
1954 /*-----------------------------------------------------------------*/
1955 static int
1956 getDataSize (operand * op)
1957 {
1958   int size;
1959   size = AOP_SIZE (op);
1960   if (size == GPTRSIZE)
1961     {
1962       sym_link *type = operandType (op);
1963       if (IS_GENPTR (type))
1964         {
1965           /* generic pointer; arithmetic operations
1966            * should ignore the high byte (pointer type).
1967            */
1968           size--;
1969         }
1970     }
1971   return size;
1972 }
1973
1974 /*-----------------------------------------------------------------*/
1975 /* outAcc - output Acc                                             */
1976 /*-----------------------------------------------------------------*/
1977 static void
1978 outAcc (operand * result)
1979 {
1980   int size, offset;
1981   size = getDataSize (result);
1982   if (size)
1983     {
1984       aopPut (result, "a", 0);
1985       size--;
1986       offset = 1;
1987       /* unsigned or positive */
1988       while (size--)
1989         {
1990           aopPut (result, zero, offset++);
1991         }
1992     }
1993 }
1994
1995 /*-----------------------------------------------------------------*/
1996 /* outBitC - output a bit C                                        */
1997 /*-----------------------------------------------------------------*/
1998 static void
1999 outBitC (operand * result)
2000 {
2001   /* if the result is bit */
2002   if (AOP_TYPE (result) == AOP_CRY)
2003     {
2004       aopPut (result, "c", 0);
2005     }
2006   else
2007     {
2008       emitcode ("clr", "a");
2009       emitcode ("rlc", "a");
2010       outAcc (result);
2011     }
2012 }
2013
2014 /*-----------------------------------------------------------------*/
2015 /* toBoolean - emit code for orl a,operator(sizeop)                */
2016 /*-----------------------------------------------------------------*/
2017 static void
2018 toBoolean (operand * oper)
2019 {
2020   int  size = AOP_SIZE (oper) - 1;
2021   int  offset = 1;
2022   bool pushedB;
2023
2024   /* The generic part of a generic pointer should
2025    * not participate in it's truth value.
2026    *
2027    * i.e. 0x10000000 is zero.
2028    */
2029   if (opIsGptr (oper))
2030     {
2031       D (emitcode (";", "toBoolean: generic ptr special case."));
2032       size--;
2033     }
2034
2035   _startLazyDPSEvaluation ();
2036   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2037   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2038     {
2039       pushedB = pushB ();
2040       emitcode("mov", "b,a");
2041       while (--size)
2042         {
2043           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2044           emitcode ("orl", "b,a");
2045         }
2046       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2047       emitcode ("orl", "a,b");
2048       popB (pushedB);
2049     }
2050   else
2051     {
2052       while (size--)
2053         {
2054           emitcode ("orl", "a,%s",
2055                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2056         }
2057     }
2058   _endLazyDPSEvaluation ();
2059 }
2060
2061
2062 /*-----------------------------------------------------------------*/
2063 /* genNot - generate code for ! operation                          */
2064 /*-----------------------------------------------------------------*/
2065 static void
2066 genNot (iCode * ic)
2067 {
2068   symbol *tlbl;
2069
2070   D (emitcode (";", "genNot"));
2071
2072   /* assign asmOps to operand & result */
2073   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2074   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2075
2076   /* if in bit space then a special case */
2077   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2078     {
2079       /* if left==result then cpl bit */
2080       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2081         {
2082           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2083         }
2084       else
2085         {
2086           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2087           emitcode ("cpl", "c");
2088           outBitC (IC_RESULT (ic));
2089         }
2090       goto release;
2091     }
2092
2093   toBoolean (IC_LEFT (ic));
2094
2095   /* set C, if a == 0 */
2096   tlbl = newiTempLabel (NULL);
2097   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2098   emitLabel (tlbl);
2099   outBitC (IC_RESULT (ic));
2100
2101 release:
2102   /* release the aops */
2103   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2104   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2105 }
2106
2107
2108 /*-----------------------------------------------------------------*/
2109 /* genCpl - generate code for complement                           */
2110 /*-----------------------------------------------------------------*/
2111 static void
2112 genCpl (iCode * ic)
2113 {
2114   int offset = 0;
2115   int size;
2116   symbol *tlbl;
2117   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2118
2119   D(emitcode (";", "genCpl"));
2120
2121   /* assign asmOps to operand & result */
2122   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2123   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2124
2125   /* special case if in bit space */
2126   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2127     {
2128       char *l;
2129
2130       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2131           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2132         {
2133           /* promotion rules are responsible for this strange result:
2134              bit -> int -> ~int -> bit
2135              uchar -> int -> ~int -> bit
2136           */
2137           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2138           goto release;
2139         }
2140
2141       tlbl=newiTempLabel(NULL);
2142       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2143       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2144           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2145           IS_AOP_PREG (IC_LEFT (ic)))
2146         {
2147           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2148         }
2149       else
2150         {
2151           MOVA (l);
2152           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2153         }
2154       emitLabel (tlbl);
2155       outBitC (IC_RESULT(ic));
2156       goto release;
2157     }
2158
2159   size = AOP_SIZE (IC_RESULT (ic));
2160   _startLazyDPSEvaluation ();
2161   while (size--)
2162     {
2163       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2164       MOVA (l);
2165       emitcode ("cpl", "a");
2166       aopPut (IC_RESULT (ic), "a", offset++);
2167     }
2168   _endLazyDPSEvaluation ();
2169
2170
2171 release:
2172   /* release the aops */
2173   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2174   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2175 }
2176
2177 /*-----------------------------------------------------------------*/
2178 /* genUminusFloat - unary minus for floating points                */
2179 /*-----------------------------------------------------------------*/
2180 static void
2181 genUminusFloat (operand * op, operand * result)
2182 {
2183   int size, offset = 0;
2184   char *l;
2185
2186   D (emitcode (";", "genUminusFloat"));
2187
2188   /* for this we just copy and then flip the bit */
2189
2190   _startLazyDPSEvaluation ();
2191   size = AOP_SIZE (op) - 1;
2192
2193   while (size--)
2194     {
2195       aopPut (result,
2196               aopGet (op, offset, FALSE, FALSE, NULL),
2197               offset);
2198       offset++;
2199     }
2200
2201   l = aopGet (op, offset, FALSE, FALSE, NULL);
2202   MOVA (l);
2203
2204   emitcode ("cpl", "acc.7");
2205   aopPut (result, "a", offset);
2206   _endLazyDPSEvaluation ();
2207 }
2208
2209 /*-----------------------------------------------------------------*/
2210 /* genUminus - unary minus code generation                         */
2211 /*-----------------------------------------------------------------*/
2212 static void
2213 genUminus (iCode * ic)
2214 {
2215   int offset, size;
2216   sym_link *optype;
2217
2218   D (emitcode (";", "genUminus"));
2219
2220   /* assign asmops */
2221   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2222   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2223
2224   /* if both in bit space then special
2225      case */
2226   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2227       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2228     {
2229
2230       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2231       emitcode ("cpl", "c");
2232       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2233       goto release;
2234     }
2235
2236   optype = operandType (IC_LEFT (ic));
2237
2238   /* if float then do float stuff */
2239   if (IS_FLOAT (optype))
2240     {
2241       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2242       goto release;
2243     }
2244
2245   /* otherwise subtract from zero */
2246   size = AOP_SIZE (IC_LEFT (ic));
2247   offset = 0;
2248   _startLazyDPSEvaluation ();
2249   while (size--)
2250     {
2251       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2252       if (!strcmp (l, "a"))
2253         {
2254           if (offset == 0)
2255             SETC;
2256           emitcode ("cpl", "a");
2257           emitcode ("addc", "a,#0");
2258         }
2259       else
2260         {
2261           if (offset == 0)
2262             CLRC;
2263           emitcode ("clr", "a");
2264           emitcode ("subb", "a,%s", l);
2265         }
2266       aopPut (IC_RESULT (ic), "a", offset++);
2267     }
2268   _endLazyDPSEvaluation ();
2269
2270   /* if any remaining bytes in the result */
2271   /* we just need to propagate the sign   */
2272   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2273     {
2274       emitcode ("rlc", "a");
2275       emitcode ("subb", "a,acc");
2276       while (size--)
2277         aopPut (IC_RESULT (ic), "a", offset++);
2278     }
2279
2280 release:
2281   /* release the aops */
2282   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2283   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2284 }
2285
2286 /*-----------------------------------------------------------------*/
2287 /* savermask - saves registers in the mask                         */
2288 /*-----------------------------------------------------------------*/
2289 static void savermask(bitVect *rs_mask)
2290 {
2291   int i;
2292
2293   if (options.useXstack)
2294     {
2295       if (bitVectBitValue (rs_mask, R0_IDX))
2296           emitcode ("mov", "b,r0");
2297       emitcode ("mov", "r0,%s", spname);
2298       for (i = 0; i < ds390_nRegs; i++)
2299         {
2300           if (bitVectBitValue (rs_mask, i))
2301             {
2302               if (i == R0_IDX)
2303                   emitcode ("mov", "a,b");
2304               else
2305                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2306               emitcode ("movx", "@r0,a");
2307               emitcode ("inc", "r0");
2308             }
2309         }
2310       emitcode ("mov", "%s,r0", spname);
2311       if (bitVectBitValue (rs_mask, R0_IDX))
2312           emitcode ("mov", "r0,b");
2313     }
2314   else
2315     {
2316       bool bits_pushed = FALSE;
2317       for (i = 0; i < ds390_nRegs; i++)
2318         {
2319           if (bitVectBitValue (rs_mask, i))
2320             {
2321               bits_pushed = pushReg (i, bits_pushed);
2322             }
2323         }
2324     }
2325 }
2326
2327 /*-----------------------------------------------------------------*/
2328 /* saveRegisters - will look for a call and save the registers     */
2329 /*-----------------------------------------------------------------*/
2330 static void
2331 saveRegisters (iCode * lic)
2332 {
2333   iCode *ic;
2334   bitVect *rsave;
2335
2336   /* look for call */
2337   for (ic = lic; ic; ic = ic->next)
2338     if (ic->op == CALL || ic->op == PCALL)
2339       break;
2340
2341   if (!ic)
2342     {
2343       fprintf (stderr, "found parameter push with no function call\n");
2344       return;
2345     }
2346
2347   /* if the registers have been saved already or don't need to be then
2348      do nothing */
2349   if (ic->regsSaved
2350       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2351     return;
2352
2353   /* special case if DPTR alive across a function call then must save it
2354      even though callee saves */
2355   if (IS_SYMOP(IC_LEFT(ic)) &&
2356       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2357     {
2358       int i;
2359       rsave = newBitVect(ic->rMask->size);
2360       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2361           if (bitVectBitValue(ic->rMask,i))
2362               rsave = bitVectSetBit(rsave,i);
2363       }
2364       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2365     }
2366   else
2367     {
2368       /* save the registers in use at this time but skip the
2369          ones for the result */
2370       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2371                              ds390_rUmaskForOp (IC_RESULT(ic)));
2372     }
2373   ic->regsSaved = 1;
2374   savermask(rsave);
2375 }
2376
2377 /*-----------------------------------------------------------------*/
2378 /* usavermask - restore registers with mask                        */
2379 /*-----------------------------------------------------------------*/
2380 static void unsavermask(bitVect *rs_mask)
2381 {
2382   int i;
2383
2384   if (options.useXstack)
2385     {
2386       emitcode ("mov", "r0,%s", spname);
2387       for (i = ds390_nRegs; i >= 0; i--)
2388         {
2389           if (bitVectBitValue (rs_mask, i))
2390             {
2391               regs * reg = REG_WITH_INDEX (i);
2392               emitcode ("dec", "r0");
2393               emitcode ("movx", "a,@r0");
2394               if (i == R0_IDX)
2395                 {
2396                   emitcode ("push", "acc");
2397                 }
2398               else
2399                 {
2400                   emitcode ("mov", "%s,a", reg->name);
2401                 }
2402             }
2403         }
2404       emitcode ("mov", "%s,r0", spname);
2405       if (bitVectBitValue (rs_mask, R0_IDX))
2406         {
2407           emitcode ("pop", "ar0");
2408         }
2409     }
2410   else
2411     {
2412       bool bits_popped = FALSE;
2413       for (i = ds390_nRegs; i >= 0; i--)
2414         {
2415           if (bitVectBitValue (rs_mask, i))
2416             {
2417               bits_popped = popReg (i, bits_popped);
2418             }
2419         }
2420     }
2421 }
2422
2423 /*-----------------------------------------------------------------*/
2424 /* unsaveRegisters - pop the pushed registers                      */
2425 /*-----------------------------------------------------------------*/
2426 static void
2427 unsaveRegisters (iCode * ic)
2428 {
2429   bitVect *rsave;
2430
2431   if (IS_SYMOP(IC_LEFT (ic)) &&
2432       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2433       int i;
2434       rsave = newBitVect(ic->rMask->size);
2435       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2436           if (bitVectBitValue(ic->rMask,i))
2437               rsave = bitVectSetBit(rsave,i);
2438       }
2439       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2440   } else {
2441     /* restore the registers in use at this time but skip the
2442        ones for the result */
2443     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2444                            ds390_rUmaskForOp (IC_RESULT(ic)));
2445   }
2446   unsavermask(rsave);
2447 }
2448
2449
2450 /*-----------------------------------------------------------------*/
2451 /* pushSide -                */
2452 /*-----------------------------------------------------------------*/
2453 static void
2454 pushSide (operand * oper, int size)
2455 {
2456   int offset = 0;
2457   _startLazyDPSEvaluation ();
2458   while (size--)
2459     {
2460       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2461       if (AOP_TYPE (oper) != AOP_REG &&
2462           AOP_TYPE (oper) != AOP_DIR &&
2463           strcmp (l, "a"))
2464         {
2465           MOVA (l);
2466           emitcode ("push", "acc");
2467         }
2468       else
2469         {
2470           emitcode ("push", "%s", l);
2471         }
2472     }
2473   _endLazyDPSEvaluation ();
2474 }
2475
2476 /*-----------------------------------------------------------------*/
2477 /* assignResultValue - also indicates if acc is in use afterwards  */
2478 /*-----------------------------------------------------------------*/
2479 static bool
2480 assignResultValue (operand * oper, operand * func)
2481 {
2482   int offset = 0;
2483   unsigned size = AOP_SIZE (oper);
2484   bool accuse = FALSE;
2485   bool pushedA = FALSE;
2486
2487   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2488     {
2489       outBitC (oper);
2490       return FALSE;
2491     }
2492
2493   if (size == fReturnSizeDS390)
2494   {
2495       /* I don't think this case can ever happen... */
2496       /* ACC is the last part of this. If writing the result
2497        * uses ACC, we must preserve it.
2498        */
2499       if (AOP_NEEDSACC(oper))
2500       {
2501           emitcode(";", "assignResultValue special case for ACC.");
2502           emitcode("push", "acc");
2503           pushedA = TRUE;
2504           size--;
2505       }
2506   }
2507
2508   _startLazyDPSEvaluation ();
2509   while (size--)
2510     {
2511       accuse |= aopPut (oper, fReturn[offset], offset);
2512       offset++;
2513     }
2514   _endLazyDPSEvaluation ();
2515
2516   if (pushedA)
2517     {
2518         emitcode ("pop", "acc");
2519         accuse |= aopPut (oper, "a", offset);
2520     }
2521   return accuse;
2522 }
2523
2524
2525 /*-----------------------------------------------------------------*/
2526 /* genXpush - pushes onto the external stack                       */
2527 /*-----------------------------------------------------------------*/
2528 static void
2529 genXpush (iCode * ic)
2530 {
2531   asmop *aop = newAsmop (0);
2532   regs *r;
2533   int size, offset = 0;
2534
2535   D (emitcode (";", "genXpush"));
2536
2537   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2538   r = getFreePtr (ic, &aop, FALSE);
2539
2540   size = AOP_SIZE (IC_LEFT (ic));
2541
2542   if (size == 1)
2543     {
2544       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2545       emitcode ("mov", "%s,_spx", r->name);
2546       emitcode ("inc", "_spx"); // allocate space first
2547       emitcode ("movx", "@%s,a", r->name);
2548     }
2549   else
2550     {
2551       // allocate space first
2552       emitcode ("mov", "%s,_spx", r->name);
2553       MOVA (r->name);
2554       emitcode ("add", "a,#%d", size);
2555       emitcode ("mov", "_spx,a");
2556
2557       _startLazyDPSEvaluation ();
2558       while (size--)
2559         {
2560           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2561           emitcode ("movx", "@%s,a", r->name);
2562           emitcode ("inc", "%s", r->name);
2563         }
2564       _endLazyDPSEvaluation ();
2565     }
2566
2567   freeAsmop (NULL, aop, ic, TRUE);
2568   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2569 }
2570
2571 /*-----------------------------------------------------------------*/
2572 /* genIpush - generate code for pushing this gets a little complex  */
2573 /*-----------------------------------------------------------------*/
2574 static void
2575 genIpush (iCode * ic)
2576 {
2577   int size, offset = 0;
2578   char *l;
2579   char *prev = "";
2580
2581   D (emitcode (";", "genIpush"));
2582
2583   /* if this is not a parm push : ie. it is spill push
2584      and spill push is always done on the local stack */
2585   if (!ic->parmPush)
2586     {
2587
2588       /* and the item is spilt then do nothing */
2589       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2590         return;
2591
2592       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2593       size = AOP_SIZE (IC_LEFT (ic));
2594       /* push it on the stack */
2595       _startLazyDPSEvaluation ();
2596       while (size--)
2597         {
2598           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2599           if (*l == '#')
2600             {
2601               MOVA (l);
2602               l = "acc";
2603             }
2604           emitcode ("push", "%s", l);
2605         }
2606       _endLazyDPSEvaluation ();
2607       return;
2608     }
2609
2610   /* this is a parameter push: in this case we call
2611      the routine to find the call and save those
2612      registers that need to be saved */
2613   saveRegisters (ic);
2614
2615   /* if use external stack then call the external
2616      stack pushing routine */
2617   if (options.useXstack)
2618     {
2619       genXpush (ic);
2620       return;
2621     }
2622
2623   /* then do the push */
2624   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2625
2626   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2627   size = AOP_SIZE (IC_LEFT (ic));
2628
2629   _startLazyDPSEvaluation ();
2630   while (size--)
2631     {
2632       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2633       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2634           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2635           strcmp (l, "acc"))
2636         {
2637           if (strcmp (l, prev) || *l == '@')
2638             MOVA (l);
2639           emitcode ("push", "acc");
2640         }
2641       else
2642         {
2643             emitcode ("push", "%s", l);
2644         }
2645       prev = l;
2646     }
2647   _endLazyDPSEvaluation ();
2648
2649   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2650 }
2651
2652 /*-----------------------------------------------------------------*/
2653 /* genIpop - recover the registers: can happen only for spilling   */
2654 /*-----------------------------------------------------------------*/
2655 static void
2656 genIpop (iCode * ic)
2657 {
2658   int size, offset;
2659
2660   D (emitcode (";", "genIpop"));
2661
2662   /* if the temp was not pushed then */
2663   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2664     return;
2665
2666   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2667   size = AOP_SIZE (IC_LEFT (ic));
2668   offset = (size - 1);
2669   _startLazyDPSEvaluation ();
2670   while (size--)
2671     {
2672       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2673                                      FALSE, TRUE, NULL));
2674     }
2675   _endLazyDPSEvaluation ();
2676
2677   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2678 }
2679
2680 /*-----------------------------------------------------------------*/
2681 /* saveRBank - saves an entire register bank on the stack          */
2682 /*-----------------------------------------------------------------*/
2683 static void
2684 saveRBank (int bank, iCode * ic, bool pushPsw)
2685 {
2686   int i;
2687   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2688   asmop *aop = NULL;
2689   regs *r = NULL;
2690
2691   if (options.useXstack)
2692     {
2693       if (!ic)
2694         {
2695           /* Assume r0 is available for use. */
2696           r = REG_WITH_INDEX (R0_IDX);;
2697         }
2698       else
2699         {
2700           aop = newAsmop (0);
2701           r = getFreePtr (ic, &aop, FALSE);
2702         }
2703       // allocate space first
2704       emitcode ("mov", "%s,_spx", r->name);
2705       MOVA (r->name);
2706       emitcode ("add", "a,#%d", count);
2707       emitcode ("mov", "_spx,a");
2708     }
2709
2710   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2711     {
2712       if (options.useXstack)
2713         {
2714           emitcode ("mov", "a,(%s+%d)",
2715                     regs390[i].base, 8 * bank + regs390[i].offset);
2716           emitcode ("movx", "@%s,a", r->name);
2717           if (--count)
2718             emitcode ("inc", "%s", r->name);
2719         }
2720       else
2721         emitcode ("push", "(%s+%d)",
2722                   regs390[i].base, 8 * bank + regs390[i].offset);
2723     }
2724
2725   if (ds390_nBitRegs > 0)
2726     {
2727       if (options.useXstack)
2728         {
2729           emitcode ("mov", "a,bits");
2730           emitcode ("movx", "@%s,a", r->name);
2731           if (--count)
2732             emitcode ("inc", "%s", r->name);
2733         }
2734       else
2735         {
2736           emitcode ("push", "bits");
2737         }
2738       BitBankUsed = 1;
2739     }
2740
2741   if (pushPsw)
2742     {
2743       if (options.useXstack)
2744         {
2745           emitcode ("mov", "a,psw");
2746           emitcode ("movx", "@%s,a", r->name);
2747         }
2748       else
2749       {
2750         emitcode ("push", "psw");
2751       }
2752
2753       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2754     }
2755
2756   if (aop)
2757     {
2758       freeAsmop (NULL, aop, ic, TRUE);
2759     }
2760
2761   if (ic)
2762   {
2763     ic->bankSaved = 1;
2764   }
2765 }
2766
2767 /*-----------------------------------------------------------------*/
2768 /* unsaveRBank - restores the register bank from stack             */
2769 /*-----------------------------------------------------------------*/
2770 static void
2771 unsaveRBank (int bank, iCode * ic, bool popPsw)
2772 {
2773   int i;
2774   asmop *aop = NULL;
2775   regs *r = NULL;
2776
2777   if (options.useXstack)
2778     {
2779       if (!ic)
2780         {
2781           /* Assume r0 is available for use. */
2782           r = REG_WITH_INDEX (R0_IDX);;
2783         }
2784       else
2785         {
2786           aop = newAsmop (0);
2787           r = getFreePtr (ic, &aop, FALSE);
2788         }
2789       emitcode ("mov", "%s,_spx", r->name);
2790     }
2791
2792   if (popPsw)
2793     {
2794       if (options.useXstack)
2795         {
2796           emitcode ("dec", "%s", r->name);
2797           emitcode ("movx", "a,@%s", r->name);
2798           emitcode ("mov", "psw,a");
2799         }
2800       else
2801       {
2802         emitcode ("pop", "psw");
2803       }
2804     }
2805
2806   if (ds390_nBitRegs > 0)
2807     {
2808       if (options.useXstack)
2809         {
2810           emitcode ("dec", "%s", r->name);
2811           emitcode ("movx", "a,@%s", r->name);
2812           emitcode ("mov", "bits,a");
2813         }
2814       else
2815         {
2816           emitcode ("pop", "bits");
2817         }
2818     }
2819
2820   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2821     {
2822       if (options.useXstack)
2823         {
2824           emitcode ("dec", "%s", r->name);
2825           emitcode ("movx", "a,@%s", r->name);
2826           emitcode ("mov", "(%s+%d),a",
2827                     regs390[i].base, 8 * bank + regs390[i].offset);
2828         }
2829       else
2830         {
2831           emitcode ("pop", "(%s+%d)",
2832                     regs390[i].base, 8 * bank + regs390[i].offset);
2833         }
2834     }
2835
2836   if (options.useXstack)
2837     {
2838       emitcode ("mov", "_spx,%s", r->name);
2839     }
2840
2841   if (aop)
2842     {
2843       freeAsmop (NULL, aop, ic, TRUE);
2844     }
2845 }
2846
2847 /*-----------------------------------------------------------------*/
2848 /* genSend - gen code for SEND                                     */
2849 /*-----------------------------------------------------------------*/
2850 static void genSend(set *sendSet)
2851 {
2852   iCode *sic;
2853   int bit_count = 0;
2854   int sendCount = 0 ;
2855   static int rb1_count = 0;
2856
2857   /* first we do all bit parameters */
2858   for (sic = setFirstItem (sendSet); sic;
2859        sic = setNextItem (sendSet))
2860     {
2861       if (sic->argreg > 12)
2862         {
2863           int bit = sic->argreg-13;
2864
2865           aopOp (IC_LEFT (sic), sic, FALSE,
2866                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2867
2868           /* if left is a literal then
2869              we know what the value is */
2870           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2871             {
2872               if (((int) operandLitValue (IC_LEFT (sic))))
2873                   emitcode ("setb", "b[%d]", bit);
2874               else
2875                   emitcode ("clr", "b[%d]", bit);
2876             }
2877           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2878             {
2879               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2880                 if (strcmp (l, "c"))
2881                     emitcode ("mov", "c,%s", l);
2882                 emitcode ("mov", "b[%d],c", bit);
2883             }
2884           else
2885             {
2886               /* we need to or */
2887               toBoolean (IC_LEFT (sic));
2888               /* set C, if a >= 1 */
2889               emitcode ("add", "a,#0xff");
2890               emitcode ("mov", "b[%d],c", bit);
2891             }
2892           bit_count++;
2893           BitBankUsed = 1;
2894
2895           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2896         }
2897     }
2898
2899   if (bit_count)
2900     {
2901       saveRegisters (setFirstItem (sendSet));
2902       emitcode ("mov", "bits,b");
2903     }
2904
2905   /* then we do all other parameters */
2906   for (sic = setFirstItem (sendSet); sic;
2907        sic = setNextItem (sendSet))
2908     {
2909       if (sic->argreg <= 12)
2910       {
2911         int size, offset = 0;
2912
2913         size = getSize (operandType (IC_LEFT (sic)));
2914         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2915         if (sendCount == 0) { /* first parameter */
2916             // we know that dpl(hxb) is the result, so
2917             rb1_count = 0 ;
2918             _startLazyDPSEvaluation ();
2919             if (size>1) {
2920                 aopOp (IC_LEFT (sic), sic, FALSE,
2921                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2922             } else {
2923                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2924             }
2925             while (size--)
2926               {
2927                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2928                 if (strcmp (l, fReturn[offset]))
2929                   {
2930                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2931                   }
2932                 offset++;
2933               }
2934             _endLazyDPSEvaluation ();
2935             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2936             rb1_count =0;
2937         } else { /* if more parameter in registers */
2938             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2939             while (size--) {
2940                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2941                                                                 FALSE, FALSE, NULL));
2942             }
2943             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2944         }
2945         sendCount++;
2946       }
2947     }
2948 }
2949
2950 static void
2951 adjustEsp(const char *reg)
2952 {
2953     emitcode ("anl","%s,#3", reg);
2954     if (TARGET_IS_DS400)
2955     {
2956         emitcode ("orl","%s,#!constbyte",
2957                   reg,
2958                   (options.stack_loc >> 8) & 0xff);
2959     }
2960 }
2961
2962 /*-----------------------------------------------------------------*/
2963 /* selectRegBank - emit code to select the register bank           */
2964 /*-----------------------------------------------------------------*/
2965 static void
2966 selectRegBank (short bank, bool keepFlags)
2967 {
2968   /* if f.e. result is in carry */
2969   if (keepFlags)
2970     {
2971       emitcode ("anl", "psw,#0xE7");
2972       if (bank)
2973         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2974     }
2975   else
2976     {
2977       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2978     }
2979 }
2980
2981 /*-----------------------------------------------------------------*/
2982 /* genCall - generates a call statement                            */
2983 /*-----------------------------------------------------------------*/
2984 static void
2985 genCall (iCode * ic)
2986 {
2987   sym_link *dtype;
2988   sym_link *etype;
2989   bool restoreBank = FALSE;
2990   bool swapBanks = FALSE;
2991   bool accuse = FALSE;
2992   bool accPushed = FALSE;
2993   bool resultInF0 = FALSE;
2994   bool assignResultGenerated = FALSE;
2995
2996   D (emitcode (";", "genCall"));
2997
2998   /* if we are calling a not _naked function that is not using
2999      the same register bank then we need to save the
3000      destination registers on the stack */
3001   dtype = operandType (IC_LEFT (ic));
3002   etype = getSpec(dtype);
3003   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3004       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3005       IFFUNC_ISISR (currFunc->type))
3006   {
3007       if (!ic->bankSaved)
3008       {
3009            /* This is unexpected; the bank should have been saved in
3010             * genFunction.
3011             */
3012            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3013            restoreBank = TRUE;
3014       }
3015       swapBanks = TRUE;
3016   }
3017
3018   /* if caller saves & we have not saved then */
3019   if (!ic->regsSaved)
3020       saveRegisters (ic);
3021
3022   /* if send set is not empty then assign */
3023   /* We've saved all the registers we care about;
3024   * therefore, we may clobber any register not used
3025   * in the calling convention (i.e. anything not in
3026   * fReturn.
3027   */
3028   if (_G.sendSet)
3029     {
3030         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3031             genSend(reverseSet(_G.sendSet));
3032         } else {
3033             genSend(_G.sendSet);
3034         }
3035       _G.sendSet = NULL;
3036     }
3037
3038   if (swapBanks)
3039     {
3040       emitcode ("mov", "psw,#!constbyte",
3041          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3042     }
3043
3044   /* make the call */
3045   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3046                             OP_SYMBOL (IC_LEFT (ic))->rname :
3047                             OP_SYMBOL (IC_LEFT (ic))->name));
3048
3049   if (swapBanks)
3050     {
3051       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3052     }
3053
3054   /* if we need assign a result value */
3055   if ((IS_ITEMP (IC_RESULT (ic)) &&
3056        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3057        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3058         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3059         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3060       IS_TRUE_SYMOP (IC_RESULT (ic)))
3061     {
3062       if (isOperandInFarSpace (IC_RESULT (ic))
3063           && getSize (operandType (IC_RESULT (ic))) <= 2)
3064         {
3065           int size = getSize (operandType (IC_RESULT (ic)));
3066           bool pushedB = FALSE;
3067
3068           /* Special case for 1 or 2 byte return in far space. */
3069           MOVA (fReturn[0]);
3070           if (size > 1)
3071             {
3072               pushedB = pushB ();
3073               emitcode ("mov", "b,%s", fReturn[1]);
3074             }
3075
3076           _G.accInUse++;
3077           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3078           _G.accInUse--;
3079
3080           popB (pushedB);
3081
3082           aopPut (IC_RESULT (ic), "a", 0);
3083
3084           if (size > 1)
3085             {
3086               aopPut (IC_RESULT (ic), "b", 1);
3087             }
3088           assignResultGenerated = TRUE;
3089           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3090         }
3091       else
3092         {
3093           bool pushedB = pushB ();
3094           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3095           popB (pushedB);
3096
3097           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3098           assignResultGenerated = TRUE;
3099           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3100         }
3101     }
3102
3103   /* adjust the stack for parameters if required */
3104   if (ic->parmBytes)
3105     {
3106       int i;
3107       if (options.stack10bit) {
3108           if (ic->parmBytes <= 10) {
3109               emitcode(";","stack adjustment for parms");
3110               for (i=0; i < ic->parmBytes ; i++) {
3111                   emitcode("pop","acc");
3112               }
3113           } else {
3114               PROTECT_SP;
3115               emitcode ("clr","c");
3116               emitcode ("mov","a,sp");
3117               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3118               emitcode ("mov","sp,a");
3119               emitcode ("mov","a,esp");
3120               adjustEsp("a");
3121               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3122               emitcode ("mov","esp,a");
3123               UNPROTECT_SP;
3124           }
3125       } else {
3126           if (ic->parmBytes > 3)
3127             {
3128               if (accuse)
3129                 {
3130                   emitcode ("push", "acc");
3131                   accPushed = TRUE;
3132                 }
3133               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3134                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3135                   !assignResultGenerated)
3136                 {
3137                   emitcode ("mov", "F0,c");
3138                   resultInF0 = TRUE;
3139                 }
3140
3141               emitcode ("mov", "a,%s", spname);
3142               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3143               emitcode ("mov", "%s,a", spname);
3144
3145               /* unsaveRegisters from xstack needs acc, but */
3146               /* unsaveRegisters from stack needs this popped */
3147               if (accPushed && !options.useXstack)
3148                 {
3149                   emitcode ("pop", "acc");
3150                   accPushed = FALSE;
3151                 }
3152             }
3153           else
3154               for (i = 0; i < ic->parmBytes; i++)
3155                   emitcode ("dec", "%s", spname);
3156       }
3157   }
3158
3159   /* if we had saved some registers then unsave them */
3160   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3161     {
3162       if (accuse && !accPushed && options.useXstack)
3163         {
3164           /* xstack needs acc, but doesn't touch normal stack */
3165           emitcode ("push", "acc");
3166           accPushed = TRUE;
3167         }
3168       unsaveRegisters (ic);
3169     }
3170
3171   /* if register bank was saved then pop them */
3172   if (restoreBank)
3173     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3174
3175   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3176     {
3177       if (resultInF0)
3178           emitcode ("mov", "c,F0");
3179
3180       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3181       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3182       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3183     }
3184
3185   if (accPushed)
3186     emitcode ("pop", "acc");
3187 }
3188
3189 /*-----------------------------------------------------------------*/
3190 /* genPcall - generates a call by pointer statement                */
3191 /*-----------------------------------------------------------------*/
3192 static void
3193 genPcall (iCode * ic)
3194 {
3195   sym_link *dtype;
3196   sym_link *etype;
3197   symbol *rlbl = newiTempLabel (NULL);
3198   bool restoreBank=FALSE;
3199   bool resultInF0 = FALSE;
3200
3201   D (emitcode (";", "genPcall"));
3202
3203   dtype = operandType (IC_LEFT (ic))->next;
3204   etype = getSpec(dtype);
3205   /* if caller saves & we have not saved then */
3206   if (!ic->regsSaved)
3207     saveRegisters (ic);
3208
3209   /* if we are calling a not _naked function that is not using
3210      the same register bank then we need to save the
3211      destination registers on the stack */
3212   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3213       IFFUNC_ISISR (currFunc->type) &&
3214       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3215     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3216     restoreBank=TRUE;
3217   }
3218
3219   /* push the return address on to the stack */
3220   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3221   emitcode ("push", "acc");
3222   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3223   emitcode ("push", "acc");
3224
3225   if (options.model == MODEL_FLAT24)
3226     {
3227       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3228       emitcode ("push", "acc");
3229     }
3230
3231   /* now push the calling address */
3232   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3233
3234   pushSide (IC_LEFT (ic), FPTRSIZE);
3235
3236   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3237
3238   /* if send set is not empty the assign */
3239   if (_G.sendSet)
3240     {
3241         genSend(reverseSet(_G.sendSet));
3242         _G.sendSet = NULL;
3243     }
3244
3245   /* make the call */
3246   emitcode ("ret", "");
3247   emitLabel (rlbl);
3248
3249
3250   /* if we need assign a result value */
3251   if ((IS_ITEMP (IC_RESULT (ic)) &&
3252        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3253        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3254         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3255       IS_TRUE_SYMOP (IC_RESULT (ic)))
3256     {
3257
3258       _G.accInUse++;
3259       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3260       _G.accInUse--;
3261
3262       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3263
3264       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3265     }
3266
3267   /* adjust the stack for parameters if required */
3268   if (ic->parmBytes)
3269     {
3270       int i;
3271       if (options.stack10bit) {
3272           if (ic->parmBytes <= 10) {
3273               emitcode(";","stack adjustment for parms");
3274               for (i=0; i < ic->parmBytes ; i++) {
3275                   emitcode("pop","acc");
3276               }
3277           } else {
3278               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3279                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3280                 {
3281                   emitcode ("mov", "F0,c");
3282                   resultInF0 = TRUE;
3283                 }
3284
3285               PROTECT_SP;
3286               emitcode ("clr","c");
3287               emitcode ("mov","a,sp");
3288               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3289               emitcode ("mov","sp,a");
3290               emitcode ("mov","a,esp");
3291               adjustEsp("a");
3292               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3293               emitcode ("mov","esp,a");
3294               UNPROTECT_SP;
3295           }
3296       } else {
3297           if (ic->parmBytes > 3) {
3298               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3299                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3300                 {
3301                   emitcode ("mov", "F0,c");
3302                   resultInF0 = TRUE;
3303                 }
3304
3305               emitcode ("mov", "a,%s", spname);
3306               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3307               emitcode ("mov", "%s,a", spname);
3308           }
3309           else
3310               for (i = 0; i < ic->parmBytes; i++)
3311                   emitcode ("dec", "%s", spname);
3312       }
3313     }
3314   /* if register bank was saved then unsave them */
3315   if (restoreBank)
3316     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3317
3318   /* if we had saved some registers then unsave them */
3319   if (ic->regsSaved)
3320     unsaveRegisters (ic);
3321
3322   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3323     {
3324       if (resultInF0)
3325           emitcode ("mov", "c,F0");
3326
3327       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3328       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3329       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3330     }
3331 }
3332
3333 /*-----------------------------------------------------------------*/
3334 /* resultRemat - result  is rematerializable                       */
3335 /*-----------------------------------------------------------------*/
3336 static int
3337 resultRemat (iCode * ic)
3338 {
3339   if (SKIP_IC (ic) || ic->op == IFX)
3340     return 0;
3341
3342   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3343     {
3344       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3345       if (sym->remat && !POINTER_SET (ic))
3346         return 1;
3347     }
3348
3349   return 0;
3350 }
3351
3352 #if defined(__BORLANDC__) || defined(_MSC_VER)
3353 #define STRCASECMP stricmp
3354 #else
3355 #define STRCASECMP strcasecmp
3356 #endif
3357
3358 /*-----------------------------------------------------------------*/
3359 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3360 /*-----------------------------------------------------------------*/
3361 static int
3362 regsCmp(void *p1, void *p2)
3363 {
3364   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3365 }
3366
3367 static bool
3368 inExcludeList (char *s)
3369 {
3370   const char *p = setFirstItem(options.excludeRegsSet);
3371
3372   if (p == NULL || STRCASECMP(p, "none") == 0)
3373     return FALSE;
3374
3375
3376   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3377 }
3378
3379 /*-----------------------------------------------------------------*/
3380 /* genFunction - generated code for function entry                 */
3381 /*-----------------------------------------------------------------*/
3382 static void
3383 genFunction (iCode * ic)
3384 {
3385   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3386   sym_link *ftype;
3387   bool     switchedPSW = FALSE;
3388   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3389
3390   D (emitcode (";", "genFunction"));
3391
3392   _G.nRegsSaved = 0;
3393   /* create the function header */
3394   emitcode (";", "-----------------------------------------");
3395   emitcode (";", " function %s", sym->name);
3396   emitcode (";", "-----------------------------------------");
3397
3398   emitcode ("", "%s:", sym->rname);
3399   ftype = operandType (IC_LEFT (ic));
3400   _G.currentFunc = sym;
3401
3402   if (IFFUNC_ISNAKED(ftype))
3403   {
3404       emitcode(";", "naked function: no prologue.");
3405       return;
3406   }
3407
3408   if (options.stack_probe)
3409       emitcode ("lcall","__stack_probe");
3410
3411   /* here we need to generate the equates for the
3412      register bank if required */
3413   if (FUNC_REGBANK (ftype) != rbank)
3414     {
3415       int i;
3416
3417       rbank = FUNC_REGBANK (ftype);
3418       for (i = 0; i < ds390_nRegs; i++)
3419         {
3420           if (regs390[i].print) {
3421               if (strcmp (regs390[i].base, "0") == 0)
3422                   emitcode ("", "%s !equ !constbyte",
3423                             regs390[i].dname,
3424                             8 * rbank + regs390[i].offset);
3425               else
3426                   emitcode ("", "%s !equ %s + !constbyte",
3427                             regs390[i].dname,
3428                             regs390[i].base,
3429                             8 * rbank + regs390[i].offset);
3430           }
3431         }
3432     }
3433
3434   /* if this is an interrupt service routine then
3435      save acc, b, dpl, dph  */
3436   if (IFFUNC_ISISR (sym->type))
3437       { /* is ISR */
3438       if (!inExcludeList ("acc"))
3439         emitcode ("push", "acc");
3440       if (!inExcludeList ("b"))
3441         emitcode ("push", "b");
3442       if (!inExcludeList ("dpl"))
3443         emitcode ("push", "dpl");
3444       if (!inExcludeList ("dph"))
3445         emitcode ("push", "dph");
3446       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3447         {
3448           emitcode ("push", "dpx");
3449           /* Make sure we're using standard DPTR */
3450           emitcode ("push", "dps");
3451           emitcode ("mov", "dps,#0");
3452           if (options.stack10bit)
3453             {
3454               /* This ISR could conceivably use DPTR2. Better save it. */
3455               emitcode ("push", "dpl1");
3456               emitcode ("push", "dph1");
3457               emitcode ("push", "dpx1");
3458               emitcode ("push",  DP2_RESULT_REG);
3459             }
3460         }
3461       /* if this isr has no bank i.e. is going to
3462          run with bank 0 , then we need to save more
3463          registers :-) */
3464       if (!FUNC_REGBANK (sym->type))
3465         {
3466             int i;
3467
3468           /* if this function does not call any other
3469              function then we can be economical and
3470              save only those registers that are used */
3471           if (!IFFUNC_HASFCALL(sym->type))
3472             {
3473               /* if any registers used */
3474               if (sym->regsUsed)
3475                 {
3476                   bool bits_pushed = FALSE;
3477                   /* save the registers used */
3478                   for (i = 0; i < sym->regsUsed->size; i++)
3479                     {
3480                       if (bitVectBitValue (sym->regsUsed, i))
3481                         bits_pushed = pushReg (i, bits_pushed);
3482                     }
3483                 }
3484             }
3485           else
3486             {
3487               /* this function has a function call. We cannot
3488                  determine register usage so we will have to push the
3489                  entire bank */
3490               saveRBank (0, ic, FALSE);
3491               if (options.parms_in_bank1) {
3492                   for (i=0; i < 8 ; i++ ) {
3493                       emitcode ("push","%s",rb1regs[i]);
3494                   }
3495               }
3496             }
3497         }
3498         else
3499         {
3500             /* This ISR uses a non-zero bank.
3501              *
3502              * We assume that the bank is available for our
3503              * exclusive use.
3504              *
3505              * However, if this ISR calls a function which uses some
3506              * other bank, we must save that bank entirely.
3507              */
3508             unsigned long banksToSave = 0;
3509
3510             if (IFFUNC_HASFCALL(sym->type))
3511             {
3512
3513 #define MAX_REGISTER_BANKS 4
3514
3515                 iCode *i;
3516                 int ix;
3517
3518                 for (i = ic; i; i = i->next)
3519                 {
3520                     if (i->op == ENDFUNCTION)
3521                     {
3522                         /* we got to the end OK. */
3523                         break;
3524                     }
3525
3526                     if (i->op == CALL)
3527                     {
3528                         sym_link *dtype;
3529
3530                         dtype = operandType (IC_LEFT(i));
3531                         if (dtype
3532                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3533                         {
3534                              /* Mark this bank for saving. */
3535                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3536                              {
3537                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3538                              }
3539                              else
3540                              {
3541                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3542                              }
3543
3544                              /* And note that we don't need to do it in
3545                               * genCall.
3546                               */
3547                              i->bankSaved = 1;
3548                         }
3549                     }
3550                     if (i->op == PCALL)
3551                     {
3552                         /* This is a mess; we have no idea what
3553                          * register bank the called function might
3554                          * use.
3555                          *
3556                          * The only thing I can think of to do is
3557                          * throw a warning and hope.
3558                          */
3559                         werror(W_FUNCPTR_IN_USING_ISR);
3560                     }
3561                 }
3562
3563                 if (banksToSave && options.useXstack)
3564                 {
3565                     /* Since we aren't passing it an ic,
3566                      * saveRBank will assume r0 is available to abuse.
3567                      *
3568                      * So switch to our (trashable) bank now, so
3569                      * the caller's R0 isn't trashed.
3570                      */
3571                     emitcode ("push", "psw");
3572                     emitcode ("mov", "psw,#!constbyte",
3573                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3574                     switchedPSW = TRUE;
3575                 }
3576
3577                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3578                 {
3579                      if (banksToSave & (1 << ix))
3580                      {
3581                          saveRBank(ix, NULL, FALSE);
3582                      }
3583                 }
3584             }
3585             // TODO: this needs a closer look
3586             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3587         }
3588     }
3589   else
3590     {
3591       /* if callee-save to be used for this function
3592          then save the registers being used in this function */
3593       if (IFFUNC_CALLEESAVES(sym->type))
3594         {
3595           int i;
3596
3597           /* if any registers used */
3598           if (sym->regsUsed)
3599             {
3600               bool bits_pushed = FALSE;
3601               /* save the registers used */
3602               for (i = 0; i < sym->regsUsed->size; i++)
3603                 {
3604                   if (bitVectBitValue (sym->regsUsed, i))
3605                     {
3606                       bits_pushed = pushReg (i, bits_pushed);
3607                       _G.nRegsSaved++;
3608                     }
3609                 }
3610             }
3611         }
3612     }
3613
3614   /* set the register bank to the desired value */
3615   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3616    && !switchedPSW)
3617     {
3618       emitcode ("push", "psw");
3619       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3620     }
3621
3622   if (fReentrant &&
3623        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3624       if (options.stack10bit) {
3625           emitcode ("push","_bpx");
3626           emitcode ("push","_bpx+1");
3627           emitcode ("mov","_bpx,%s",spname);
3628           emitcode ("mov","_bpx+1,esp");
3629           adjustEsp("_bpx+1");
3630       } else {
3631           if (options.useXstack)
3632           {
3633               emitcode ("mov", "r0,%s", spname);
3634               emitcode ("mov", "a,_bp");
3635               emitcode ("movx", "@r0,a");
3636               emitcode ("inc", "%s", spname);
3637           } else {
3638               /* set up the stack */
3639               emitcode ("push", "_bp"); /* save the callers stack  */
3640           }
3641           emitcode ("mov", "_bp,%s", spname);
3642       }
3643   }
3644
3645   /* adjust the stack for the function */
3646   if (sym->stack) {
3647       int i = sym->stack;
3648       if (options.stack10bit) {
3649           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3650           assert (sym->recvSize <= 4);
3651           if (sym->stack <= 8) {
3652               while (i--) emitcode ("push","acc");
3653           } else {
3654               PROTECT_SP;
3655               emitcode ("mov","a,sp");
3656               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3657               emitcode ("mov","sp,a");
3658               emitcode ("mov","a,esp");
3659               adjustEsp("a");
3660               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3661               emitcode ("mov","esp,a");
3662               UNPROTECT_SP;
3663           }
3664       } else {
3665           if (i > 256)
3666               werror (W_STACK_OVERFLOW, sym->name);
3667
3668           if (i > 3 && sym->recvSize < 4) {
3669
3670               emitcode ("mov", "a,sp");
3671               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3672               emitcode ("mov", "sp,a");
3673
3674           } else
3675               while (i--)
3676                   emitcode ("inc", "sp");
3677       }
3678   }
3679
3680   if (sym->xstack)
3681     {
3682
3683       emitcode ("mov", "a,_spx");
3684       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3685       emitcode ("mov", "_spx,a");
3686     }
3687
3688   /* if critical function then turn interrupts off */
3689   if (IFFUNC_ISCRITICAL (ftype))
3690     {
3691       symbol *tlbl = newiTempLabel (NULL);
3692       emitcode ("setb", "c");
3693       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3694       emitcode ("clr", "c");
3695       emitLabel (tlbl);
3696       emitcode ("push", "psw"); /* save old ea via c in psw */
3697     }
3698 }
3699
3700 /*-----------------------------------------------------------------*/
3701 /* genEndFunction - generates epilogue for functions               */
3702 /*-----------------------------------------------------------------*/
3703 static void
3704 genEndFunction (iCode * ic)
3705 {
3706   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3707   lineNode *lnp = lineCurr;
3708   bitVect *regsUsed;
3709   bitVect *regsUsedPrologue;
3710   bitVect *regsUnneeded;
3711   int idx;
3712
3713   D (emitcode (";", "genEndFunction"));
3714
3715   _G.currentFunc = NULL;
3716   if (IFFUNC_ISNAKED(sym->type))
3717   {
3718       emitcode(";", "naked function: no epilogue.");
3719       if (options.debug && currFunc)
3720         debugFile->writeEndFunction (currFunc, ic, 0);
3721       return;
3722   }
3723
3724   if (IFFUNC_ISCRITICAL (sym->type))
3725     {
3726       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3727         {
3728           emitcode ("rlc", "a");   /* save c in a */
3729           emitcode ("pop", "psw"); /* restore ea via c in psw */
3730           emitcode ("mov", "ea,c");
3731           emitcode ("rrc", "a");   /* restore c from a */
3732         }
3733       else
3734         {
3735           emitcode ("pop", "psw"); /* restore ea via c in psw */
3736           emitcode ("mov", "ea,c");
3737         }
3738     }
3739
3740   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3741        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3742
3743       if (options.stack10bit) {
3744           PROTECT_SP;
3745           emitcode ("mov", "sp,_bpx", spname);
3746           emitcode ("mov", "esp,_bpx+1", spname);
3747           UNPROTECT_SP;
3748       } else {
3749           emitcode ("mov", "%s,_bp", spname);
3750       }
3751   }
3752
3753   /* if use external stack but some variables were
3754      added to the local stack then decrement the
3755      local stack */
3756   if (options.useXstack && sym->stack) {
3757       emitcode ("mov", "a,sp");
3758       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3759       emitcode ("mov", "sp,a");
3760   }
3761
3762
3763   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3764        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3765
3766       if (options.useXstack) {
3767           emitcode ("mov", "r0,%s", spname);
3768           emitcode ("movx", "a,@r0");
3769           emitcode ("mov", "_bp,a");
3770           emitcode ("dec", "%s", spname);
3771       } else {
3772           if (options.stack10bit) {
3773               emitcode ("pop", "_bpx+1");
3774               emitcode ("pop", "_bpx");
3775           } else {
3776               emitcode ("pop", "_bp");
3777           }
3778       }
3779   }
3780
3781   /* restore the register bank  */
3782   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3783   {
3784     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3785      || !options.useXstack)
3786     {
3787         /* Special case of ISR using non-zero bank with useXstack
3788          * is handled below.
3789          */
3790         emitcode ("pop", "psw");
3791     }
3792   }
3793
3794   if (IFFUNC_ISISR (sym->type))
3795     { /* is ISR */
3796
3797       /* now we need to restore the registers */
3798       /* if this isr has no bank i.e. is going to
3799          run with bank 0 , then we need to save more
3800          registers :-) */
3801       if (!FUNC_REGBANK (sym->type))
3802         {
3803           int i;
3804           /* if this function does not call any other
3805              function then we can be economical and
3806              save only those registers that are used */
3807           if (!IFFUNC_HASFCALL(sym->type))
3808             {
3809               /* if any registers used */
3810               if (sym->regsUsed)
3811                 {
3812                   bool bits_popped = FALSE;
3813                   /* save the registers used */
3814                   for (i = sym->regsUsed->size; i >= 0; i--)
3815                     {
3816                       if (bitVectBitValue (sym->regsUsed, i))
3817                         bits_popped = popReg (i, bits_popped);
3818                     }
3819                 }
3820             }
3821           else
3822             {
3823               /* this function has a function call. We cannot
3824                  determine register usage so we will have to pop the
3825                  entire bank */
3826               if (options.parms_in_bank1) {
3827                   for (i = 7 ; i >= 0 ; i-- ) {
3828                       emitcode ("pop","%s",rb1regs[i]);
3829                   }
3830               }
3831               unsaveRBank (0, ic, FALSE);
3832             }
3833         }
3834       else
3835         {
3836             /* This ISR uses a non-zero bank.
3837              *
3838              * Restore any register banks saved by genFunction
3839              * in reverse order.
3840              */
3841             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3842             int ix;
3843
3844             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3845             {
3846                 if (savedBanks & (1 << ix))
3847                 {
3848                     unsaveRBank(ix, NULL, FALSE);
3849                 }
3850             }
3851
3852             if (options.useXstack)
3853             {
3854                 /* Restore bank AFTER calling unsaveRBank,
3855                  * since it can trash r0.
3856                  */
3857                 emitcode ("pop", "psw");
3858             }
3859         }
3860
3861       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3862         {
3863           if (options.stack10bit)
3864             {
3865               emitcode ("pop", DP2_RESULT_REG);
3866               emitcode ("pop", "dpx1");
3867               emitcode ("pop", "dph1");
3868               emitcode ("pop", "dpl1");
3869             }
3870           emitcode ("pop", "dps");
3871           emitcode ("pop", "dpx");
3872         }
3873       if (!inExcludeList ("dph"))
3874         emitcode ("pop", "dph");
3875       if (!inExcludeList ("dpl"))
3876         emitcode ("pop", "dpl");
3877       if (!inExcludeList ("b"))
3878         emitcode ("pop", "b");
3879       if (!inExcludeList ("acc"))
3880         emitcode ("pop", "acc");
3881
3882       /* if debug then send end of function */
3883       if (options.debug && currFunc)
3884         {
3885           debugFile->writeEndFunction (currFunc, ic, 1);
3886         }
3887
3888       emitcode ("reti", "");
3889     }
3890   else
3891     {
3892       if (IFFUNC_CALLEESAVES(sym->type))
3893         {
3894           int i;
3895
3896           /* if any registers used */
3897           if (sym->regsUsed)
3898             {
3899               /* save the registers used */
3900               for (i = sym->regsUsed->size; i >= 0; i--)
3901                 {
3902                   if (bitVectBitValue (sym->regsUsed, i))
3903                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3904                 }
3905             }
3906         }
3907
3908       /* if debug then send end of function */
3909       if (options.debug && currFunc)
3910         {
3911           debugFile->writeEndFunction (currFunc, ic, 1);
3912         }
3913
3914       emitcode ("ret", "");
3915     }
3916
3917   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3918     return;
3919
3920   /* If this was an interrupt handler using bank 0 that called another */
3921   /* function, then all registers must be saved; nothing to optimized. */
3922   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3923       && !FUNC_REGBANK(sym->type))
3924     return;
3925
3926   /* There are no push/pops to optimize if not callee-saves or ISR */
3927   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3928     return;
3929
3930   /* If there were stack parameters, we cannot optimize without also    */
3931   /* fixing all of the stack offsets; this is too dificult to consider. */
3932   if (FUNC_HASSTACKPARM(sym->type))
3933     return;
3934
3935   /* Compute the registers actually used */
3936   regsUsed = newBitVect (ds390_nRegs);
3937   regsUsedPrologue = newBitVect (ds390_nRegs);
3938   while (lnp)
3939     {
3940       if (lnp->ic && lnp->ic->op == FUNCTION)
3941         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3942       else
3943         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3944
3945       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3946           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3947         break;
3948       if (!lnp->prev)
3949         break;
3950       lnp = lnp->prev;
3951     }
3952
3953   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3954       && !bitVectBitValue (regsUsed, DPS_IDX))
3955     {
3956       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3957     }
3958
3959   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3960       && !bitVectBitValue (regsUsed, CND_IDX))
3961     {
3962       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3963       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3964           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3965         bitVectUnSetBit (regsUsed, CND_IDX);
3966     }
3967   else
3968     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3969
3970   /* If this was an interrupt handler that called another function */
3971   /* function, then assume working registers may be modified by it. */
3972   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3973     {
3974       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3975       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3976       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3985     }
3986
3987   /* Remove the unneeded push/pops */
3988   regsUnneeded = newBitVect (ds390_nRegs);
3989   while (lnp)
3990     {
3991       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3992         {
3993           if (!strncmp(lnp->line, "push", 4))
3994             {
3995               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3996               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3997                 {
3998                   connectLine (lnp->prev, lnp->next);
3999                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4000                 }
4001             }
4002           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4003             {
4004               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4005               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4006                 {
4007                   connectLine (lnp->prev, lnp->next);
4008                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4009                 }
4010             }
4011         }
4012       lnp = lnp->next;
4013     }
4014
4015   for (idx = 0; idx < regsUnneeded->size; idx++)
4016     if (bitVectBitValue (regsUnneeded, idx))
4017       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4018
4019   freeBitVect (regsUnneeded);
4020   freeBitVect (regsUsed);
4021   freeBitVect (regsUsedPrologue);
4022 }
4023
4024 /*-----------------------------------------------------------------*/
4025 /* genJavaNativeRet - generate code for return JavaNative          */
4026 /*-----------------------------------------------------------------*/
4027 static void genJavaNativeRet(iCode *ic)
4028 {
4029     int i, size;
4030
4031     aopOp (IC_LEFT (ic), ic, FALSE,
4032            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4033     size = AOP_SIZE (IC_LEFT (ic));
4034
4035     assert (size <= 4);
4036
4037     /* it is assigned to GPR0-R3 then push them */
4038     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4039         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4040         for (i = 0 ; i < size ; i++ ) {
4041             emitcode ("push","%s",
4042                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4043         }
4044         for (i = (size-1) ; i >= 0 ; i--) {
4045             emitcode ("pop","a%s",javaRet[i]);
4046         }
4047     } else {
4048         for (i = 0 ; i < size ; i++)
4049             emitcode ("mov","%s,%s",javaRet[i],
4050                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4051     }
4052     for (i = size ; i < 4 ; i++ )
4053             emitcode ("mov","%s,#0",javaRet[i]);
4054     return;
4055 }
4056
4057 /*-----------------------------------------------------------------*/
4058 /* genRet - generate code for return statement                     */
4059 /*-----------------------------------------------------------------*/
4060 static void
4061 genRet (iCode * ic)
4062 {
4063   int size, offset = 0, pushed = 0;
4064
4065   D (emitcode (";", "genRet"));
4066
4067   /* if we have no return value then
4068      just generate the "ret" */
4069   if (!IC_LEFT (ic))
4070     goto jumpret;
4071
4072   /* if this is a JavaNative function then return
4073      value in different register */
4074   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4075       genJavaNativeRet(ic);
4076       goto jumpret;
4077   }
4078   /* we have something to return then
4079      move the return value into place */
4080   aopOp (IC_LEFT (ic), ic, FALSE,
4081          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4082   size = AOP_SIZE (IC_LEFT (ic));
4083
4084   _startLazyDPSEvaluation ();
4085
4086   if (IS_BIT(_G.currentFunc->etype))
4087     {
4088       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4089       size = 0;
4090     }
4091
4092   while (size--)
4093     {
4094       char *l;
4095       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4096         {
4097           l = aopGet (IC_LEFT (ic), offset++,
4098                       FALSE, TRUE, NULL);
4099           emitcode ("push", "%s", l);
4100           pushed++;
4101         }
4102       else
4103         {
4104           /* Since A is the last element of fReturn,
4105            * it is OK to clobber it in the aopGet.
4106            */
4107           l = aopGet (IC_LEFT (ic), offset,
4108                       FALSE, FALSE, NULL);
4109           if (strcmp (fReturn[offset], l))
4110             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4111         }
4112     }
4113   _endLazyDPSEvaluation ();
4114
4115   while (pushed)
4116     {
4117       pushed--;
4118       if (strcmp (fReturn[pushed], "a"))
4119         emitcode ("pop", fReturn[pushed]);
4120       else
4121         emitcode ("pop", "acc");
4122     }
4123   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4124
4125 jumpret:
4126   /* generate a jump to the return label
4127      if the next is not the return statement */
4128   if (!(ic->next && ic->next->op == LABEL &&
4129         IC_LABEL (ic->next) == returnLabel))
4130
4131     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4132
4133 }
4134
4135 /*-----------------------------------------------------------------*/
4136 /* genLabel - generates a label                                    */
4137 /*-----------------------------------------------------------------*/
4138 static void
4139 genLabel (iCode * ic)
4140 {
4141   /* special case never generate */
4142   if (IC_LABEL (ic) == entryLabel)
4143     return;
4144
4145   D (emitcode (";", "genLabel"));
4146
4147   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4148 }
4149
4150 /*-----------------------------------------------------------------*/
4151 /* genGoto - generates a ljmp                                      */
4152 /*-----------------------------------------------------------------*/
4153 static void
4154 genGoto (iCode * ic)
4155 {
4156   D (emitcode (";", "genGoto"));
4157
4158   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4159 }
4160
4161 /*-----------------------------------------------------------------*/
4162 /* findLabelBackwards: walks back through the iCode chain looking  */
4163 /* for the given label. Returns number of iCode instructions     */
4164 /* between that label and given ic.          */
4165 /* Returns zero if label not found.          */
4166 /*-----------------------------------------------------------------*/
4167 static int
4168 findLabelBackwards (iCode * ic, int key)
4169 {
4170   int count = 0;
4171
4172   while (ic->prev)
4173     {
4174       ic = ic->prev;
4175       count++;
4176
4177       /* If we have any pushes or pops, we cannot predict the distance.
4178          I don't like this at all, this should be dealt with in the
4179          back-end */
4180       if (ic->op == IPUSH || ic->op == IPOP) {
4181         return 0;
4182       }
4183
4184       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4185         {
4186           /* printf("findLabelBackwards = %d\n", count); */
4187           return count;
4188         }
4189     }
4190
4191   return 0;
4192 }
4193
4194 /*-----------------------------------------------------------------*/
4195 /* genPlusIncr :- does addition with increment if possible         */
4196 /*-----------------------------------------------------------------*/
4197 static bool
4198 genPlusIncr (iCode * ic)
4199 {
4200   unsigned int icount;
4201   unsigned int size = getDataSize (IC_RESULT (ic));
4202
4203   /* will try to generate an increment */
4204   /* if the right side is not a literal
4205      we cannot */
4206   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4207     return FALSE;
4208
4209   /* if the literal value of the right hand side
4210      is greater than 4 then it is not worth it */
4211   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4212     return FALSE;
4213
4214   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4215       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4216       while (icount--) {
4217           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4218       }
4219       return TRUE;
4220   }
4221   /* if increment 16 bits in register */
4222   if (
4223        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4224        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4225        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4226        (size > 1) &&
4227        (icount == 1))
4228     {
4229       symbol  *tlbl;
4230       int     emitTlbl;
4231       int     labelRange;
4232       char    *l;
4233
4234       /* If the next instruction is a goto and the goto target
4235        * is <= 5 instructions previous to this, we can generate
4236        * jumps straight to that target.
4237        */
4238       if (ic->next && ic->next->op == GOTO
4239           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4240           && labelRange <= 5)
4241         {
4242           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4243           tlbl = IC_LABEL (ic->next);
4244           emitTlbl = 0;
4245         }
4246       else
4247         {
4248           tlbl = newiTempLabel (NULL);
4249           emitTlbl = 1;
4250         }
4251       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4252       emitcode ("inc", "%s", l);
4253
4254       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4255           IS_AOP_PREG (IC_RESULT (ic)))
4256         {
4257           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4258         }
4259       else
4260         {
4261           emitcode ("clr", "a");
4262           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4263         }
4264
4265       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4266       emitcode ("inc", "%s", l);
4267       if (size > 2)
4268         {
4269           if (!strcmp(l, "acc"))
4270             {
4271                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4272             }
4273           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4274                    IS_AOP_PREG (IC_RESULT (ic)))
4275             {
4276                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4277             }
4278           else
4279             {
4280                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4281             }
4282
4283           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4284           emitcode ("inc", "%s", l);
4285         }
4286       if (size > 3)
4287         {
4288           if (!strcmp(l, "acc"))
4289             {
4290                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4291             }
4292           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4293                    IS_AOP_PREG (IC_RESULT (ic)))
4294             {
4295                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4296             }
4297           else
4298             {
4299                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4300             }
4301
4302           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4303           emitcode ("inc", "%s", l);
4304         }
4305
4306       if (emitTlbl)
4307         {
4308           emitLabel (tlbl);
4309         }
4310       return TRUE;
4311     }
4312
4313   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4314       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4315       options.model == MODEL_FLAT24 )
4316     {
4317       if (IC_RESULT(ic)->isGptr)
4318         {
4319           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4320         }
4321       switch (size) {
4322       case 3:
4323           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4324       case 2:
4325           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4326       case 1:
4327           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4328           break;
4329       }
4330       while (icount--)
4331         emitcode ("inc", "dptr");
4332       return TRUE;
4333   }
4334
4335   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4336       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4337       icount <= 5 ) {
4338       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4339       while (icount--)
4340         emitcode ("inc", "dptr");
4341       emitcode ("mov", "dps,#0");
4342       return TRUE;
4343   }
4344
4345   /* if the sizes are greater than 1 then we cannot */
4346   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4347       AOP_SIZE (IC_LEFT (ic)) > 1)
4348     return FALSE;
4349
4350   /* we can if the aops of the left & result match or
4351      if they are in registers and the registers are the
4352      same */
4353   if (
4354        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4355        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4356        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4357     {
4358       if (icount > 3)
4359         {
4360           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4361           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4362           aopPut (IC_RESULT (ic), "a", 0);
4363         }
4364       else
4365         {
4366           _startLazyDPSEvaluation ();
4367           while (icount--)
4368             {
4369               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4370             }
4371           _endLazyDPSEvaluation ();
4372         }
4373
4374       return TRUE;
4375     }
4376
4377   return FALSE;
4378 }
4379
4380 /*-----------------------------------------------------------------*/
4381 /* outBitAcc - output a bit in acc                                 */
4382 /*-----------------------------------------------------------------*/
4383 static void
4384 outBitAcc (operand * result)
4385 {
4386   symbol *tlbl = newiTempLabel (NULL);
4387   /* if the result is a bit */
4388   if (AOP_TYPE (result) == AOP_CRY)
4389     {
4390       aopPut (result, "a", 0);
4391     }
4392   else
4393     {
4394       emitcode ("jz", "!tlabel", tlbl->key + 100);
4395       emitcode ("mov", "a,%s", one);
4396       emitLabel (tlbl);
4397       outAcc (result);
4398     }
4399 }
4400
4401 /*-----------------------------------------------------------------*/
4402 /* genPlusBits - generates code for addition of two bits           */
4403 /*-----------------------------------------------------------------*/
4404 static void
4405 genPlusBits (iCode * ic)
4406 {
4407   D (emitcode (";", "genPlusBits"));
4408
4409   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4410     {
4411       symbol *lbl = newiTempLabel (NULL);
4412       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4413       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4414       emitcode ("cpl", "c");
4415       emitLabel (lbl);
4416       outBitC (IC_RESULT (ic));
4417     }
4418   else
4419     {
4420       emitcode ("clr", "a");
4421       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4422       emitcode ("rlc", "a");
4423       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4424       emitcode ("addc", "a,%s", zero);
4425       outAcc (IC_RESULT (ic));
4426     }
4427 }
4428
4429 static void
4430 adjustArithmeticResult (iCode * ic)
4431 {
4432   if (opIsGptr (IC_RESULT (ic)) &&
4433       opIsGptr (IC_LEFT (ic)) &&
4434       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4435     {
4436       aopPut (IC_RESULT (ic),
4437               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4438               GPTRSIZE - 1);
4439     }
4440
4441   if (opIsGptr (IC_RESULT (ic)) &&
4442       opIsGptr (IC_RIGHT (ic)) &&
4443       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4444     {
4445       aopPut (IC_RESULT (ic),
4446               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4447               GPTRSIZE - 1);
4448     }
4449
4450   if (opIsGptr (IC_RESULT (ic)) &&
4451       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4452       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4453       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4454       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4455     {
4456       char buffer[5];
4457       SNPRINTF (buffer, sizeof(buffer),
4458                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4459       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4460     }
4461 }
4462
4463 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4464 // generates the result if possible. If result is generated, returns TRUE; otherwise
4465 // returns false and caller must deal with fact that result isn't aopOp'd.
4466 bool aopOp3(iCode * ic)
4467 {
4468     bool dp1InUse, dp2InUse;
4469     bool useDp2;
4470
4471     // First, generate the right opcode. DPTR may be used if neither left nor result are
4472     // of type AOP_STR.
4473
4474 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4475 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4476 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4477 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4478 //      );
4479 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4480 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4481 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4482 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4483 //      );
4484
4485     // Right uses DPTR unless left or result is an AOP_STR; however,
4486     // if right is an AOP_STR, it must use DPTR regardless.
4487     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4488      && !AOP_IS_STR (IC_RIGHT (ic)))
4489     {
4490         useDp2 = TRUE;
4491     }
4492     else
4493     {
4494         useDp2 = FALSE;
4495     }
4496
4497     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4498
4499     // if the right used DPTR, left MUST use DPTR2.
4500     // if the right used DPTR2, left MUST use DPTR.
4501     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4502     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4503     // enabling us to assign DPTR to result.
4504
4505     if (AOP_USESDPTR (IC_RIGHT (ic)))
4506     {
4507         useDp2 = TRUE;
4508     }
4509     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4510     {
4511         useDp2 = FALSE;
4512     }
4513     else
4514     {
4515         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4516         {
4517             useDp2 = TRUE;
4518         }
4519         else
4520         {
4521             useDp2 = FALSE;
4522         }
4523     }
4524
4525     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4526
4527
4528     // We've op'd the left & right. So, if left or right are the same operand as result,
4529     // we know aopOp will succeed, and we can just do it & bail.
4530     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4531       {
4532         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4533         return TRUE;
4534       }
4535     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4536       {
4537 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4538         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4539         return TRUE;
4540       }
4541
4542     // Operands may be equivalent (but not equal) if they share a spill location. If
4543     // so, use the same DPTR or DPTR2.
4544     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4545       {
4546         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4547         return TRUE;
4548       }
4549     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4550       {
4551         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4552         return TRUE;
4553       }
4554
4555     // Note which dptrs are currently in use.
4556     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4557     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4558
4559     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4560     // generate it.
4561     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4562     {
4563         return FALSE;
4564     }
4565
4566     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4567     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4568     {
4569         return FALSE;
4570     }
4571
4572     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4573     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4574     {
4575         return FALSE;
4576     }
4577
4578     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4579
4580     // Some sanity checking...
4581     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4582     {
4583         fprintf(stderr,
4584                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4585                 __FILE__, __LINE__, ic->filename, ic->lineno);
4586         emitcode(";", ">>> unexpected DPTR here.");
4587     }
4588
4589     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4590     {
4591         fprintf(stderr,
4592                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4593                 __FILE__, __LINE__, ic->filename, ic->lineno);
4594         emitcode(";", ">>> unexpected DPTR2 here.");
4595     }
4596
4597     return TRUE;
4598 }
4599
4600 // Macro to aopOp all three operands of an ic. If this cannot be done,
4601 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4602 // will be set TRUE. The caller must then handle the case specially, noting
4603 // that the IC_RESULT operand is not aopOp'd.
4604 //
4605 #define AOP_OP_3_NOFATAL(ic, rc) \
4606             do { rc = !aopOp3(ic); } while (0)
4607
4608 // aopOp the left & right operands of an ic.
4609 #define AOP_OP_2(ic) \
4610     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4611     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4612
4613 // convienience macro.
4614 #define AOP_SET_LOCALS(ic) \
4615     left = IC_LEFT(ic); \
4616     right = IC_RIGHT(ic); \
4617     result = IC_RESULT(ic);
4618
4619
4620 // Given an integer value of pushedSize bytes on the stack,
4621 // adjust it to be resultSize bytes, either by discarding
4622 // the most significant bytes or by zero-padding.
4623 //
4624 // On exit from this macro, pushedSize will have been adjusted to
4625 // equal resultSize, and ACC may be trashed.
4626 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4627       /* If the pushed data is bigger than the result,          \
4628        * simply discard unused bytes. Icky, but works.          \
4629        */                                                       \
4630       while (pushedSize > resultSize)                           \
4631       {                                                         \
4632           D (emitcode (";", "discarding unused result byte.")); \
4633           emitcode ("pop", "acc");                              \
4634           pushedSize--;                                         \
4635       }                                                         \
4636       if (pushedSize < resultSize)                              \
4637       {                                                         \
4638           emitcode ("clr", "a");                                \
4639           /* Conversly, we haven't pushed enough here.          \
4640            * just zero-pad, and all is well.                    \
4641            */                                                   \
4642           while (pushedSize < resultSize)                       \
4643           {                                                     \
4644               emitcode("push", "acc");                          \
4645               pushedSize++;                                     \
4646           }                                                     \
4647       }                                                         \
4648       assert(pushedSize == resultSize);
4649
4650 /*-----------------------------------------------------------------*/
4651 /* genPlus - generates code for addition                           */
4652 /*-----------------------------------------------------------------*/
4653 static void
4654 genPlus (iCode * ic)
4655 {
4656   int size, offset = 0;
4657   bool pushResult;
4658   int rSize;
4659   bool swappedLR = FALSE;
4660
4661   D (emitcode (";", "genPlus"));
4662
4663   /* special cases :- */
4664   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4665       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4666       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4667       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4668       if (size <= 9) {
4669           while (size--) emitcode ("inc","dptr");
4670       } else {
4671           emitcode ("mov", "a,dpl");
4672           emitcode ("add", "a,#!constbyte", size & 0xff);
4673           emitcode ("mov", "dpl,a");
4674           emitcode ("mov", "a,dph");
4675           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4676           emitcode ("mov", "dph,a");
4677           emitcode ("mov", "a,dpx");
4678           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4679           emitcode ("mov", "dpx,a");
4680       }
4681       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4682       return ;
4683   }
4684   if ( IS_SYMOP (IC_LEFT (ic)) &&
4685        OP_SYMBOL (IC_LEFT (ic))->remat &&
4686        isOperandInFarSpace (IC_RIGHT (ic))) {
4687       operand *op = IC_RIGHT(ic);
4688       IC_RIGHT(ic) = IC_LEFT(ic);
4689       IC_LEFT(ic) = op;
4690   }
4691
4692   AOP_OP_3_NOFATAL (ic, pushResult);
4693
4694   if (pushResult)
4695     {
4696       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4697     }
4698
4699   if (!pushResult)
4700     {
4701       /* if literal, literal on the right or
4702          if left requires ACC or right is already
4703          in ACC */
4704       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4705           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4706           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4707         {
4708           operand *t = IC_RIGHT (ic);
4709           IC_RIGHT (ic) = IC_LEFT (ic);
4710           IC_LEFT (ic) = t;
4711           swappedLR = TRUE;
4712           D (emitcode (";", "Swapped plus args."));
4713         }
4714
4715       /* if both left & right are in bit
4716          space */
4717       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4718           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4719         {
4720           genPlusBits (ic);
4721           goto release;
4722         }
4723
4724       /* if left in bit space & right literal */
4725       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4726           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4727         {
4728           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4729           /* if result in bit space */
4730           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4731             {
4732               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4733                 emitcode ("cpl", "c");
4734               outBitC (IC_RESULT (ic));
4735             }
4736           else
4737             {
4738               size = getDataSize (IC_RESULT (ic));
4739               _startLazyDPSEvaluation ();
4740               while (size--)
4741                 {
4742                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4743                   emitcode ("addc", "a,%s", zero);
4744                   aopPut (IC_RESULT (ic), "a", offset++);
4745                 }
4746               _endLazyDPSEvaluation ();
4747             }
4748           goto release;
4749         }
4750
4751       /* if I can do an increment instead
4752          of add then GOOD for ME */
4753       if (genPlusIncr (ic) == TRUE)
4754         {
4755           D (emitcode (";", "did genPlusIncr"));
4756           goto release;
4757         }
4758
4759     }
4760   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4761
4762   _startLazyDPSEvaluation ();
4763   while (size--)
4764     {
4765       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4766         {
4767           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4768           if (offset == 0)
4769             emitcode ("add", "a,%s",
4770                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4771           else
4772             emitcode ("addc", "a,%s",
4773                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4774         }
4775       else
4776         {
4777           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4778           {
4779               /* right is going to use ACC or we would have taken the
4780                * above branch.
4781                */
4782               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4783               TR_AP("#3");
4784               D(emitcode(";", "+ AOP_ACC special case."););
4785               emitcode("xch", "a, %s", DP2_RESULT_REG);
4786           }
4787           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4788           if (offset == 0)
4789           {
4790             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4791             {
4792                 TR_AP("#4");
4793                 emitcode("add", "a, %s", DP2_RESULT_REG);
4794             }
4795             else
4796             {
4797                 emitcode ("add", "a,%s",
4798                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4799                                   DP2_RESULT_REG));
4800             }
4801           }
4802           else
4803           {
4804             emitcode ("addc", "a,%s",
4805                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4806                           DP2_RESULT_REG));
4807           }
4808         }
4809       if (!pushResult)
4810         {
4811           aopPut (IC_RESULT (ic), "a", offset);
4812         }
4813       else
4814         {
4815           emitcode ("push", "acc");
4816         }
4817       offset++;
4818     }
4819   _endLazyDPSEvaluation ();
4820
4821   if (pushResult)
4822     {
4823       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4824
4825       size = getDataSize (IC_LEFT (ic));
4826       rSize = getDataSize (IC_RESULT (ic));
4827
4828       ADJUST_PUSHED_RESULT(size, rSize);
4829
4830       _startLazyDPSEvaluation ();
4831       while (size--)
4832         {
4833           emitcode ("pop", "acc");
4834           aopPut (IC_RESULT (ic), "a", size);
4835         }
4836       _endLazyDPSEvaluation ();
4837     }
4838
4839   adjustArithmeticResult (ic);
4840
4841 release:
4842   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4843   if (!swappedLR)
4844     {
4845       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4846       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4847     }
4848   else
4849     {
4850       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4851       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4852     }
4853 }
4854
4855 /*-----------------------------------------------------------------*/
4856 /* genMinusDec :- does subtraction with decrement if possible      */
4857 /*-----------------------------------------------------------------*/
4858 static bool
4859 genMinusDec (iCode * ic)
4860 {
4861   unsigned int icount;
4862   unsigned int size = getDataSize (IC_RESULT (ic));
4863
4864   /* will try to generate an increment */
4865   /* if the right side is not a literal
4866      we cannot */
4867   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4868     return FALSE;
4869
4870   /* if the literal value of the right hand side
4871      is greater than 4 then it is not worth it */
4872   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4873     return FALSE;
4874
4875   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4876       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4877       while (icount--) {
4878           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4879       }
4880       return TRUE;
4881   }
4882   /* if decrement 16 bits in register */
4883   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4884       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4885       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4886       (size > 1) &&
4887       (icount == 1))
4888     {
4889       symbol *tlbl;
4890       int    emitTlbl;
4891       int    labelRange;
4892       char   *l;
4893
4894       /* If the next instruction is a goto and the goto target
4895          * is <= 5 instructions previous to this, we can generate
4896          * jumps straight to that target.
4897        */
4898       if (ic->next && ic->next->op == GOTO
4899           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4900           && labelRange <= 5)
4901         {
4902           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4903           tlbl = IC_LABEL (ic->next);
4904           emitTlbl = 0;
4905         }
4906       else
4907         {
4908           tlbl = newiTempLabel (NULL);
4909           emitTlbl = 1;
4910         }
4911
4912       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4913       emitcode ("dec", "%s", l);
4914
4915       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4916           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4917           IS_AOP_PREG (IC_RESULT (ic)))
4918       {
4919           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4920       }
4921       else
4922       {
4923           emitcode ("mov", "a,#!constbyte",0xff);
4924           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4925       }
4926       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4927       emitcode ("dec", "%s", l);
4928       if (size > 2)
4929         {
4930             if (!strcmp(l, "acc"))
4931             {
4932                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4933             }
4934             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4935                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4936                      IS_AOP_PREG (IC_RESULT (ic)))
4937             {
4938                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4939             }
4940             else
4941             {
4942                 emitcode ("mov", "a,#!constbyte",0xff);
4943                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4944             }
4945             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4946             emitcode ("dec", "%s", l);
4947         }
4948       if (size > 3)
4949         {
4950             if (!strcmp(l, "acc"))
4951             {
4952                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4953             }
4954             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4955                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4956                      IS_AOP_PREG (IC_RESULT (ic)))
4957             {
4958                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4959             }
4960             else
4961             {
4962                 emitcode ("mov", "a,#!constbyte",0xff);
4963                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4964             }
4965             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4966             emitcode ("dec", "%s", l);
4967         }
4968       if (emitTlbl)
4969         {
4970           emitLabel (tlbl);
4971         }
4972       return TRUE;
4973     }
4974
4975   /* if the sizes are greater than 1 then we cannot */
4976   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4977       AOP_SIZE (IC_LEFT (ic)) > 1)
4978     return FALSE;
4979
4980   /* we can if the aops of the left & result match or
4981      if they are in registers and the registers are the
4982      same */
4983   if (
4984        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4985        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4986        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4987     {
4988       char *l;
4989
4990       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4991         {
4992           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4993           l = "a";
4994         }
4995       else
4996         {
4997           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
4998         }
4999
5000       _startLazyDPSEvaluation ();
5001       while (icount--)
5002         {
5003           emitcode ("dec", "%s", l);
5004         }
5005       _endLazyDPSEvaluation ();
5006
5007       if (AOP_NEEDSACC (IC_RESULT (ic)))
5008         aopPut (IC_RESULT (ic), "a", 0);
5009
5010       return TRUE;
5011     }
5012
5013   return FALSE;
5014 }
5015
5016 /*-----------------------------------------------------------------*/
5017 /* addSign - complete with sign                                    */
5018 /*-----------------------------------------------------------------*/
5019 static void
5020 addSign (operand * result, int offset, int sign)
5021 {
5022   int size = (getDataSize (result) - offset);
5023   if (size > 0)
5024     {
5025       _startLazyDPSEvaluation();
5026       if (sign)
5027         {
5028           emitcode ("rlc", "a");
5029           emitcode ("subb", "a,acc");
5030           while (size--)
5031             {
5032               aopPut (result, "a", offset++);
5033             }
5034         }
5035       else
5036       {
5037         while (size--)
5038         {
5039           aopPut (result, zero, offset++);
5040         }
5041       }
5042       _endLazyDPSEvaluation();
5043     }
5044 }
5045
5046 /*-----------------------------------------------------------------*/
5047 /* genMinusBits - generates code for subtraction  of two bits      */
5048 /*-----------------------------------------------------------------*/
5049 static void
5050 genMinusBits (iCode * ic)
5051 {
5052   symbol *lbl = newiTempLabel (NULL);
5053
5054   D (emitcode (";", "genMinusBits"));
5055
5056   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5057     {
5058       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5059       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5060       emitcode ("cpl", "c");
5061       emitLabel (lbl);
5062       outBitC (IC_RESULT (ic));
5063     }
5064   else
5065     {
5066       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5067       emitcode ("subb", "a,acc");
5068       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5069       emitcode ("inc", "a");
5070       emitLabel (lbl);
5071       aopPut (IC_RESULT (ic), "a", 0);
5072       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5073     }
5074 }
5075
5076 /*-----------------------------------------------------------------*/
5077 /* genMinus - generates code for subtraction                       */
5078 /*-----------------------------------------------------------------*/
5079 static void
5080 genMinus (iCode * ic)
5081 {
5082     int size, offset = 0;
5083     int rSize;
5084     long lit = 0L;
5085     bool pushResult;
5086
5087     D (emitcode (";", "genMinus"));
5088
5089     AOP_OP_3_NOFATAL(ic, pushResult);
5090
5091     if (!pushResult)
5092     {
5093       /* special cases :- */
5094       /* if both left & right are in bit space */
5095       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5096           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5097         {
5098           genMinusBits (ic);
5099           goto release;
5100         }
5101
5102       /* if I can do an decrement instead
5103          of subtract then GOOD for ME */
5104       if (genMinusDec (ic) == TRUE)
5105         goto release;
5106
5107     }
5108
5109   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5110
5111   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5112     {
5113       CLRC;
5114     }
5115   else
5116     {
5117       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5118       lit = -lit;
5119     }
5120
5121
5122   /* if literal, add a,#-lit, else normal subb */
5123   _startLazyDPSEvaluation ();
5124   while (size--) {
5125       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5126           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5127               emitcode ("mov","b,%s",
5128                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5129               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5130               emitcode ("subb","a,b");
5131           } else {
5132               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5133               emitcode ("subb", "a,%s",
5134                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5135                                 DP2_RESULT_REG));
5136           }
5137       } else {
5138           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5139           /* first add without previous c */
5140           if (!offset) {
5141               if (!size && lit==-1) {
5142                   emitcode ("dec", "a");
5143               } else {
5144                   emitcode ("add", "a,#!constbyte",
5145                             (unsigned int) (lit & 0x0FFL));
5146               }
5147           } else {
5148               emitcode ("addc", "a,#!constbyte",
5149                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5150           }
5151       }
5152
5153       if (pushResult) {
5154           emitcode ("push", "acc");
5155       } else {
5156           aopPut (IC_RESULT (ic), "a", offset);
5157       }
5158       offset++;
5159   }
5160   _endLazyDPSEvaluation ();
5161
5162   if (pushResult)
5163     {
5164       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5165
5166       size = getDataSize (IC_LEFT (ic));
5167       rSize = getDataSize (IC_RESULT (ic));
5168
5169       ADJUST_PUSHED_RESULT(size, rSize);
5170
5171       _startLazyDPSEvaluation ();
5172       while (size--)
5173         {
5174           emitcode ("pop", "acc");
5175           aopPut (IC_RESULT (ic), "a", size);
5176         }
5177       _endLazyDPSEvaluation ();
5178     }
5179
5180   adjustArithmeticResult (ic);
5181
5182 release:
5183   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5184   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5185   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5186 }
5187
5188
5189 /*-----------------------------------------------------------------*/
5190 /* genMultbits :- multiplication of bits                           */
5191 /*-----------------------------------------------------------------*/
5192 static void
5193 genMultbits (operand * left,
5194              operand * right,
5195              operand * result,
5196              iCode   * ic)
5197 {
5198   D (emitcode (";", "genMultbits"));
5199
5200   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5201   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5202   aopOp(result, ic, TRUE, FALSE);
5203   outBitC (result);
5204 }
5205
5206 /*-----------------------------------------------------------------*/
5207 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5208 /*-----------------------------------------------------------------*/
5209 static void
5210 genMultOneByte (operand * left,
5211                 operand * right,
5212                 operand * result,
5213                 iCode   * ic)
5214 {
5215   symbol *lbl;
5216   int size;
5217   bool runtimeSign, compiletimeSign;
5218   bool lUnsigned, rUnsigned, pushedB;
5219
5220   /* (if two literals: the value is computed before) */
5221   /* if one literal, literal on the right */
5222   if (AOP_TYPE (left) == AOP_LIT)
5223     {
5224       operand *t = right;
5225       right = left;
5226       left = t;
5227       /* emitcode (";", "swapped left and right"); */
5228     }
5229   /* if no literal, unsigned on the right: shorter code */
5230   if (   AOP_TYPE (right) != AOP_LIT
5231       && SPEC_USIGN (getSpec (operandType (left))))
5232     {
5233       operand *t = right;
5234       right = left;
5235       left = t;
5236     }
5237
5238   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5239   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5240
5241   pushedB = pushB ();
5242
5243   if ((lUnsigned && rUnsigned)
5244 /* sorry, I don't know how to get size
5245    without calling aopOp (result,...);
5246    see Feature Request  */
5247       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5248                    no need to take care about the signedness! */
5249     {
5250       /* just an unsigned 8 * 8 = 8 multiply
5251          or 8u * 8u = 16u */
5252       /* emitcode (";","unsigned"); */
5253       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5254       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5255       emitcode ("mul", "ab");
5256
5257       _G.accInUse++;
5258       aopOp (result, ic, TRUE, FALSE);
5259       size = AOP_SIZE (result);
5260
5261       if (size < 1 || size > 2)
5262         {
5263           /* this should never happen */
5264           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5265                    size, __FILE__, lineno);
5266           exit (1);
5267         }
5268
5269       aopPut (result, "a", 0);
5270       _G.accInUse--;
5271       if (size == 2)
5272         aopPut (result, "b", 1);
5273
5274       popB (pushedB);
5275       return;
5276     }
5277
5278   /* we have to do a signed multiply */
5279   /* emitcode (";", "signed"); */
5280
5281   /* now sign adjust for both left & right */
5282
5283   /* let's see what's needed: */
5284   /* apply negative sign during runtime */
5285   runtimeSign = FALSE;
5286   /* negative sign from literals */
5287   compiletimeSign = FALSE;
5288
5289   if (!lUnsigned)
5290     {
5291       if (AOP_TYPE(left) == AOP_LIT)
5292         {
5293           /* signed literal */
5294           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5295           if (val < 0)
5296             compiletimeSign = TRUE;
5297         }
5298       else
5299         /* signed but not literal */
5300         runtimeSign = TRUE;
5301     }
5302
5303   if (!rUnsigned)
5304     {
5305       if (AOP_TYPE(right) == AOP_LIT)
5306         {
5307           /* signed literal */
5308           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5309           if (val < 0)
5310             compiletimeSign ^= TRUE;
5311         }
5312       else
5313         /* signed but not literal */
5314         runtimeSign = TRUE;
5315     }
5316
5317   /* initialize F0, which stores the runtime sign */
5318   if (runtimeSign)
5319     {
5320       if (compiletimeSign)
5321         emitcode ("setb", "F0"); /* set sign flag */
5322       else
5323         emitcode ("clr", "F0"); /* reset sign flag */
5324     }
5325
5326   /* save the signs of the operands */
5327   if (AOP_TYPE(right) == AOP_LIT)
5328     {
5329       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5330
5331       if (!rUnsigned && val < 0)
5332         emitcode ("mov", "b,#!constbyte", -val);
5333       else
5334         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5335     }
5336   else /* ! literal */
5337     {
5338       if (rUnsigned)  /* emitcode (";", "signed"); */
5339         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5340       else
5341         {
5342           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5343           lbl = newiTempLabel (NULL);
5344           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5345           emitcode ("cpl", "F0"); /* complement sign flag */
5346           emitcode ("cpl", "a");  /* 2's complement */
5347           emitcode ("inc", "a");
5348           emitLabel (lbl);
5349           emitcode ("mov", "b,a");
5350         }
5351     }
5352
5353   if (AOP_TYPE(left) == AOP_LIT)
5354     {
5355       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5356
5357       if (!lUnsigned && val < 0)
5358         emitcode ("mov", "a,#!constbyte", -val);
5359       else
5360         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5361     }
5362   else /* ! literal */
5363     {
5364       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5365
5366       if (!lUnsigned)  /* emitcode (";", "signed"); */
5367         {
5368           lbl = newiTempLabel (NULL);
5369           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5370           emitcode ("cpl", "F0"); /* complement sign flag */
5371           emitcode ("cpl", "a");  /* 2's complement */
5372           emitcode ("inc", "a");
5373           emitLabel (lbl);
5374         }
5375     }
5376
5377   /* now the multiplication */
5378   emitcode ("mul", "ab");
5379   _G.accInUse++;
5380   aopOp(result, ic, TRUE, FALSE);
5381   size = AOP_SIZE (result);
5382
5383   if (size < 1 || size > 2)
5384     {
5385       /* this should never happen */
5386       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5387                size, __FILE__, lineno);
5388       exit (1);
5389     }
5390
5391   if (runtimeSign || compiletimeSign)
5392     {
5393       lbl = newiTempLabel (NULL);
5394       if (runtimeSign)
5395         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5396       emitcode ("cpl", "a"); /* lsb 2's complement */
5397       if (size != 2)
5398         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5399       else
5400         {
5401           emitcode ("add", "a,#1"); /* this sets carry flag */
5402           emitcode ("xch", "a,b");
5403           emitcode ("cpl", "a"); /* msb 2's complement */
5404           emitcode ("addc", "a,#0");
5405           emitcode ("xch", "a,b");
5406         }
5407       emitLabel (lbl);
5408     }
5409   aopPut (result, "a", 0);
5410   _G.accInUse--;
5411   if (size == 2)
5412     aopPut (result, "b", 1);
5413
5414   popB (pushedB);
5415 }
5416
5417 /*-----------------------------------------------------------------*/
5418 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5419 /*-----------------------------------------------------------------*/
5420 static void genMultTwoByte (operand *left, operand *right,
5421                             operand *result, iCode *ic)
5422 {
5423         sym_link *retype = getSpec(operandType(right));
5424         sym_link *letype = getSpec(operandType(left));
5425         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5426         symbol *lbl;
5427
5428         if (AOP_TYPE (left) == AOP_LIT) {
5429                 operand *t = right;
5430                 right = left;
5431                 left = t;
5432         }
5433         /* save EA bit in F1 */
5434         lbl = newiTempLabel(NULL);
5435         emitcode ("setb","F1");
5436         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5437         emitcode ("clr","F1");
5438         emitLabel (lbl);
5439
5440         /* load up MB with right */
5441         if (!umult) {
5442                 emitcode("clr","F0");
5443                 if (AOP_TYPE(right) == AOP_LIT) {
5444                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5445                         if (val < 0) {
5446                                 emitcode("setb","F0");
5447                                 val = -val;
5448                         }
5449                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5450                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5451                 } else {
5452                         lbl = newiTempLabel(NULL);
5453                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5454                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5455                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5456                         emitcode ("xch", "a,b");
5457                         emitcode ("cpl","a");
5458                         emitcode ("add", "a,#1");
5459                         emitcode ("xch", "a,b");
5460                         emitcode ("cpl", "a"); // msb
5461                         emitcode ("addc", "a,#0");
5462                         emitcode ("setb","F0");
5463                         emitLabel (lbl);
5464                         emitcode ("mov","mb,b");
5465                         emitcode ("mov","mb,a");
5466                 }
5467         } else {
5468                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5469                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5470         }
5471         /* load up MA with left */
5472         if (!umult) {
5473                 lbl = newiTempLabel(NULL);
5474                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5475                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5476                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5477                 emitcode ("xch", "a,b");
5478                 emitcode ("cpl","a");
5479                 emitcode ("add", "a,#1");
5480                 emitcode ("xch", "a,b");
5481                 emitcode ("cpl", "a"); // msb
5482                 emitcode ("addc","a,#0");
5483                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5484                 emitcode ("setb","F0");
5485                 emitLabel (lbl);
5486                 emitcode ("mov","ma,b");
5487                 emitcode ("mov","ma,a");
5488         } else {
5489                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5490                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5491         }
5492         /* wait for multiplication to finish */
5493         lbl = newiTempLabel(NULL);
5494         emitLabel (lbl);
5495         emitcode("mov","a,mcnt1");
5496         emitcode("anl","a,#!constbyte",0x80);
5497         emitcode("jnz","!tlabel",lbl->key+100);
5498
5499         freeAsmop (left, NULL, ic, TRUE);
5500         freeAsmop (right, NULL, ic,TRUE);
5501         aopOp(result, ic, TRUE, FALSE);
5502
5503         /* if unsigned then simple */
5504         if (umult) {
5505                 emitcode ("mov","a,ma");
5506                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5507                 emitcode ("mov","a,ma");
5508                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5509                 aopPut(result,"ma",1);
5510                 aopPut(result,"ma",0);
5511         } else {
5512                 emitcode("push","ma");
5513                 emitcode("push","ma");
5514                 emitcode("push","ma");
5515                 MOVA("ma");
5516                 /* negate result if needed */
5517                 lbl = newiTempLabel(NULL);
5518                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5519                 emitcode("cpl","a");
5520                 emitcode("add","a,#1");
5521                 emitLabel (lbl);
5522                 if (AOP_TYPE(result) == AOP_ACC)
5523                 {
5524                     D (emitcode(";", "ACC special case."));
5525                     /* We know result is the only live aop, and
5526                      * it's obviously not a DPTR2, so AP is available.
5527                      */
5528                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5529                 }
5530                 else
5531                 {
5532                     aopPut(result,"a",0);
5533                 }
5534
5535                 emitcode("pop","acc");
5536                 lbl = newiTempLabel(NULL);
5537                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5538                 emitcode("cpl","a");
5539                 emitcode("addc","a,#0");
5540                 emitLabel (lbl);
5541                 aopPut(result,"a",1);
5542                 emitcode("pop","acc");
5543                 if (AOP_SIZE(result) >= 3) {
5544                         lbl = newiTempLabel(NULL);
5545                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5546                         emitcode("cpl","a");
5547                         emitcode("addc","a,#0");
5548                         emitLabel (lbl);
5549                         aopPut(result,"a",2);
5550                 }
5551                 emitcode("pop","acc");
5552                 if (AOP_SIZE(result) >= 4) {
5553                         lbl = newiTempLabel(NULL);
5554                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5555                         emitcode("cpl","a");
5556                         emitcode("addc","a,#0");
5557                         emitLabel (lbl);
5558                         aopPut(result,"a",3);
5559                 }
5560                 if (AOP_TYPE(result) == AOP_ACC)
5561                 {
5562                     /* We stashed the result away above. */
5563                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5564                 }
5565
5566         }
5567         freeAsmop (result, NULL, ic, TRUE);
5568
5569         /* restore EA bit in F1 */
5570         lbl = newiTempLabel(NULL);
5571         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5572         emitcode ("setb","EA");
5573         emitLabel (lbl);
5574         return ;
5575 }
5576
5577 /*-----------------------------------------------------------------*/
5578 /* genMult - generates code for multiplication                     */
5579 /*-----------------------------------------------------------------*/
5580 static void
5581 genMult (iCode * ic)
5582 {
5583   operand *left = IC_LEFT (ic);
5584   operand *right = IC_RIGHT (ic);
5585   operand *result = IC_RESULT (ic);
5586
5587   D (emitcode (";", "genMult"));
5588
5589   /* assign the asmops */
5590   AOP_OP_2 (ic);
5591
5592   /* special cases first */
5593   /* both are bits */
5594   if (AOP_TYPE (left) == AOP_CRY &&
5595       AOP_TYPE (right) == AOP_CRY)
5596     {
5597       genMultbits (left, right, result, ic);
5598       goto release;
5599     }
5600
5601   /* if both are of size == 1 */
5602   if (AOP_SIZE (left) == 1 &&
5603       AOP_SIZE (right) == 1)
5604     {
5605       genMultOneByte (left, right, result, ic);
5606       goto release;
5607     }
5608
5609   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5610           /* use the ds390 ARITHMETIC accel UNIT */
5611           genMultTwoByte (left, right, result, ic);
5612           return ;
5613   }
5614   /* should have been converted to function call */
5615   assert (0);
5616
5617 release:
5618   freeAsmop (result, NULL, ic, TRUE);
5619   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5620   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5621 }
5622
5623 /*-----------------------------------------------------------------*/
5624 /* genDivbits :- division of bits                                  */
5625 /*-----------------------------------------------------------------*/
5626 static void
5627 genDivbits (operand * left,
5628             operand * right,
5629             operand * result,
5630             iCode   * ic)
5631 {
5632   char *l;
5633   bool pushedB;
5634
5635   D(emitcode (";     genDivbits",""));
5636
5637   pushedB = pushB ();
5638
5639   /* the result must be bit */
5640   LOAD_AB_FOR_DIV (left, right, l);
5641   emitcode ("div", "ab");
5642   emitcode ("rrc", "a");
5643   aopOp(result, ic, TRUE, FALSE);
5644
5645   popB (pushedB);
5646
5647   aopPut (result, "c", 0);
5648 }
5649
5650 /*-----------------------------------------------------------------*/
5651 /* genDivOneByte : 8 bit division                                  */
5652 /*-----------------------------------------------------------------*/
5653 static void
5654 genDivOneByte (operand * left,
5655                operand * right,
5656                operand * result,
5657                iCode   * ic)
5658 {
5659   bool lUnsigned, rUnsigned, pushedB;
5660   bool runtimeSign, compiletimeSign;
5661   char *l;
5662   symbol *lbl;
5663   int size, offset;
5664
5665   D(emitcode (";     genDivOneByte",""));
5666
5667   offset = 1;
5668   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5669   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5670
5671   pushedB = pushB ();
5672
5673   /* signed or unsigned */
5674   if (lUnsigned && rUnsigned)
5675     {
5676       /* unsigned is easy */
5677       LOAD_AB_FOR_DIV (left, right, l);
5678       emitcode ("div", "ab");
5679
5680       _G.accInUse++;
5681       aopOp (result, ic, TRUE, FALSE);
5682       aopPut (result, "a", 0);
5683       _G.accInUse--;
5684
5685       size = AOP_SIZE (result) - 1;
5686
5687       while (size--)
5688         aopPut (result, zero, offset++);
5689
5690       popB (pushedB);
5691       return;
5692     }
5693
5694   /* signed is a little bit more difficult */
5695
5696   /* now sign adjust for both left & right */
5697
5698   /* let's see what's needed: */
5699   /* apply negative sign during runtime */
5700   runtimeSign = FALSE;
5701   /* negative sign from literals */
5702   compiletimeSign = FALSE;
5703
5704   if (!lUnsigned)
5705     {
5706       if (AOP_TYPE(left) == AOP_LIT)
5707         {
5708           /* signed literal */
5709           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5710           if (val < 0)
5711             compiletimeSign = TRUE;
5712         }
5713       else
5714         /* signed but not literal */
5715         runtimeSign = TRUE;
5716     }
5717
5718   if (!rUnsigned)
5719     {
5720       if (AOP_TYPE(right) == AOP_LIT)
5721         {
5722           /* signed literal */
5723           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5724           if (val < 0)
5725             compiletimeSign ^= TRUE;
5726         }
5727       else
5728         /* signed but not literal */
5729         runtimeSign = TRUE;
5730     }
5731
5732   /* initialize F0, which stores the runtime sign */
5733   if (runtimeSign)
5734     {
5735       if (compiletimeSign)
5736         emitcode ("setb", "F0"); /* set sign flag */
5737       else
5738         emitcode ("clr", "F0"); /* reset sign flag */
5739     }
5740
5741   /* save the signs of the operands */
5742   if (AOP_TYPE(right) == AOP_LIT)
5743     {
5744       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5745
5746       if (!rUnsigned && val < 0)
5747         emitcode ("mov", "b,#0x%02x", -val);
5748       else
5749         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5750     }
5751   else /* ! literal */
5752     {
5753       if (rUnsigned)
5754         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5755       else
5756         {
5757           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5758           lbl = newiTempLabel (NULL);
5759           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5760           emitcode ("cpl", "F0"); /* complement sign flag */
5761           emitcode ("cpl", "a");  /* 2's complement */
5762           emitcode ("inc", "a");
5763           emitLabel (lbl);
5764           emitcode ("mov", "b,a");
5765         }
5766     }
5767
5768   if (AOP_TYPE(left) == AOP_LIT)
5769     {
5770       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5771
5772       if (!lUnsigned && val < 0)
5773         emitcode ("mov", "a,#0x%02x", -val);
5774       else
5775         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5776     }
5777   else /* ! literal */
5778     {
5779       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5780
5781       if (!lUnsigned)
5782         {
5783           lbl = newiTempLabel (NULL);
5784           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5785           emitcode ("cpl", "F0"); /* complement sign flag */
5786           emitcode ("cpl", "a");  /* 2's complement */
5787           emitcode ("inc", "a");
5788           emitLabel (lbl);
5789         }
5790     }
5791
5792   /* now the division */
5793   emitcode ("nop", "; workaround for DS80C390 div bug.");
5794   emitcode ("div", "ab");
5795
5796   if (runtimeSign || compiletimeSign)
5797     {
5798       lbl = newiTempLabel (NULL);
5799       if (runtimeSign)
5800         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5801       emitcode ("cpl", "a"); /* lsb 2's complement */
5802       emitcode ("inc", "a");
5803       emitLabel (lbl);
5804
5805       _G.accInUse++;
5806       aopOp (result, ic, TRUE, FALSE);
5807       size = AOP_SIZE (result) - 1;
5808
5809       if (size > 0)
5810         {
5811           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5812              then the result will be in b, a */
5813           emitcode ("mov", "b,a"); /* 1 */
5814           /* msb is 0x00 or 0xff depending on the sign */
5815           if (runtimeSign)
5816             {
5817               emitcode ("mov",  "c,F0");
5818               emitcode ("subb", "a,acc");
5819               emitcode ("xch",  "a,b"); /* 2 */
5820               while (size--)
5821                 aopPut (result, "b", offset++); /* write msb's */
5822             }
5823           else /* compiletimeSign */
5824             while (size--)
5825               aopPut (result, "#0xff", offset++); /* write msb's */
5826         }
5827       aopPut (result, "a", 0); /* 3: write lsb */
5828     }
5829   else
5830     {
5831       _G.accInUse++;
5832       aopOp(result, ic, TRUE, FALSE);
5833       size = AOP_SIZE (result) - 1;
5834
5835       aopPut (result, "a", 0);
5836       while (size--)
5837         aopPut (result, zero, offset++);
5838     }
5839   _G.accInUse--;
5840   popB (pushedB);
5841 }
5842
5843 /*-----------------------------------------------------------------*/
5844 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5845 /*-----------------------------------------------------------------*/
5846 static void genDivTwoByte (operand *left, operand *right,
5847                             operand *result, iCode *ic)
5848 {
5849         sym_link *retype = getSpec(operandType(right));
5850         sym_link *letype = getSpec(operandType(left));
5851         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5852         symbol *lbl;
5853
5854         /* save EA bit in F1 */
5855         lbl = newiTempLabel(NULL);
5856         emitcode ("setb","F1");
5857         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5858         emitcode ("clr","F1");
5859         emitLabel (lbl);
5860
5861         /* load up MA with left */
5862         if (!umult) {
5863                 emitcode("clr","F0");
5864                 lbl = newiTempLabel(NULL);
5865                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5866                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5867                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5868                 emitcode ("xch", "a,b");
5869                 emitcode ("cpl","a");
5870                 emitcode ("add", "a,#1");
5871                 emitcode ("xch", "a,b");
5872                 emitcode ("cpl", "a"); // msb
5873                 emitcode ("addc","a,#0");
5874                 emitcode ("setb","F0");
5875                 emitLabel (lbl);
5876                 emitcode ("mov","ma,b");
5877                 emitcode ("mov","ma,a");
5878         } else {
5879                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5880                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5881         }
5882
5883         /* load up MB with right */
5884         if (!umult) {
5885                 if (AOP_TYPE(right) == AOP_LIT) {
5886                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5887                         if (val < 0) {
5888                                 lbl = newiTempLabel(NULL);
5889                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5890                                 emitcode("setb","F0");
5891                                 emitLabel (lbl);
5892                                 val = -val;
5893                         }
5894                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5895                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5896                 } else {
5897                         lbl = newiTempLabel(NULL);
5898                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5899                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5900                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5901                         emitcode ("xch", "a,b");
5902                         emitcode ("cpl","a");
5903                         emitcode ("add", "a,#1");
5904                         emitcode ("xch", "a,b");
5905                         emitcode ("cpl", "a"); // msb
5906                         emitcode ("addc", "a,#0");
5907                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5908                         emitcode ("setb","F0");
5909                         emitLabel (lbl);
5910                         emitcode ("mov","mb,b");
5911                         emitcode ("mov","mb,a");
5912                 }
5913         } else {
5914                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5915                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5916         }
5917
5918         /* wait for multiplication to finish */
5919         lbl = newiTempLabel(NULL);
5920         emitLabel (lbl);
5921         emitcode("mov","a,mcnt1");
5922         emitcode("anl","a,#!constbyte",0x80);
5923         emitcode("jnz","!tlabel",lbl->key+100);
5924
5925         freeAsmop (left, NULL, ic, TRUE);
5926         freeAsmop (right, NULL, ic,TRUE);
5927         aopOp(result, ic, TRUE, FALSE);
5928
5929         /* if unsigned then simple */
5930         if (umult) {
5931                 aopPut(result,"ma",1);
5932                 aopPut(result,"ma",0);
5933         } else {
5934                 emitcode("push","ma");
5935                 MOVA("ma");
5936                 /* negate result if needed */
5937                 lbl = newiTempLabel(NULL);
5938                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5939                 emitcode("cpl","a");
5940                 emitcode("add","a,#1");
5941                 emitLabel (lbl);
5942                 aopPut(result,"a",0);
5943                 emitcode("pop","acc");
5944                 lbl = newiTempLabel(NULL);
5945                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5946                 emitcode("cpl","a");
5947                 emitcode("addc","a,#0");
5948                 emitLabel (lbl);
5949                 aopPut(result,"a",1);
5950         }
5951         freeAsmop (result, NULL, ic, TRUE);
5952         /* restore EA bit in F1 */
5953         lbl = newiTempLabel(NULL);
5954         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5955         emitcode ("setb","EA");
5956         emitLabel (lbl);
5957         return ;
5958 }
5959
5960 /*-----------------------------------------------------------------*/
5961 /* genDiv - generates code for division                            */
5962 /*-----------------------------------------------------------------*/
5963 static void
5964 genDiv (iCode * ic)
5965 {
5966   operand *left = IC_LEFT (ic);
5967   operand *right = IC_RIGHT (ic);
5968   operand *result = IC_RESULT (ic);
5969
5970   D (emitcode (";", "genDiv"));
5971
5972   /* assign the amsops */
5973   AOP_OP_2 (ic);
5974
5975   /* special cases first */
5976   /* both are bits */
5977   if (AOP_TYPE (left) == AOP_CRY &&
5978       AOP_TYPE (right) == AOP_CRY)
5979     {
5980       genDivbits (left, right, result, ic);
5981       goto release;
5982     }
5983
5984   /* if both are of size == 1 */
5985   if (AOP_SIZE (left) == 1 &&
5986       AOP_SIZE (right) == 1)
5987     {
5988       genDivOneByte (left, right, result, ic);
5989       goto release;
5990     }
5991
5992   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5993           /* use the ds390 ARITHMETIC accel UNIT */
5994           genDivTwoByte (left, right, result, ic);
5995           return ;
5996   }
5997   /* should have been converted to function call */
5998   assert (0);
5999 release:
6000   freeAsmop (result, NULL, ic, TRUE);
6001   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6002   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6003 }
6004
6005 /*-----------------------------------------------------------------*/
6006 /* genModbits :- modulus of bits                                   */
6007 /*-----------------------------------------------------------------*/
6008 static void
6009 genModbits (operand * left,
6010             operand * right,
6011             operand * result,
6012             iCode   * ic)
6013 {
6014   char *l;
6015   bool pushedB;
6016
6017   D (emitcode (";", "genModbits"));
6018
6019   pushedB = pushB ();
6020
6021   /* the result must be bit */
6022   LOAD_AB_FOR_DIV (left, right, l);
6023   emitcode ("div", "ab");
6024   emitcode ("mov", "a,b");
6025   emitcode ("rrc", "a");
6026   aopOp(result, ic, TRUE, FALSE);
6027
6028   popB (pushedB);
6029
6030   aopPut (result, "c", 0);
6031 }
6032
6033 /*-----------------------------------------------------------------*/
6034 /* genModOneByte : 8 bit modulus                                   */
6035 /*-----------------------------------------------------------------*/
6036 static void
6037 genModOneByte (operand * left,
6038                operand * right,
6039                operand * result,
6040                iCode   * ic)
6041 {
6042   bool lUnsigned, rUnsigned, pushedB;
6043   bool runtimeSign, compiletimeSign;
6044   char *l;
6045   symbol *lbl;
6046   int size, offset;
6047
6048   D (emitcode (";", "genModOneByte"));
6049
6050   offset = 1;
6051   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6052   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6053
6054   pushedB = pushB ();
6055
6056   /* signed or unsigned */
6057   if (lUnsigned && rUnsigned)
6058     {
6059       /* unsigned is easy */
6060       LOAD_AB_FOR_DIV (left, right, l);
6061       emitcode ("div", "ab");
6062       aopOp (result, ic, TRUE, FALSE);
6063       aopPut (result, "b", 0);
6064
6065       for (size = AOP_SIZE (result) - 1; size--;)
6066         aopPut (result, zero, offset++);
6067
6068       popB (pushedB);
6069       return;
6070     }
6071
6072   /* signed is a little bit more difficult */
6073
6074   /* now sign adjust for both left & right */
6075
6076   /* modulus: sign of the right operand has no influence on the result! */
6077   if (AOP_TYPE(right) == AOP_LIT)
6078     {
6079       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6080
6081       if (!rUnsigned && val < 0)
6082         emitcode ("mov", "b,#0x%02x", -val);
6083       else
6084         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6085     }
6086   else /* not literal */
6087     {
6088       if (rUnsigned)
6089         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6090       else
6091         {
6092           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6093           lbl = newiTempLabel (NULL);
6094           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6095           emitcode ("cpl", "a");  /* 2's complement */
6096           emitcode ("inc", "a");
6097           emitLabel (lbl);
6098           emitcode ("mov", "b,a");
6099         }
6100     }
6101
6102   /* let's see what's needed: */
6103   /* apply negative sign during runtime */
6104   runtimeSign = FALSE;
6105   /* negative sign from literals */
6106   compiletimeSign = FALSE;
6107
6108   /* sign adjust left side */
6109   if (AOP_TYPE(left) == AOP_LIT)
6110     {
6111       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6112
6113       if (!lUnsigned && val < 0)
6114         {
6115           compiletimeSign = TRUE; /* set sign flag */
6116           emitcode ("mov", "a,#0x%02x", -val);
6117         }
6118       else
6119         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6120     }
6121   else /* ! literal */
6122     {
6123       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6124
6125       if (!lUnsigned)
6126         {
6127           runtimeSign = TRUE;
6128           emitcode ("clr", "F0"); /* clear sign flag */
6129
6130           lbl = newiTempLabel (NULL);
6131           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6132           emitcode ("setb", "F0"); /* set sign flag */
6133           emitcode ("cpl", "a");   /* 2's complement */
6134           emitcode ("inc", "a");
6135           emitLabel (lbl);
6136         }
6137     }
6138
6139   /* now the modulus */
6140   emitcode ("nop", "; workaround for DS80C390 div bug.");
6141   emitcode ("div", "ab");
6142
6143   if (runtimeSign || compiletimeSign)
6144     {
6145       emitcode ("mov", "a,b");
6146       lbl = newiTempLabel (NULL);
6147       if (runtimeSign)
6148         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6149       emitcode ("cpl", "a"); /* lsb 2's complement */
6150       emitcode ("inc", "a");
6151       emitLabel (lbl);
6152
6153       _G.accInUse++;
6154       aopOp (result, ic, TRUE, FALSE);
6155       size = AOP_SIZE (result) - 1;
6156
6157       if (size > 0)
6158         {
6159           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6160              then the result will be in b, a */
6161           emitcode ("mov", "b,a"); /* 1 */
6162           /* msb is 0x00 or 0xff depending on the sign */
6163           if (runtimeSign)
6164             {
6165               emitcode ("mov",  "c,F0");
6166               emitcode ("subb", "a,acc");
6167               emitcode ("xch",  "a,b"); /* 2 */
6168               while (size--)
6169                 aopPut (result, "b", offset++); /* write msb's */
6170             }
6171           else /* compiletimeSign */
6172             while (size--)
6173               aopPut (result, "#0xff", offset++); /* write msb's */
6174         }
6175       aopPut (result, "a", 0); /* 3: write lsb */
6176     }
6177   else
6178     {
6179       _G.accInUse++;
6180       aopOp(result, ic, TRUE, FALSE);
6181       size = AOP_SIZE (result) - 1;
6182
6183       aopPut (result, "b", 0);
6184       while (size--)
6185         aopPut (result, zero, offset++);
6186     }
6187   _G.accInUse--;
6188   popB (pushedB);
6189 }
6190
6191 /*-----------------------------------------------------------------*/
6192 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6193 /*-----------------------------------------------------------------*/
6194 static void genModTwoByte (operand *left, operand *right,
6195                             operand *result, iCode *ic)
6196 {
6197         sym_link *retype = getSpec(operandType(right));
6198         sym_link *letype = getSpec(operandType(left));
6199         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6200         symbol *lbl;
6201
6202         /* load up MA with left */
6203         /* save EA bit in F1 */
6204         lbl = newiTempLabel(NULL);
6205         emitcode ("setb","F1");
6206         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6207         emitcode ("clr","F1");
6208         emitLabel (lbl);
6209
6210         if (!umult) {
6211                 lbl = newiTempLabel(NULL);
6212                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6213                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6214                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6215                 emitcode ("xch", "a,b");
6216                 emitcode ("cpl","a");
6217                 emitcode ("add", "a,#1");
6218                 emitcode ("xch", "a,b");
6219                 emitcode ("cpl", "a"); // msb
6220                 emitcode ("addc","a,#0");
6221                 emitLabel (lbl);
6222                 emitcode ("mov","ma,b");
6223                 emitcode ("mov","ma,a");
6224         } else {
6225                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6226                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6227         }
6228
6229         /* load up MB with right */
6230         if (!umult) {
6231                 if (AOP_TYPE(right) == AOP_LIT) {
6232                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6233                         if (val < 0) {
6234                                 val = -val;
6235                         }
6236                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6237                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6238                 } else {
6239                         lbl = newiTempLabel(NULL);
6240                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6241                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6242                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6243                         emitcode ("xch", "a,b");
6244                         emitcode ("cpl","a");
6245                         emitcode ("add", "a,#1");
6246                         emitcode ("xch", "a,b");
6247                         emitcode ("cpl", "a"); // msb
6248                         emitcode ("addc", "a,#0");
6249                         emitLabel (lbl);
6250                         emitcode ("mov","mb,b");
6251                         emitcode ("mov","mb,a");
6252                 }
6253         } else {
6254                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6255                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6256         }
6257
6258         /* wait for multiplication to finish */
6259         lbl = newiTempLabel(NULL);
6260         emitLabel (lbl);
6261         emitcode("mov","a,mcnt1");
6262         emitcode("anl","a,#!constbyte",0x80);
6263         emitcode("jnz","!tlabel",lbl->key+100);
6264
6265         freeAsmop (left, NULL, ic, TRUE);
6266         freeAsmop (right, NULL, ic,TRUE);
6267         aopOp(result, ic, TRUE, FALSE);
6268
6269         aopPut(result,"mb",1);
6270         aopPut(result,"mb",0);
6271         freeAsmop (result, NULL, ic, TRUE);
6272
6273         /* restore EA bit in F1 */
6274         lbl = newiTempLabel(NULL);
6275         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6276         emitcode ("setb","EA");
6277         emitLabel (lbl);
6278 }
6279
6280 /*-----------------------------------------------------------------*/
6281 /* genMod - generates code for division                            */
6282 /*-----------------------------------------------------------------*/
6283 static void
6284 genMod (iCode * ic)
6285 {
6286   operand *left = IC_LEFT (ic);
6287   operand *right = IC_RIGHT (ic);
6288   operand *result = IC_RESULT (ic);
6289
6290   D (emitcode (";", "genMod"));
6291
6292   /* assign the asmops */
6293   AOP_OP_2 (ic);
6294
6295   /* special cases first */
6296   /* both are bits */
6297   if (AOP_TYPE (left) == AOP_CRY &&
6298       AOP_TYPE (right) == AOP_CRY)
6299     {
6300       genModbits (left, right, result, ic);
6301       goto release;
6302     }
6303
6304   /* if both are of size == 1 */
6305   if (AOP_SIZE (left) == 1 &&
6306       AOP_SIZE (right) == 1)
6307     {
6308       genModOneByte (left, right, result, ic);
6309       goto release;
6310     }
6311
6312   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6313           /* use the ds390 ARITHMETIC accel UNIT */
6314           genModTwoByte (left, right, result, ic);
6315           return ;
6316   }
6317
6318   /* should have been converted to function call */
6319   assert (0);
6320
6321 release:
6322   freeAsmop (result, NULL, ic, TRUE);
6323   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6324   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6325 }
6326
6327 /*-----------------------------------------------------------------*/
6328 /* genIfxJump :- will create a jump depending on the ifx           */
6329 /*-----------------------------------------------------------------*/
6330 static void
6331 genIfxJump (iCode * ic, char *jval)
6332 {
6333   symbol *jlbl;
6334   symbol *tlbl = newiTempLabel (NULL);
6335   char *inst;
6336
6337   D (emitcode (";", "genIfxJump"));
6338
6339   /* if true label then we jump if condition
6340      supplied is true */
6341   if (IC_TRUE (ic))
6342     {
6343       jlbl = IC_TRUE (ic);
6344       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6345                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6346     }
6347   else
6348     {
6349       /* false label is present */
6350       jlbl = IC_FALSE (ic);
6351       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6352                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6353     }
6354   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6355     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6356   else
6357     emitcode (inst, "!tlabel", tlbl->key + 100);
6358   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6359   emitLabel (tlbl);
6360
6361   /* mark the icode as generated */
6362   ic->generated = 1;
6363 }
6364
6365 /*-----------------------------------------------------------------*/
6366 /* genCmp :- greater or less than comparison                       */
6367 /*-----------------------------------------------------------------*/
6368 static void
6369 genCmp (operand * left, operand * right,
6370         iCode * ic, iCode * ifx, int sign)
6371 {
6372   int size, offset = 0;
6373   unsigned long lit = 0L;
6374   operand *result;
6375
6376   D (emitcode (";", "genCmp"));
6377
6378   result = IC_RESULT (ic);
6379
6380   /* if left & right are bit variables */
6381   if (AOP_TYPE (left) == AOP_CRY &&
6382       AOP_TYPE (right) == AOP_CRY)
6383     {
6384       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6385       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6386     }
6387   else
6388     {
6389       /* subtract right from left if at the
6390          end the carry flag is set then we know that
6391          left is greater than right */
6392       size = max (AOP_SIZE (left), AOP_SIZE (right));
6393
6394       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6395       if ((size == 1) && !sign &&
6396           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6397         {
6398           symbol *lbl = newiTempLabel (NULL);
6399           emitcode ("cjne", "%s,%s,!tlabel",
6400                     aopGet (left, offset, FALSE, FALSE, NULL),
6401                     aopGet (right, offset, FALSE, FALSE, NULL),
6402                     lbl->key + 100);
6403           emitLabel (lbl);
6404         }
6405       else
6406         {
6407           if (AOP_TYPE (right) == AOP_LIT)
6408             {
6409               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6410               /* optimize if(x < 0) or if(x >= 0) */
6411               if (lit == 0L)
6412                 {
6413                   if (!sign)
6414                     {
6415                       CLRC;
6416                     }
6417                   else
6418                     {
6419                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6420
6421                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6422                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6423
6424                       aopOp (result, ic, FALSE, FALSE);
6425
6426                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6427                         {
6428                           freeAsmop (result, NULL, ic, TRUE);
6429                           genIfxJump (ifx, "acc.7");
6430                           return;
6431                         }
6432                       else
6433                         {
6434                           emitcode ("rlc", "a");
6435                         }
6436                       goto release_freedLR;
6437                     }
6438                   goto release;
6439                 }
6440             }
6441           CLRC;
6442           while (size--)
6443             {
6444               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6445               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6446               // emitcode (";", "genCmp #2");
6447               if (sign && (size == 0))
6448                 {
6449                   // emitcode (";", "genCmp #3");
6450                   emitcode ("xrl", "a,#!constbyte",0x80);
6451                   if (AOP_TYPE (right) == AOP_LIT)
6452                     {
6453                       unsigned long lit = (unsigned long)
6454                       floatFromVal (AOP (right)->aopu.aop_lit);
6455                       // emitcode (";", "genCmp #3.1");
6456                       emitcode ("subb", "a,#!constbyte",
6457                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6458                     }
6459                   else
6460                     {
6461                       // emitcode (";", "genCmp #3.2");
6462                       saveAccWarn = 0;
6463                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6464                       saveAccWarn = DEFAULT_ACC_WARNING;
6465                       emitcode ("xrl", "b,#!constbyte",0x80);
6466                       emitcode ("subb", "a,b");
6467                     }
6468                 }
6469               else
6470                 {
6471                   const char *s;
6472
6473                   // emitcode (";", "genCmp #4");
6474                   saveAccWarn = 0;
6475                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6476                   saveAccWarn = DEFAULT_ACC_WARNING;
6477
6478                   emitcode ("subb", "a,%s", s);
6479                 }
6480             }
6481         }
6482     }
6483
6484 release:
6485 /* Don't need the left & right operands any more; do need the result. */
6486   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6487   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6488
6489   aopOp (result, ic, FALSE, FALSE);
6490
6491 release_freedLR:
6492
6493   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6494     {
6495       outBitC (result);
6496     }
6497   else
6498     {
6499       /* if the result is used in the next
6500          ifx conditional branch then generate
6501          code a little differently */
6502       if (ifx)
6503         {
6504           genIfxJump (ifx, "c");
6505         }
6506       else
6507         {
6508           outBitC (result);
6509         }
6510       /* leave the result in acc */
6511     }
6512   freeAsmop (result, NULL, ic, TRUE);
6513 }
6514
6515 /*-----------------------------------------------------------------*/
6516 /* genCmpGt :- greater than comparison                             */
6517 /*-----------------------------------------------------------------*/
6518 static void
6519 genCmpGt (iCode * ic, iCode * ifx)
6520 {
6521   operand *left, *right;
6522   sym_link *letype, *retype;
6523   int sign;
6524
6525   D (emitcode (";", "genCmpGt"));
6526
6527   left = IC_LEFT (ic);
6528   right = IC_RIGHT (ic);
6529
6530   letype = getSpec (operandType (left));
6531   retype = getSpec (operandType (right));
6532   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6533
6534   /* assign the left & right amsops */
6535   AOP_OP_2 (ic);
6536
6537   genCmp (right, left, ic, ifx, sign);
6538 }
6539
6540 /*-----------------------------------------------------------------*/
6541 /* genCmpLt - less than comparisons                                */
6542 /*-----------------------------------------------------------------*/
6543 static void
6544 genCmpLt (iCode * ic, iCode * ifx)
6545 {
6546   operand *left, *right;
6547   sym_link *letype, *retype;
6548   int sign;
6549
6550   D (emitcode (";", "genCmpLt"));
6551
6552   left = IC_LEFT (ic);
6553   right = IC_RIGHT (ic);
6554
6555   letype = getSpec (operandType (left));
6556   retype = getSpec (operandType (right));
6557   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6558
6559   /* assign the left & right amsops */
6560   AOP_OP_2 (ic);
6561
6562   genCmp (left, right, ic, ifx, sign);
6563 }
6564
6565 /*-----------------------------------------------------------------*/
6566 /* gencjneshort - compare and jump if not equal                    */
6567 /*-----------------------------------------------------------------*/
6568 static void
6569 gencjneshort (operand * left, operand * right, symbol * lbl)
6570 {
6571   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6572   int offset = 0;
6573   unsigned long lit = 0L;
6574
6575   D (emitcode (";", "gencjneshort"));
6576
6577   /* if the left side is a literal or
6578      if the right is in a pointer register and left
6579      is not */
6580   if ((AOP_TYPE (left) == AOP_LIT) ||
6581       (AOP_TYPE (left) == AOP_IMMD) ||
6582       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6583     {
6584       operand *t = right;
6585       right = left;
6586       left = t;
6587     }
6588
6589   if (AOP_TYPE (right) == AOP_LIT)
6590     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6591
6592   if (opIsGptr (left) || opIsGptr (right))
6593     {
6594       /* We are comparing a generic pointer to something.
6595        * Exclude the generic type byte from the comparison.
6596        */
6597       size--;
6598       D (emitcode (";", "cjneshort: generic ptr special case."););
6599     }
6600
6601
6602   /* if the right side is a literal then anything goes */
6603   if (AOP_TYPE (right) == AOP_LIT &&
6604       AOP_TYPE (left) != AOP_DIR)
6605     {
6606       while (size--)
6607         {
6608           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6609           emitcode ("cjne", "a,%s,!tlabel",
6610                     aopGet (right, offset, FALSE, FALSE, NULL),
6611                     lbl->key + 100);
6612           offset++;
6613         }
6614     }
6615
6616   /* if the right side is in a register or in direct space or
6617      if the left is a pointer register & right is not */
6618   else if (AOP_TYPE (right) == AOP_REG ||
6619            AOP_TYPE (right) == AOP_DIR ||
6620            AOP_TYPE (right) == AOP_LIT ||
6621            AOP_TYPE (right) == AOP_IMMD ||
6622            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6623            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6624     {
6625       while (size--)
6626         {
6627           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6628           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6629               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6630             emitcode ("jnz", "!tlabel", lbl->key + 100);
6631           else
6632             emitcode ("cjne", "a,%s,!tlabel",
6633                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6634                       lbl->key + 100);
6635           offset++;
6636         }
6637     }
6638   else
6639     {
6640       /* right is a pointer reg need both a & b */
6641       while (size--)
6642         {
6643           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6644           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6645           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6646           offset++;
6647         }
6648     }
6649 }
6650
6651 /*-----------------------------------------------------------------*/
6652 /* gencjne - compare and jump if not equal                         */
6653 /*-----------------------------------------------------------------*/
6654 static void
6655 gencjne (operand * left, operand * right, symbol * lbl)
6656 {
6657   symbol *tlbl = newiTempLabel (NULL);
6658
6659   D (emitcode (";", "gencjne"));
6660
6661   gencjneshort (left, right, lbl);
6662
6663   emitcode ("mov", "a,%s", one);
6664   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6665   emitLabel (lbl);
6666   emitcode ("clr", "a");
6667   emitLabel (tlbl);
6668 }
6669
6670 /*-----------------------------------------------------------------*/
6671 /* genCmpEq - generates code for equal to                          */
6672 /*-----------------------------------------------------------------*/
6673 static void
6674 genCmpEq (iCode * ic, iCode * ifx)
6675 {
6676   operand *left, *right, *result;
6677
6678   D (emitcode (";", "genCmpEq"));
6679
6680   AOP_OP_2 (ic);
6681   AOP_SET_LOCALS (ic);
6682
6683   /* if literal, literal on the right or
6684      if the right is in a pointer register and left
6685      is not */
6686   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6687       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6688     {
6689       operand *t = IC_RIGHT (ic);
6690       IC_RIGHT (ic) = IC_LEFT (ic);
6691       IC_LEFT (ic) = t;
6692     }
6693
6694   if (ifx &&                    /* !AOP_SIZE(result) */
6695       OP_SYMBOL (result) &&
6696       OP_SYMBOL (result)->regType == REG_CND)
6697     {
6698       symbol *tlbl;
6699       /* if they are both bit variables */
6700       if (AOP_TYPE (left) == AOP_CRY &&
6701           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6702         {
6703           if (AOP_TYPE (right) == AOP_LIT)
6704             {
6705               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6706               if (lit == 0L)
6707                 {
6708                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6709                   emitcode ("cpl", "c");
6710                 }
6711               else if (lit == 1L)
6712                 {
6713                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6714                 }
6715               else
6716                 {
6717                   emitcode ("clr", "c");
6718                 }
6719               /* AOP_TYPE(right) == AOP_CRY */
6720             }
6721           else
6722             {
6723               symbol *lbl = newiTempLabel (NULL);
6724               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6725               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6726               emitcode ("cpl", "c");
6727               emitLabel (lbl);
6728             }
6729           /* if true label then we jump if condition
6730              supplied is true */
6731           tlbl = newiTempLabel (NULL);
6732           if (IC_TRUE (ifx))
6733             {
6734               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6735               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6736             }
6737           else
6738             {
6739               emitcode ("jc", "!tlabel", tlbl->key + 100);
6740               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6741             }
6742           emitLabel (tlbl);
6743         }
6744       else
6745         {
6746           tlbl = newiTempLabel (NULL);
6747           gencjneshort (left, right, tlbl);
6748           if (IC_TRUE (ifx))
6749             {
6750               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6751               emitLabel (tlbl);
6752             }
6753           else
6754             {
6755               symbol *lbl = newiTempLabel (NULL);
6756               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6757               emitLabel (tlbl);
6758               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6759               emitLabel (lbl);
6760             }
6761         }
6762       /* mark the icode as generated */
6763       ifx->generated = 1;
6764
6765       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6766       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6767       return;
6768     }
6769
6770   /* if they are both bit variables */
6771   if (AOP_TYPE (left) == AOP_CRY &&
6772       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6773     {
6774       if (AOP_TYPE (right) == AOP_LIT)
6775         {
6776           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6777           if (lit == 0L)
6778             {
6779               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6780               emitcode ("cpl", "c");
6781             }
6782           else if (lit == 1L)
6783             {
6784               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6785             }
6786           else
6787             {
6788               emitcode ("clr", "c");
6789             }
6790           /* AOP_TYPE(right) == AOP_CRY */
6791         }
6792       else
6793         {
6794           symbol *lbl = newiTempLabel (NULL);
6795           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6796           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6797           emitcode ("cpl", "c");
6798           emitLabel (lbl);
6799         }
6800
6801       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6802       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6803
6804       aopOp (result, ic, TRUE, FALSE);
6805
6806       /* c = 1 if egal */
6807       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6808         {
6809           outBitC (result);
6810           goto release;
6811         }
6812       if (ifx)
6813         {
6814           genIfxJump (ifx, "c");
6815           goto release;
6816         }
6817       /* if the result is used in an arithmetic operation
6818          then put the result in place */
6819       outBitC (result);
6820     }
6821   else
6822     {
6823       gencjne (left, right, newiTempLabel (NULL));
6824
6825       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6826       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6827
6828       aopOp (result, ic, TRUE, FALSE);
6829
6830       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6831         {
6832           aopPut (result, "a", 0);
6833           goto release;
6834         }
6835       if (ifx)
6836         {
6837           genIfxJump (ifx, "a");
6838           goto release;
6839         }
6840       /* if the result is used in an arithmetic operation
6841          then put the result in place */
6842       if (AOP_TYPE (result) != AOP_CRY)
6843         outAcc (result);
6844       /* leave the result in acc */
6845     }
6846
6847 release:
6848   freeAsmop (result, NULL, ic, TRUE);
6849 }
6850
6851 /*-----------------------------------------------------------------*/
6852 /* ifxForOp - returns the icode containing the ifx for operand     */
6853 /*-----------------------------------------------------------------*/
6854 static iCode *
6855 ifxForOp (operand * op, iCode * ic)
6856 {
6857   /* if true symbol then needs to be assigned */
6858   if (IS_TRUE_SYMOP (op))
6859     return NULL;
6860
6861   /* if this has register type condition and
6862      the next instruction is ifx with the same operand
6863      and live to of the operand is upto the ifx only then */
6864   if (ic->next &&
6865       ic->next->op == IFX &&
6866       IC_COND (ic->next)->key == op->key &&
6867       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6868     return ic->next;
6869
6870   return NULL;
6871 }
6872
6873 /*-----------------------------------------------------------------*/
6874 /* hasInc - operand is incremented before any other use            */
6875 /*-----------------------------------------------------------------*/
6876 static iCode *
6877 hasInc (operand *op, iCode *ic, int osize)
6878 {
6879   sym_link *type = operandType(op);
6880   sym_link *retype = getSpec (type);
6881   iCode *lic = ic->next;
6882   int isize ;
6883
6884   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6885   if (!IS_SYMOP(op)) return NULL;
6886
6887   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6888   if (IS_AGGREGATE(type->next)) return NULL;
6889   if (osize != (isize = getSize(type->next))) return NULL;
6890
6891   while (lic) {
6892       /* if operand of the form op = op + <sizeof *op> */
6893       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6894           isOperandEqual(IC_RESULT(lic),op) &&
6895           isOperandLiteral(IC_RIGHT(lic)) &&
6896           operandLitValue(IC_RIGHT(lic)) == isize) {
6897           return lic;
6898       }
6899       /* if the operand used or deffed */
6900       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6901           return NULL;
6902       }
6903       /* if GOTO or IFX */
6904       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6905       lic = lic->next;
6906   }
6907   return NULL;
6908 }
6909
6910 /*-----------------------------------------------------------------*/
6911 /* genAndOp - for && operation                                     */
6912 /*-----------------------------------------------------------------*/
6913 static void
6914 genAndOp (iCode * ic)
6915 {
6916   operand *left, *right, *result;
6917   symbol *tlbl;
6918
6919   D (emitcode (";", "genAndOp"));
6920
6921   /* note here that && operations that are in an
6922      if statement are taken away by backPatchLabels
6923      only those used in arthmetic operations remain */
6924   AOP_OP_2 (ic);
6925   AOP_SET_LOCALS (ic);
6926
6927   /* if both are bit variables */
6928   if (AOP_TYPE (left) == AOP_CRY &&
6929       AOP_TYPE (right) == AOP_CRY)
6930     {
6931       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6932       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6933       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6934       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6935
6936       aopOp (result,ic,FALSE, FALSE);
6937       outBitC (result);
6938     }
6939   else
6940     {
6941       tlbl = newiTempLabel (NULL);
6942       toBoolean (left);
6943       emitcode ("jz", "!tlabel", tlbl->key + 100);
6944       toBoolean (right);
6945       emitLabel (tlbl);
6946       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6947       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6948
6949       aopOp (result,ic,FALSE, FALSE);
6950       outBitAcc (result);
6951     }
6952
6953     freeAsmop (result, NULL, ic, TRUE);
6954 }
6955
6956
6957 /*-----------------------------------------------------------------*/
6958 /* genOrOp - for || operation                                      */
6959 /*-----------------------------------------------------------------*/
6960 static void
6961 genOrOp (iCode * ic)
6962 {
6963   operand *left, *right, *result;
6964   symbol *tlbl;
6965
6966   D (emitcode (";", "genOrOp"));
6967
6968   /* note here that || operations that are in an
6969      if statement are taken away by backPatchLabels
6970      only those used in arthmetic operations remain */
6971   AOP_OP_2 (ic);
6972   AOP_SET_LOCALS (ic);
6973
6974   /* if both are bit variables */
6975   if (AOP_TYPE (left) == AOP_CRY &&
6976       AOP_TYPE (right) == AOP_CRY)
6977     {
6978       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6979       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6980       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6981       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6982
6983       aopOp (result,ic,FALSE, FALSE);
6984
6985       outBitC (result);
6986     }
6987   else
6988     {
6989       tlbl = newiTempLabel (NULL);
6990       toBoolean (left);
6991       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6992       toBoolean (right);
6993       emitLabel (tlbl);
6994       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6995       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6996
6997       aopOp (result,ic,FALSE, FALSE);
6998
6999       outBitAcc (result);
7000     }
7001
7002   freeAsmop (result, NULL, ic, TRUE);
7003 }
7004
7005 /*-----------------------------------------------------------------*/
7006 /* isLiteralBit - test if lit == 2^n                               */
7007 /*-----------------------------------------------------------------*/
7008 static int
7009 isLiteralBit (unsigned long lit)
7010 {
7011   unsigned long pw[32] =
7012   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7013    0x100L, 0x200L, 0x400L, 0x800L,
7014    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7015    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7016    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7017    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7018    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7019   int idx;
7020
7021   for (idx = 0; idx < 32; idx++)
7022     if (lit == pw[idx])
7023       return idx + 1;
7024   return 0;
7025 }
7026
7027 /*-----------------------------------------------------------------*/
7028 /* continueIfTrue -                                                */
7029 /*-----------------------------------------------------------------*/
7030 static void
7031 continueIfTrue (iCode * ic)
7032 {
7033   if (IC_TRUE (ic))
7034     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7035   ic->generated = 1;
7036 }
7037
7038 /*-----------------------------------------------------------------*/
7039 /* jmpIfTrue -                                                     */
7040 /*-----------------------------------------------------------------*/
7041 static void
7042 jumpIfTrue (iCode * ic)
7043 {
7044   if (!IC_TRUE (ic))
7045     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7046   ic->generated = 1;
7047 }
7048
7049 /*-----------------------------------------------------------------*/
7050 /* jmpTrueOrFalse -                                                */
7051 /*-----------------------------------------------------------------*/
7052 static void
7053 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7054 {
7055   // ugly but optimized by peephole
7056   if (IC_TRUE (ic))
7057     {
7058       symbol *nlbl = newiTempLabel (NULL);
7059       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7060       emitLabel (tlbl);
7061       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7062       emitLabel (nlbl);
7063     }
7064   else
7065     {
7066       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7067       emitLabel (tlbl);
7068     }
7069   ic->generated = 1;
7070 }
7071
7072 // Generate code to perform a bit-wise logic operation
7073 // on two operands in far space (assumed to already have been
7074 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7075 // in far space. This requires pushing the result on the stack
7076 // then popping it into the result.
7077 static void
7078 genFarFarLogicOp(iCode *ic, char *logicOp)
7079 {
7080       int size, resultSize, compSize;
7081       int offset = 0;
7082
7083       TR_AP("#5");
7084       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7085       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7086                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7087
7088       _startLazyDPSEvaluation();
7089       for (size = compSize; (size--); offset++)
7090       {
7091           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7092           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7093           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7094
7095           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7096           emitcode ("push", "acc");
7097       }
7098       _endLazyDPSEvaluation();
7099
7100       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7101       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7102       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7103
7104       resultSize = AOP_SIZE(IC_RESULT(ic));
7105
7106       ADJUST_PUSHED_RESULT(compSize, resultSize);
7107
7108       _startLazyDPSEvaluation();
7109       while (compSize--)
7110       {
7111           emitcode ("pop", "acc");
7112           aopPut (IC_RESULT (ic), "a", compSize);
7113       }
7114       _endLazyDPSEvaluation();
7115       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7116 }
7117
7118
7119 /*-----------------------------------------------------------------*/
7120 /* genAnd  - code for and                                          */
7121 /*-----------------------------------------------------------------*/
7122 static void
7123 genAnd (iCode * ic, iCode * ifx)
7124 {
7125   operand *left, *right, *result;
7126   int size, offset = 0;
7127   unsigned long lit = 0L;
7128   int bytelit = 0;
7129   char buffer[10];
7130   bool pushResult;
7131
7132   D (emitcode (";", "genAnd"));
7133
7134   AOP_OP_3_NOFATAL (ic, pushResult);
7135   AOP_SET_LOCALS (ic);
7136
7137   if (pushResult)
7138   {
7139       genFarFarLogicOp(ic, "anl");
7140       return;
7141   }
7142
7143 #ifdef DEBUG_TYPE
7144   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7145             AOP_TYPE (result),
7146             AOP_TYPE (left), AOP_TYPE (right));
7147   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7148             AOP_SIZE (result),
7149             AOP_SIZE (left), AOP_SIZE (right));
7150 #endif
7151
7152   /* if left is a literal & right is not then exchange them */
7153   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7154 #ifdef LOGIC_OPS_BROKEN
7155     ||  AOP_NEEDSACC (left)
7156 #endif
7157     )
7158     {
7159       operand *tmp = right;
7160       right = left;
7161       left = tmp;
7162     }
7163
7164   /* if result = right then exchange left and right */
7165   if (sameRegs (AOP (result), AOP (right)))
7166     {
7167       operand *tmp = right;
7168       right = left;
7169       left = tmp;
7170     }
7171
7172   /* if right is bit then exchange them */
7173   if (AOP_TYPE (right) == AOP_CRY &&
7174       AOP_TYPE (left) != AOP_CRY)
7175     {
7176       operand *tmp = right;
7177       right = left;
7178       left = tmp;
7179     }
7180   if (AOP_TYPE (right) == AOP_LIT)
7181     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7182
7183   size = AOP_SIZE (result);
7184
7185   // if(bit & yy)
7186   // result = bit & yy;
7187   if (AOP_TYPE (left) == AOP_CRY)
7188     {
7189       // c = bit & literal;
7190       if (AOP_TYPE (right) == AOP_LIT)
7191         {
7192           if (lit & 1)
7193             {
7194               if (size && sameRegs (AOP (result), AOP (left)))
7195                 // no change
7196                 goto release;
7197               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7198             }
7199           else
7200             {
7201               // bit(result) = 0;
7202               if (size && (AOP_TYPE (result) == AOP_CRY))
7203                 {
7204                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7205                   goto release;
7206                 }
7207               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7208                 {
7209                   jumpIfTrue (ifx);
7210                   goto release;
7211                 }
7212               emitcode ("clr", "c");
7213             }
7214         }
7215       else
7216         {
7217           if (AOP_TYPE (right) == AOP_CRY)
7218             {
7219               // c = bit & bit;
7220               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7221               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7222             }
7223           else
7224             {
7225               // c = bit & val;
7226               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7227               // c = lsb
7228               emitcode ("rrc", "a");
7229               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7230             }
7231         }
7232       // bit = c
7233       // val = c
7234       if (size)
7235         outBitC (result);
7236       // if(bit & ...)
7237       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7238         genIfxJump (ifx, "c");
7239       goto release;
7240     }
7241
7242   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7243   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7244   if ((AOP_TYPE (right) == AOP_LIT) &&
7245       (AOP_TYPE (result) == AOP_CRY) &&
7246       (AOP_TYPE (left) != AOP_CRY))
7247     {
7248       int posbit = isLiteralBit (lit);
7249       /* left &  2^n */
7250       if (posbit)
7251         {
7252           posbit--;
7253           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7254           // bit = left & 2^n
7255           if (size)
7256             {
7257               switch (posbit & 0x07)
7258                 {
7259                   case 0: emitcode ("rrc", "a");
7260                           break;
7261                   case 7: emitcode ("rlc", "a");
7262                           break;
7263                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7264                           break;
7265                 }
7266             }
7267           // if(left &  2^n)
7268           else
7269             {
7270               if (ifx)
7271                 {
7272                   SNPRINTF (buffer, sizeof(buffer),
7273                             "acc.%d", posbit & 0x07);
7274                   genIfxJump (ifx, buffer);
7275                 }
7276               else
7277                 {
7278                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7279                 }
7280               goto release;
7281             }
7282         }
7283       else
7284         {
7285           symbol *tlbl = newiTempLabel (NULL);
7286           int sizel = AOP_SIZE (left);
7287           if (size)
7288             emitcode ("setb", "c");
7289           while (sizel--)
7290             {
7291               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7292                 {
7293                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7294                   // byte ==  2^n ?
7295                   if ((posbit = isLiteralBit (bytelit)) != 0)
7296                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7297                   else
7298                     {
7299                       if (bytelit != 0x0FFL)
7300                         emitcode ("anl", "a,%s",
7301                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7302                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7303                     }
7304                 }
7305               offset++;
7306             }
7307           // bit = left & literal
7308           if (size)
7309             {
7310               emitcode ("clr", "c");
7311               emitLabel (tlbl);
7312             }
7313           // if(left & literal)
7314           else
7315             {
7316               if (ifx)
7317                 jmpTrueOrFalse (ifx, tlbl);
7318               else
7319                 emitLabel (tlbl);
7320               goto release;
7321             }
7322         }
7323       outBitC (result);
7324       goto release;
7325     }
7326
7327   /* if left is same as result */
7328   if (sameRegs (AOP (result), AOP (left)))
7329     {
7330       for (; size--; offset++)
7331         {
7332           if (AOP_TYPE (right) == AOP_LIT)
7333             {
7334               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7335               if (bytelit == 0x0FF)
7336                 {
7337                   /* dummy read of volatile operand */
7338                   if (isOperandVolatile (left, FALSE))
7339                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7340                   else
7341                     continue;
7342                 }
7343               else if (bytelit == 0)
7344                 {
7345                   aopPut (result, zero, offset);
7346                 }
7347               else if (IS_AOP_PREG (result))
7348                 {
7349                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7350                   emitcode ("anl", "a,%s",
7351                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7352                   aopPut (result, "a", offset);
7353                 }
7354               else
7355                 emitcode ("anl", "%s,%s",
7356                           aopGet (left, offset, FALSE, TRUE, NULL),
7357                           aopGet (right, offset, FALSE, FALSE, NULL));
7358             }
7359           else
7360             {
7361               if (AOP_TYPE (left) == AOP_ACC)
7362                 {
7363                   if (offset)
7364                     emitcode("mov", "a,b");
7365                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7366                 }
7367               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7368                 {
7369                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7370                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7371                   emitcode ("anl", "a,b");
7372                   aopPut (result, "a", offset);
7373                 }
7374               else if (aopGetUsesAcc (left, offset))
7375                 {
7376                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7377                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7378                   aopPut (result, "a", offset);
7379                 }
7380               else
7381                 {
7382                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7383                   if (IS_AOP_PREG (result))
7384                     {
7385                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7386                       aopPut (result, "a", offset);
7387                     }
7388                   else
7389                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7390                 }
7391             }
7392         }
7393     }
7394   else
7395     {
7396       // left & result in different registers
7397       if (AOP_TYPE (result) == AOP_CRY)
7398         {
7399           // result = bit
7400           // if(size), result in bit
7401           // if(!size && ifx), conditional oper: if(left & right)
7402           symbol *tlbl = newiTempLabel (NULL);
7403           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7404           if (size)
7405             emitcode ("setb", "c");
7406           while (sizer--)
7407             {
7408               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7409                   && AOP_TYPE(left)==AOP_ACC)
7410                 {
7411                   if (offset)
7412                     emitcode("mov", "a,b");
7413                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7414                 }
7415               else if (AOP_TYPE(left)==AOP_ACC)
7416                 {
7417                   if (!offset)
7418                     {
7419                       bool pushedB = pushB ();
7420                       emitcode("mov", "b,a");
7421                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7422                       emitcode("anl", "a,b");
7423                       popB (pushedB);
7424                     }
7425                   else
7426                     {
7427                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7428                       emitcode("anl", "a,b");
7429                     }
7430                 }
7431               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7432                 {
7433                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7434                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7435                   emitcode ("anl", "a,b");
7436                 }
7437               else if (aopGetUsesAcc (left, offset))
7438                 {
7439                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7440                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7441                 }
7442               else
7443                 {
7444                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7445                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7446                 }
7447
7448               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7449               offset++;
7450             }
7451           if (size)
7452             {
7453               CLRC;
7454               emitLabel (tlbl);
7455               outBitC (result);
7456             }
7457           else if (ifx)
7458             jmpTrueOrFalse (ifx, tlbl);
7459           else
7460             emitLabel (tlbl);
7461         }
7462       else
7463         {
7464           for (; (size--); offset++)
7465             {
7466               // normal case
7467               // result = left & right
7468               if (AOP_TYPE (right) == AOP_LIT)
7469                 {
7470                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7471                   if (bytelit == 0x0FF)
7472                     {
7473                       aopPut (result,
7474                               aopGet (left, offset, FALSE, FALSE, NULL),
7475                               offset);
7476                       continue;
7477                     }
7478                   else if (bytelit == 0)
7479                     {
7480                       /* dummy read of volatile operand */
7481                       if (isOperandVolatile (left, FALSE))
7482                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7483                       aopPut (result, zero, offset);
7484                       continue;
7485                     }
7486                   else if (AOP_TYPE (left) == AOP_ACC)
7487                     {
7488                       if (!offset)
7489                         {
7490                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7491                           aopPut (result, "a", offset);
7492                           continue;
7493                         }
7494                       else
7495                         {
7496                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7497                           aopPut (result, "b", offset);
7498                           continue;
7499                         }
7500                     }
7501                 }
7502               // faster than result <- left, anl result,right
7503               // and better if result is SFR
7504               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7505                   && AOP_TYPE(left)==AOP_ACC)
7506                 {
7507                   if (offset)
7508                     emitcode("mov", "a,b");
7509                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7510                 }
7511               else if (AOP_TYPE(left)==AOP_ACC)
7512                 {
7513                   if (!offset)
7514                     {
7515                       bool pushedB = pushB ();
7516                       emitcode("mov", "b,a");
7517                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7518                       emitcode("anl", "a,b");
7519                       popB (pushedB);
7520                     }
7521                   else
7522                     {
7523                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7524                       emitcode("anl", "a,b");
7525                     }
7526                 }
7527               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7528                 {
7529                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7530                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7531                   emitcode ("anl", "a,b");
7532                 }
7533               else if (aopGetUsesAcc (left, offset))
7534                 {
7535                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7536                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7537                 }
7538               else
7539                 {
7540                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7541                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7542                 }
7543               aopPut (result, "a", offset);
7544             }
7545         }
7546     }
7547
7548 release:
7549   freeAsmop (result, NULL, ic, TRUE);
7550   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7551   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7552 }
7553
7554 /*-----------------------------------------------------------------*/
7555 /* genOr  - code for or                                            */
7556 /*-----------------------------------------------------------------*/
7557 static void
7558 genOr (iCode * ic, iCode * ifx)
7559 {
7560   operand *left, *right, *result;
7561   int size, offset = 0;
7562   unsigned long lit = 0L;
7563   int bytelit = 0;
7564   bool     pushResult;
7565
7566   D (emitcode (";", "genOr"));
7567
7568   AOP_OP_3_NOFATAL (ic, pushResult);
7569   AOP_SET_LOCALS (ic);
7570
7571   if (pushResult)
7572   {
7573       genFarFarLogicOp(ic, "orl");
7574       return;
7575   }
7576
7577
7578 #ifdef DEBUG_TYPE
7579   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7580             AOP_TYPE (result),
7581             AOP_TYPE (left), AOP_TYPE (right));
7582   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7583             AOP_SIZE (result),
7584             AOP_SIZE (left), AOP_SIZE (right));
7585 #endif
7586
7587   /* if left is a literal & right is not then exchange them */
7588   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7589 #ifdef LOGIC_OPS_BROKEN
7590    || AOP_NEEDSACC (left) // I think this is a net loss now.
7591 #endif
7592       )
7593     {
7594       operand *tmp = right;
7595       right = left;
7596       left = tmp;
7597     }
7598
7599   /* if result = right then exchange them */
7600   if (sameRegs (AOP (result), AOP (right)))
7601     {
7602       operand *tmp = right;
7603       right = left;
7604       left = tmp;
7605     }
7606
7607   /* if right is bit then exchange them */
7608   if (AOP_TYPE (right) == AOP_CRY &&
7609       AOP_TYPE (left) != AOP_CRY)
7610     {
7611       operand *tmp = right;
7612       right = left;
7613       left = tmp;
7614     }
7615   if (AOP_TYPE (right) == AOP_LIT)
7616     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7617
7618   size = AOP_SIZE (result);
7619
7620   // if(bit | yy)
7621   // xx = bit | yy;
7622   if (AOP_TYPE (left) == AOP_CRY)
7623     {
7624       if (AOP_TYPE (right) == AOP_LIT)
7625         {
7626           // c = bit | literal;
7627           if (lit)
7628             {
7629               // lit != 0 => result = 1
7630               if (AOP_TYPE (result) == AOP_CRY)
7631                 {
7632                   if (size)
7633                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7634                   else if (ifx)
7635                     continueIfTrue (ifx);
7636                   goto release;
7637                 }
7638               emitcode ("setb", "c");
7639             }
7640           else
7641             {
7642               // lit == 0 => result = left
7643               if (size && sameRegs (AOP (result), AOP (left)))
7644                 goto release;
7645               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7646             }
7647         }
7648       else
7649         {
7650           if (AOP_TYPE (right) == AOP_CRY)
7651             {
7652               // c = bit | bit;
7653               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7654               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7655             }
7656           else
7657             {
7658               // c = bit | val;
7659               symbol *tlbl = newiTempLabel (NULL);
7660               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7661                 emitcode ("setb", "c");
7662               emitcode ("jb", "%s,!tlabel",
7663                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7664               toBoolean (right);
7665               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7666               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7667                 {
7668                   jmpTrueOrFalse (ifx, tlbl);
7669                   goto release;
7670                 }
7671               else
7672                 {
7673                   CLRC;
7674                   emitLabel (tlbl);
7675                 }
7676             }
7677         }
7678       // bit = c
7679       // val = c
7680       if (size)
7681         outBitC (result);
7682       // if(bit | ...)
7683       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7684            genIfxJump (ifx, "c");
7685       goto release;
7686     }
7687
7688   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7689   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7690   if ((AOP_TYPE (right) == AOP_LIT) &&
7691       (AOP_TYPE (result) == AOP_CRY) &&
7692       (AOP_TYPE (left) != AOP_CRY))
7693     {
7694       if (lit)
7695         {
7696           // result = 1
7697           if (size)
7698             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7699           else
7700             continueIfTrue (ifx);
7701           goto release;
7702         }
7703       else
7704         {
7705           // lit = 0, result = boolean(left)
7706           if (size)
7707             emitcode ("setb", "c");
7708           toBoolean (right);
7709           if (size)
7710             {
7711               symbol *tlbl = newiTempLabel (NULL);
7712               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7713               CLRC;
7714               emitLabel (tlbl);
7715             }
7716           else
7717             {
7718               genIfxJump (ifx, "a");
7719               goto release;
7720             }
7721         }
7722       outBitC (result);
7723       goto release;
7724     }
7725
7726   /* if left is same as result */
7727   if (sameRegs (AOP (result), AOP (left)))
7728     {
7729       for (; size--; offset++)
7730         {
7731           if (AOP_TYPE (right) == AOP_LIT)
7732             {
7733               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7734               if (bytelit == 0)
7735                 {
7736                   /* dummy read of volatile operand */
7737                   if (isOperandVolatile (left, FALSE))
7738                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7739                   else
7740                     continue;
7741                 }
7742               else if (bytelit == 0x0FF)
7743                 {
7744                   aopPut (result, "#0xFF", offset);
7745                 }
7746               else if (IS_AOP_PREG (left))
7747                 {
7748                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7749                   emitcode ("orl", "a,%s",
7750                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7751                   aopPut (result, "a", offset);
7752                 }
7753               else
7754                 {
7755                   emitcode ("orl", "%s,%s",
7756                             aopGet (left, offset, FALSE, TRUE, NULL),
7757                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7758                 }
7759             }
7760           else
7761             {
7762               if (AOP_TYPE (left) == AOP_ACC)
7763                 {
7764                   if (offset)
7765                     emitcode("mov", "a,b");
7766                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7767                 }
7768               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7769                 {
7770                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7771                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7772                   emitcode ("orl", "a,b");
7773                   aopPut (result, "a", offset);
7774                 }
7775               else if (aopGetUsesAcc (left, offset))
7776                 {
7777                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7778                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7779                   aopPut (result, "a", offset);
7780                 }
7781               else
7782                 {
7783                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7784                   if (IS_AOP_PREG (left))
7785                     {
7786                       emitcode ("orl", "a,%s",
7787                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7788                       aopPut (result, "a", offset);
7789                     }
7790                   else
7791                     {
7792                       emitcode ("orl", "%s,a",
7793                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7794                     }
7795                 }
7796             }
7797         }
7798     }
7799   else
7800     {
7801       // left & result in different registers
7802       if (AOP_TYPE (result) == AOP_CRY)
7803         {
7804           // result = bit
7805           // if(size), result in bit
7806           // if(!size && ifx), conditional oper: if(left | right)
7807           symbol *tlbl = newiTempLabel (NULL);
7808           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7809           if (size)
7810             emitcode ("setb", "c");
7811           while (sizer--)
7812             {
7813               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7814                   && AOP_TYPE(left)==AOP_ACC)
7815                 {
7816                   if (offset)
7817                     emitcode("mov", "a,b");
7818                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7819                 }
7820               else if (AOP_TYPE(left)==AOP_ACC)
7821                 {
7822                   if (!offset)
7823                     {
7824                       bool pushedB = pushB ();
7825                       emitcode("mov", "b,a");
7826                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7827                       emitcode("orl", "a,b");
7828                       popB (pushedB);
7829                     }
7830                   else
7831                     {
7832                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7833                       emitcode("orl", "a,b");
7834                     }
7835                 }
7836               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7837                 {
7838                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7839                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7840                   emitcode ("orl", "a,b");
7841                 }
7842               else if (aopGetUsesAcc (left, offset))
7843                 {
7844                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7845                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7846                 }
7847               else
7848                 {
7849                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7850                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7851               }
7852
7853               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7854               offset++;
7855             }
7856           if (size)
7857             {
7858               CLRC;
7859               emitLabel (tlbl);
7860               outBitC (result);
7861             }
7862           else if (ifx)
7863             jmpTrueOrFalse (ifx, tlbl);
7864           else
7865             emitLabel (tlbl);
7866         }
7867       else
7868         {
7869             _startLazyDPSEvaluation();
7870           for (; (size--); offset++)
7871             {
7872               // normal case
7873               // result = left | right
7874               if (AOP_TYPE (right) == AOP_LIT)
7875                 {
7876                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7877                   if (bytelit == 0)
7878                     {
7879                       aopPut (result,
7880                               aopGet (left, offset, FALSE, FALSE, NULL),
7881                               offset);
7882                       continue;
7883                     }
7884                   else if (bytelit == 0x0FF)
7885                     {
7886                       /* dummy read of volatile operand */
7887                       if (isOperandVolatile (left, FALSE))
7888                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7889                       aopPut (result, "#0xFF", offset);
7890                       continue;
7891                     }
7892                 }
7893               // faster than result <- left, orl result,right
7894               // and better if result is SFR
7895               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7896                   && AOP_TYPE(left)==AOP_ACC)
7897                 {
7898                   if (offset)
7899                     emitcode("mov", "a,b");
7900                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7901                 }
7902               else if (AOP_TYPE(left)==AOP_ACC)
7903                 {
7904                   if (!offset)
7905                     {
7906                       bool pushedB = pushB ();
7907                       emitcode("mov", "b,a");
7908                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7909                       emitcode("orl", "a,b");
7910                       popB (pushedB);
7911                     }
7912                   else
7913                     {
7914                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7915                       emitcode("orl", "a,b");
7916                     }
7917                 }
7918               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7919                 {
7920                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7921                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7922                   emitcode ("orl", "a,b");
7923                 }
7924               else if (aopGetUsesAcc (left, offset))
7925                 {
7926                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7927                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7928                 }
7929               else
7930                 {
7931                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7932                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7933                 }
7934               aopPut (result, "a", offset);
7935             }
7936             _endLazyDPSEvaluation();
7937         }
7938     }
7939
7940 release:
7941   freeAsmop (result, NULL, ic, TRUE);
7942   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7943   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7944 }
7945
7946 /*-----------------------------------------------------------------*/
7947 /* genXor - code for xclusive or                                   */
7948 /*-----------------------------------------------------------------*/
7949 static void
7950 genXor (iCode * ic, iCode * ifx)
7951 {
7952   operand *left, *right, *result;
7953   int size, offset = 0;
7954   unsigned long lit = 0L;
7955   int bytelit = 0;
7956   bool pushResult;
7957
7958   D (emitcode (";", "genXor"));
7959
7960   AOP_OP_3_NOFATAL (ic, pushResult);
7961   AOP_SET_LOCALS (ic);
7962
7963   if (pushResult)
7964   {
7965       genFarFarLogicOp(ic, "xrl");
7966       return;
7967   }
7968
7969 #ifdef DEBUG_TYPE
7970   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7971             AOP_TYPE (result),
7972             AOP_TYPE (left), AOP_TYPE (right));
7973   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7974             AOP_SIZE (result),
7975             AOP_SIZE (left), AOP_SIZE (right));
7976 #endif
7977
7978   /* if left is a literal & right is not ||
7979      if left needs acc & right does not */
7980   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7981 #ifdef LOGIC_OPS_BROKEN
7982       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7983 #endif
7984      )
7985     {
7986       operand *tmp = right;
7987       right = left;
7988       left = tmp;
7989     }
7990
7991   /* if result = right then exchange them */
7992   if (sameRegs (AOP (result), AOP (right)))
7993     {
7994       operand *tmp = right;
7995       right = left;
7996       left = tmp;
7997     }
7998
7999   /* if right is bit then exchange them */
8000   if (AOP_TYPE (right) == AOP_CRY &&
8001       AOP_TYPE (left) != AOP_CRY)
8002     {
8003       operand *tmp = right;
8004       right = left;
8005       left = tmp;
8006     }
8007   if (AOP_TYPE (right) == AOP_LIT)
8008     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8009
8010   size = AOP_SIZE (result);
8011
8012   // if(bit ^ yy)
8013   // xx = bit ^ yy;
8014   if (AOP_TYPE (left) == AOP_CRY)
8015     {
8016       if (AOP_TYPE (right) == AOP_LIT)
8017         {
8018           // c = bit & literal;
8019           if (lit >> 1)
8020             {
8021               // lit>>1  != 0 => result = 1
8022               if (AOP_TYPE (result) == AOP_CRY)
8023                 {
8024                   if (size)
8025                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8026                   else if (ifx)
8027                     continueIfTrue (ifx);
8028                   goto release;
8029                 }
8030               emitcode ("setb", "c");
8031             }
8032           else
8033             {
8034               // lit == (0 or 1)
8035               if (lit == 0)
8036                 {
8037                   // lit == 0, result = left
8038                   if (size && sameRegs (AOP (result), AOP (left)))
8039                     goto release;
8040                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8041                 }
8042               else
8043                 {
8044                   // lit == 1, result = not(left)
8045                   if (size && sameRegs (AOP (result), AOP (left)))
8046                     {
8047                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8048                       goto release;
8049                     }
8050                   else
8051                     {
8052                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8053                       emitcode ("cpl", "c");
8054                     }
8055                 }
8056             }
8057         }
8058       else
8059         {
8060           // right != literal
8061           symbol *tlbl = newiTempLabel (NULL);
8062           if (AOP_TYPE (right) == AOP_CRY)
8063             {
8064               // c = bit ^ bit;
8065               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8066             }
8067           else
8068             {
8069               int sizer = AOP_SIZE (right);
8070               // c = bit ^ val
8071               // if val>>1 != 0, result = 1
8072               emitcode ("setb", "c");
8073               while (sizer)
8074                 {
8075                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8076                   if (sizer == 1)
8077                     // test the msb of the lsb
8078                     emitcode ("anl", "a,#!constbyte",0xfe);
8079                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8080                   sizer--;
8081                 }
8082               // val = (0,1)
8083               emitcode ("rrc", "a");
8084             }
8085           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8086           emitcode ("cpl", "c");
8087           emitLabel (tlbl);
8088         }
8089       // bit = c
8090       // val = c
8091       if (size)
8092         outBitC (result);
8093       // if(bit | ...)
8094       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8095         genIfxJump (ifx, "c");
8096       goto release;
8097     }
8098
8099   /* if left is same as result */
8100   if (sameRegs (AOP (result), AOP (left)))
8101     {
8102       for (; size--; offset++)
8103         {
8104           if (AOP_TYPE (right) == AOP_LIT)
8105             {
8106               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8107               if (bytelit == 0)
8108                 {
8109                   /* dummy read of volatile operand */
8110                   if (isOperandVolatile (left, FALSE))
8111                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8112                   else
8113                     continue;
8114                 }
8115               else if (IS_AOP_PREG (left))
8116                 {
8117                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8118                   emitcode ("xrl", "a,%s",
8119                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8120                   aopPut (result, "a", offset);
8121                 }
8122               else
8123                 {
8124                   emitcode ("xrl", "%s,%s",
8125                             aopGet (left, offset, FALSE, TRUE, NULL),
8126                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8127                 }
8128             }
8129           else
8130             {
8131               if (AOP_TYPE (left) == AOP_ACC)
8132                 {
8133                   if (offset)
8134                     emitcode("mov", "a,b");
8135                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8136                 }
8137               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8138                 {
8139                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8140                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8141                   emitcode ("xrl", "a,b");
8142                   aopPut (result, "a", offset);
8143                 }
8144               else if (aopGetUsesAcc (left, offset))
8145                 {
8146                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8147                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8148                   aopPut (result, "a", offset);
8149                 }
8150               else
8151                 {
8152                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8153                   if (IS_AOP_PREG (left))
8154                     {
8155                       emitcode ("xrl", "a,%s",
8156                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8157                       aopPut (result, "a", offset);
8158                     }
8159                   else
8160                     emitcode ("xrl", "%s,a",
8161                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8162                 }
8163             }
8164         }
8165     }
8166   else
8167     {
8168       // left & result in different registers
8169       if (AOP_TYPE (result) == AOP_CRY)
8170         {
8171           // result = bit
8172           // if(size), result in bit
8173           // if(!size && ifx), conditional oper: if(left ^ right)
8174           symbol *tlbl = newiTempLabel (NULL);
8175           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8176
8177           if (size)
8178             emitcode ("setb", "c");
8179           while (sizer--)
8180             {
8181               if ((AOP_TYPE (right) == AOP_LIT) &&
8182                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8183                 {
8184                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8185                 }
8186               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8187                   && AOP_TYPE(left)==AOP_ACC)
8188                 {
8189                   if (offset)
8190                     emitcode("mov", "a,b");
8191                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8192                 }
8193               else if (AOP_TYPE(left)==AOP_ACC)
8194                 {
8195                   if (!offset)
8196                     {
8197                       bool pushedB = pushB ();
8198                       emitcode("mov", "b,a");
8199                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8200                       emitcode("xrl", "a,b");
8201                       popB (pushedB);
8202                     }
8203                   else
8204                     {
8205                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8206                       emitcode("xrl", "a,b");
8207                     }
8208                 }
8209               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8210                 {
8211                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8212                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8213                   emitcode ("xrl", "a,b");
8214                 }
8215               else if (aopGetUsesAcc (left, offset))
8216                 {
8217                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8218                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8219                 }
8220               else
8221                 {
8222                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8223                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8224                 }
8225
8226               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8227               offset++;
8228             }
8229           if (size)
8230             {
8231               CLRC;
8232               emitLabel (tlbl);
8233               outBitC (result);
8234             }
8235           else if (ifx)
8236             jmpTrueOrFalse (ifx, tlbl);
8237         }
8238       else
8239         {
8240         for (; (size--); offset++)
8241           {
8242             // normal case
8243             // result = left ^ right
8244             if (AOP_TYPE (right) == AOP_LIT)
8245               {
8246                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8247                 if (bytelit == 0)
8248                   {
8249                     aopPut (result,
8250                             aopGet (left, offset, FALSE, FALSE, NULL),
8251                             offset);
8252                     continue;
8253                   }
8254                 D (emitcode (";", "better literal XOR."));
8255                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8256                 emitcode ("xrl", "a, %s",
8257                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8258               }
8259             else
8260               {
8261                 // faster than result <- left, anl result,right
8262                 // and better if result is SFR
8263                 if (AOP_TYPE (left) == AOP_ACC)
8264                   {
8265                     emitcode ("xrl", "a,%s",
8266                               aopGet (right, offset,
8267                                       FALSE, FALSE, DP2_RESULT_REG));
8268                   }
8269                 else
8270                   {
8271                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8272                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8273                       {
8274                           emitcode("mov", "b,a");
8275                           rOp = "b";
8276                       }
8277
8278                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8279                       emitcode ("xrl", "a,%s", rOp);
8280                   }
8281               }
8282             aopPut (result, "a", offset);
8283           }
8284         }
8285     }
8286
8287 release:
8288   freeAsmop (result, NULL, ic, TRUE);
8289   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8290   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8291 }
8292
8293 /*-----------------------------------------------------------------*/
8294 /* genInline - write the inline code out                           */
8295 /*-----------------------------------------------------------------*/
8296 static void
8297 genInline (iCode * ic)
8298 {
8299   char *buffer, *bp, *bp1;
8300
8301   D (emitcode (";", "genInline"));
8302
8303   _G.inLine += (!options.asmpeep);
8304
8305   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8306
8307   /* emit each line as a code */
8308   while (*bp)
8309     {
8310       if (*bp == '\n')
8311         {
8312           *bp++ = '\0';
8313           emitcode (bp1, "");
8314           bp1 = bp;
8315         }
8316       else
8317         {
8318           /* Add \n for labels, not dirs such as c:\mydir */
8319           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8320             {
8321               bp++;
8322               *bp = '\0';
8323               bp++;
8324               emitcode (bp1, "");
8325               bp1 = bp;
8326             }
8327           else
8328             bp++;
8329         }
8330     }
8331   if (bp1 != bp)
8332     emitcode (bp1, "");
8333   /*     emitcode("",buffer); */
8334   _G.inLine -= (!options.asmpeep);
8335 }
8336
8337 /*-----------------------------------------------------------------*/
8338 /* genRRC - rotate right with carry                                */
8339 /*-----------------------------------------------------------------*/
8340 static void
8341 genRRC (iCode * ic)
8342 {
8343   operand *left, *result;
8344   int     size, offset;
8345   char *l;
8346
8347   D (emitcode (";", "genRRC"));
8348
8349   /* rotate right with carry */
8350   left = IC_LEFT (ic);
8351   result = IC_RESULT (ic);
8352   aopOp (left, ic, FALSE, FALSE);
8353   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8354
8355   /* move it to the result */
8356   size = AOP_SIZE (result);
8357   offset = size - 1;
8358   CLRC;
8359
8360   _startLazyDPSEvaluation ();
8361   while (size--)
8362     {
8363       l = aopGet (left, offset, FALSE, FALSE, NULL);
8364       MOVA (l);
8365       emitcode ("rrc", "a");
8366       if (AOP_SIZE (result) > 1)
8367         aopPut (result, "a", offset--);
8368     }
8369   _endLazyDPSEvaluation ();
8370
8371   /* now we need to put the carry into the
8372      highest order byte of the result */
8373   if (AOP_SIZE (result) > 1)
8374     {
8375       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8376       MOVA (l);
8377     }
8378   emitcode ("mov", "acc.7,c");
8379   aopPut (result, "a", AOP_SIZE (result) - 1);
8380   freeAsmop (result, NULL, ic, TRUE);
8381   freeAsmop (left, NULL, ic, TRUE);
8382 }
8383
8384 /*-----------------------------------------------------------------*/
8385 /* genRLC - generate code for rotate left with carry               */
8386 /*-----------------------------------------------------------------*/
8387 static void
8388 genRLC (iCode * ic)
8389 {
8390   operand *left, *result;
8391   int size, offset;
8392   char *l;
8393
8394   D (emitcode (";", "genRLC"));
8395
8396   /* rotate right with carry */
8397   left = IC_LEFT (ic);
8398   result = IC_RESULT (ic);
8399   aopOp (left, ic, FALSE, FALSE);
8400   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8401
8402   /* move it to the result */
8403   size = AOP_SIZE (result);
8404   offset = 0;
8405   if (size--)
8406     {
8407       l = aopGet (left, offset, FALSE, FALSE, NULL);
8408       MOVA (l);
8409       emitcode ("add", "a,acc");
8410       if (AOP_SIZE (result) > 1)
8411         {
8412           aopPut (result, "a", offset++);
8413         }
8414
8415       _startLazyDPSEvaluation ();
8416       while (size--)
8417         {
8418           l = aopGet (left, offset, FALSE, FALSE, NULL);
8419           MOVA (l);
8420           emitcode ("rlc", "a");
8421           if (AOP_SIZE (result) > 1)
8422             aopPut (result, "a", offset++);
8423         }
8424       _endLazyDPSEvaluation ();
8425     }
8426   /* now we need to put the carry into the
8427      highest order byte of the result */
8428   if (AOP_SIZE (result) > 1)
8429     {
8430       l = aopGet (result, 0, FALSE, FALSE, NULL);
8431       MOVA (l);
8432     }
8433   emitcode ("mov", "acc.0,c");
8434   aopPut (result, "a", 0);
8435   freeAsmop (result, NULL, ic, TRUE);
8436   freeAsmop (left, NULL, ic, TRUE);
8437 }
8438
8439 /*-----------------------------------------------------------------*/
8440 /* genGetHbit - generates code get highest order bit               */
8441 /*-----------------------------------------------------------------*/
8442 static void
8443 genGetHbit (iCode * ic)
8444 {
8445   operand *left, *result;
8446
8447   D (emitcode (";", "genGetHbit"));
8448
8449   left = IC_LEFT (ic);
8450   result = IC_RESULT (ic);
8451   aopOp (left, ic, FALSE, FALSE);
8452   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8453
8454   /* get the highest order byte into a */
8455   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8456   if (AOP_TYPE (result) == AOP_CRY)
8457     {
8458       emitcode ("rlc", "a");
8459       outBitC (result);
8460     }
8461   else
8462     {
8463       emitcode ("rl", "a");
8464       emitcode ("anl", "a,#1");
8465       outAcc (result);
8466     }
8467
8468
8469   freeAsmop (result, NULL, ic, TRUE);
8470   freeAsmop (left, NULL, ic, TRUE);
8471 }
8472
8473 /*-----------------------------------------------------------------*/
8474 /* genSwap - generates code to swap nibbles or bytes               */
8475 /*-----------------------------------------------------------------*/
8476 static void
8477 genSwap (iCode * ic)
8478 {
8479   operand *left, *result;
8480
8481   D(emitcode (";     genSwap",""));
8482
8483   left = IC_LEFT (ic);
8484   result = IC_RESULT (ic);
8485   aopOp (left, ic, FALSE, FALSE);
8486   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8487
8488   _startLazyDPSEvaluation ();
8489   switch (AOP_SIZE (left))
8490     {
8491     case 1: /* swap nibbles in byte */
8492       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8493       emitcode ("swap", "a");
8494       aopPut (result, "a", 0);
8495       break;
8496     case 2: /* swap bytes in word */
8497       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8498         {
8499           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8500           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8501           aopPut (result, "a", 1);
8502         }
8503       else if (operandsEqu (left, result))
8504         {
8505           char * reg = "a";
8506           bool pushedB = FALSE, leftInB = FALSE;
8507
8508           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8509           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8510             {
8511               pushedB = pushB ();
8512               emitcode ("mov", "b,a");
8513               reg = "b";
8514               leftInB = TRUE;
8515             }
8516           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8517           aopPut (result, reg, 1);
8518
8519           if (leftInB)
8520             popB (pushedB);
8521         }
8522       else
8523         {
8524           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8525           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8526         }
8527       break;
8528     default:
8529       wassertl(FALSE, "unsupported SWAP operand size");
8530     }
8531   _endLazyDPSEvaluation ();
8532
8533   freeAsmop (result, NULL, ic, TRUE);
8534   freeAsmop (left, NULL, ic, TRUE);
8535 }
8536
8537 /*-----------------------------------------------------------------*/
8538 /* AccRol - rotate left accumulator by known count                 */
8539 /*-----------------------------------------------------------------*/
8540 static void
8541 AccRol (int shCount)
8542 {
8543   shCount &= 0x0007;            // shCount : 0..7
8544
8545   switch (shCount)
8546     {
8547     case 0:
8548       break;
8549     case 1:
8550       emitcode ("rl", "a");
8551       break;
8552     case 2:
8553       emitcode ("rl", "a");
8554       emitcode ("rl", "a");
8555       break;
8556     case 3:
8557       emitcode ("swap", "a");
8558       emitcode ("rr", "a");
8559       break;
8560     case 4:
8561       emitcode ("swap", "a");
8562       break;
8563     case 5:
8564       emitcode ("swap", "a");
8565       emitcode ("rl", "a");
8566       break;
8567     case 6:
8568       emitcode ("rr", "a");
8569       emitcode ("rr", "a");
8570       break;
8571     case 7:
8572       emitcode ("rr", "a");
8573       break;
8574     }
8575 }
8576
8577 /*-----------------------------------------------------------------*/
8578 /* AccLsh - left shift accumulator by known count                  */
8579 /*-----------------------------------------------------------------*/
8580 static void
8581 AccLsh (int shCount)
8582 {
8583   if (shCount != 0)
8584     {
8585       if (shCount == 1)
8586         emitcode ("add", "a,acc");
8587       else if (shCount == 2)
8588         {
8589           emitcode ("add", "a,acc");
8590           emitcode ("add", "a,acc");
8591         }
8592       else
8593         {
8594           /* rotate left accumulator */
8595           AccRol (shCount);
8596           /* and kill the lower order bits */
8597           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8598         }
8599     }
8600 }
8601
8602 /*-----------------------------------------------------------------*/
8603 /* AccRsh - right shift accumulator by known count                 */
8604 /*-----------------------------------------------------------------*/
8605 static void
8606 AccRsh (int shCount)
8607 {
8608   if (shCount != 0)
8609     {
8610       if (shCount == 1)
8611         {
8612           CLRC;
8613           emitcode ("rrc", "a");
8614         }
8615       else
8616         {
8617           /* rotate right accumulator */
8618           AccRol (8 - shCount);
8619           /* and kill the higher order bits */
8620           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8621         }
8622     }
8623 }
8624
8625 #ifdef BETTER_LITERAL_SHIFT
8626 /*-----------------------------------------------------------------*/
8627 /* AccSRsh - signed right shift accumulator by known count                 */
8628 /*-----------------------------------------------------------------*/
8629 static void
8630 AccSRsh (int shCount)
8631 {
8632   symbol *tlbl;
8633   if (shCount != 0)
8634     {
8635       if (shCount == 1)
8636         {
8637           emitcode ("mov", "c,acc.7");
8638           emitcode ("rrc", "a");
8639         }
8640       else if (shCount == 2)
8641         {
8642           emitcode ("mov", "c,acc.7");
8643           emitcode ("rrc", "a");
8644           emitcode ("mov", "c,acc.7");
8645           emitcode ("rrc", "a");
8646         }
8647       else
8648         {
8649           tlbl = newiTempLabel (NULL);
8650           /* rotate right accumulator */
8651           AccRol (8 - shCount);
8652           /* and kill the higher order bits */
8653           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8654           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8655           emitcode ("orl", "a,#!constbyte",
8656                     (unsigned char) ~SRMask[shCount]);
8657           emitLabel (tlbl);
8658         }
8659     }
8660 }
8661 #endif
8662
8663 #ifdef BETTER_LITERAL_SHIFT
8664 /*-----------------------------------------------------------------*/
8665 /* shiftR1Left2Result - shift right one byte from left to result   */
8666 /*-----------------------------------------------------------------*/
8667 static void
8668 shiftR1Left2Result (operand * left, int offl,
8669                     operand * result, int offr,
8670                     int shCount, int sign)
8671 {
8672   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8673   /* shift right accumulator */
8674   if (sign)
8675     AccSRsh (shCount);
8676   else
8677     AccRsh (shCount);
8678   aopPut (result, "a", offr);
8679 }
8680 #endif
8681
8682 #ifdef BETTER_LITERAL_SHIFT
8683 /*-----------------------------------------------------------------*/
8684 /* shiftL1Left2Result - shift left one byte from left to result    */
8685 /*-----------------------------------------------------------------*/
8686 static void
8687 shiftL1Left2Result (operand * left, int offl,
8688                     operand * result, int offr, int shCount)
8689 {
8690   char *l;
8691   l = aopGet (left, offl, FALSE, FALSE, NULL);
8692   MOVA (l);
8693   /* shift left accumulator */
8694   AccLsh (shCount);
8695   aopPut (result, "a", offr);
8696 }
8697 #endif
8698
8699 #ifdef BETTER_LITERAL_SHIFT
8700 /*-----------------------------------------------------------------*/
8701 /* movLeft2Result - move byte from left to result                  */
8702 /*-----------------------------------------------------------------*/
8703 static void
8704 movLeft2Result (operand * left, int offl,
8705                 operand * result, int offr, int sign)
8706 {
8707   char *l;
8708   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8709   {
8710       l = aopGet (left, offl, FALSE, FALSE, NULL);
8711
8712       if (*l == '@' && (IS_AOP_PREG (result)))
8713       {
8714           emitcode ("mov", "a,%s", l);
8715           aopPut (result, "a", offr);
8716       }
8717       else
8718       {
8719           if (!sign)
8720             {
8721               aopPut (result, l, offr);
8722             }
8723           else
8724             {
8725               /* MSB sign in acc.7 ! */
8726               if (getDataSize (left) == offl + 1)
8727                 {
8728                   MOVA (l);
8729                   aopPut (result, "a", offr);
8730                 }
8731             }
8732       }
8733   }
8734 }
8735 #endif
8736
8737 #ifdef BETTER_LITERAL_SHIFT
8738 /*-----------------------------------------------------------------*/
8739 /* AccAXRrl1 - right rotate a:x by 1                               */
8740 /*-----------------------------------------------------------------*/
8741 static void
8742 AccAXRrl1 (char *x)
8743 {
8744   emitcode ("mov", "c,acc.0");
8745   emitcode ("xch", "a,%s", x);
8746   emitcode ("rrc", "a");
8747   emitcode ("xch", "a,%s", x);
8748   emitcode ("rrc", "a");
8749 }
8750 #endif
8751
8752 #ifdef BETTER_LITERAL_SHIFT
8753 //REMOVE ME!!!
8754 /*-----------------------------------------------------------------*/
8755 /* AccAXLrl1 - left rotate a:x by 1                                */
8756 /*-----------------------------------------------------------------*/
8757 static void
8758 AccAXLrl1 (char *x)
8759 {
8760   emitcode ("mov", "c,acc.7");
8761   emitcode ("xch", "a,%s", x);
8762   emitcode ("rlc", "a");
8763   emitcode ("xch", "a,%s", x);
8764   emitcode ("rlc", "a");
8765 }
8766 #endif
8767
8768 #ifdef BETTER_LITERAL_SHIFT
8769 /*-----------------------------------------------------------------*/
8770 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8771 /*-----------------------------------------------------------------*/
8772 static void
8773 AccAXRsh1 (char *x)
8774 {
8775   emitcode ("rrc", "a");
8776   emitcode ("xch", "a,%s", x);
8777   emitcode ("rrc", "a");
8778   emitcode ("xch", "a,%s", x);
8779 }
8780 #endif
8781
8782 #ifdef BETTER_LITERAL_SHIFT
8783 /*-----------------------------------------------------------------*/
8784 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8785 /*-----------------------------------------------------------------*/
8786 static void
8787 AccAXLsh1 (char *x)
8788 {
8789   emitcode ("xch", "a,%s", x);
8790   emitcode ("add", "a,acc");
8791   emitcode ("xch", "a,%s", x);
8792   emitcode ("rlc", "a");
8793 }
8794 #endif
8795
8796 #ifdef BETTER_LITERAL_SHIFT
8797 /*-----------------------------------------------------------------*/
8798 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8799 /*-----------------------------------------------------------------*/
8800 static void
8801 AccAXLsh (char *x, int shCount)
8802 {
8803   switch (shCount)
8804     {
8805     case 0:
8806       break;
8807     case 1:
8808       AccAXLsh1 (x);
8809       break;
8810     case 2:
8811       AccAXLsh1 (x);
8812       AccAXLsh1 (x);
8813       break;
8814     case 3:
8815     case 4:
8816     case 5:                             // AAAAABBB:CCCCCDDD
8817
8818       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8819
8820       emitcode ("anl", "a,#!constbyte",
8821                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8822
8823       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8824
8825       AccRol (shCount);                 // DDDCCCCC:BBB00000
8826
8827       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8828
8829       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8830
8831       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8832
8833       emitcode ("anl", "a,#!constbyte",
8834                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8835
8836       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8837
8838       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8839
8840       break;
8841     case 6:                             // AAAAAABB:CCCCCCDD
8842       emitcode ("anl", "a,#!constbyte",
8843                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8844 #if 1
8845       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8846       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8847       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8848 #else
8849       emitcode ("mov", "c,acc.0");      // c = B
8850       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8851       emitcode("rrc","a");
8852       emitcode("xch","a,%s", x);
8853       emitcode("rrc","a");
8854       emitcode("mov","c,acc.0"); //<< get correct bit
8855       emitcode("xch","a,%s", x);
8856
8857       emitcode("rrc","a");
8858       emitcode("xch","a,%s", x);
8859       emitcode("rrc","a");
8860       emitcode("xch","a,%s", x);
8861 #endif
8862       break;
8863     case 7:                             // a:x <<= 7
8864
8865       emitcode ("anl", "a,#!constbyte",
8866                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8867
8868       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8869
8870       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8871
8872       break;
8873     default:
8874       break;
8875     }
8876 }
8877 #endif
8878
8879 #ifdef BETTER_LITERAL_SHIFT
8880 //REMOVE ME!!!
8881 /*-----------------------------------------------------------------*/
8882 /* AccAXRsh - right shift a:x known count (0..7)                   */
8883 /*-----------------------------------------------------------------*/
8884 static void
8885 AccAXRsh (char *x, int shCount)
8886 {
8887   switch (shCount)
8888     {
8889     case 0:
8890       break;
8891     case 1:
8892       CLRC;
8893       AccAXRsh1 (x);                    // 0->a:x
8894
8895       break;
8896     case 2:
8897       CLRC;
8898       AccAXRsh1 (x);                    // 0->a:x
8899
8900       CLRC;
8901       AccAXRsh1 (x);                    // 0->a:x
8902
8903       break;
8904     case 3:
8905     case 4:
8906     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8907
8908       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8909
8910       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8911
8912       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8913
8914       emitcode ("anl", "a,#!constbyte",
8915                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8916
8917       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8918
8919       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8920
8921       emitcode ("anl", "a,#!constbyte",
8922                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8923
8924       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8925
8926       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8927
8928       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8929
8930       break;
8931     case 6:                             // AABBBBBB:CCDDDDDD
8932
8933       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8934       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8935
8936       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8937
8938       emitcode ("anl", "a,#!constbyte",
8939                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8940
8941       break;
8942     case 7:                             // ABBBBBBB:CDDDDDDD
8943
8944       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8945
8946       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8947
8948       emitcode ("anl", "a,#!constbyte",
8949                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8950
8951       break;
8952     default:
8953       break;
8954     }
8955 }
8956 #endif
8957
8958 #ifdef BETTER_LITERAL_SHIFT
8959 /*-----------------------------------------------------------------*/
8960 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8961 /*-----------------------------------------------------------------*/
8962 static void
8963 AccAXRshS (char *x, int shCount)
8964 {
8965   symbol *tlbl;
8966   switch (shCount)
8967     {
8968     case 0:
8969       break;
8970     case 1:
8971       emitcode ("mov", "c,acc.7");
8972       AccAXRsh1 (x);                    // s->a:x
8973
8974       break;
8975     case 2:
8976       emitcode ("mov", "c,acc.7");
8977       AccAXRsh1 (x);                    // s->a:x
8978
8979       emitcode ("mov", "c,acc.7");
8980       AccAXRsh1 (x);                    // s->a:x
8981
8982       break;
8983     case 3:
8984     case 4:
8985     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8986
8987       tlbl = newiTempLabel (NULL);
8988       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8989
8990       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8991
8992       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8993
8994       emitcode ("anl", "a,#!constbyte",
8995                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8996
8997       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8998
8999       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9000
9001       emitcode ("anl", "a,#!constbyte",
9002                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9003
9004       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9005
9006       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9007
9008       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9009
9010       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9011       emitcode ("orl", "a,#!constbyte",
9012                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9013
9014       emitLabel (tlbl);
9015       break;                            // SSSSAAAA:BBBCCCCC
9016
9017     case 6:                             // AABBBBBB:CCDDDDDD
9018
9019       tlbl = newiTempLabel (NULL);
9020
9021       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9022       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9023
9024       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9025
9026       emitcode ("anl", "a,#!constbyte",
9027                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9028
9029       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9030       emitcode ("orl", "a,#!constbyte",
9031                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9032
9033       emitLabel (tlbl);
9034       break;
9035     case 7:                             // ABBBBBBB:CDDDDDDD
9036
9037       tlbl = newiTempLabel (NULL);
9038
9039       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9040
9041       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9042
9043       emitcode ("anl", "a,#!constbyte",
9044                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9045
9046       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9047       emitcode ("orl", "a,#!constbyte",
9048                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9049
9050       emitLabel (tlbl);
9051       break;
9052     default:
9053       break;
9054     }
9055 }
9056 #endif
9057
9058 #ifdef BETTER_LITERAL_SHIFT
9059 static void
9060 _loadLeftIntoAx(char    **lsb,
9061                 operand *left,
9062                 operand *result,
9063                 int     offl,
9064                 int     offr)
9065 {
9066   // Get the initial value from left into a pair of registers.
9067   // MSB must be in A, LSB can be any register.
9068   //
9069   // If the result is held in registers, it is an optimization
9070   // if the LSB can be held in the register which will hold the,
9071   // result LSB since this saves us from having to copy it into
9072   // the result following AccAXLsh.
9073   //
9074   // If the result is addressed indirectly, this is not a gain.
9075   if (AOP_NEEDSACC(result))
9076   {
9077        char *leftByte;
9078
9079        _startLazyDPSEvaluation();
9080       if (AOP_TYPE(left) == AOP_DPTR2)
9081        {
9082            // Get MSB in A.
9083            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9084            // get LSB in DP2_RESULT_REG.
9085            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9086            assert(!strcmp(leftByte, DP2_RESULT_REG));
9087        }
9088        else
9089        {
9090            // get LSB into DP2_RESULT_REG
9091            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9092            if (strcmp(leftByte, DP2_RESULT_REG))
9093            {
9094                TR_AP("#7");
9095                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9096            }
9097            // And MSB in A.
9098            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9099            assert(strcmp(leftByte, DP2_RESULT_REG));
9100            MOVA (leftByte);
9101        }
9102        _endLazyDPSEvaluation();
9103        *lsb = DP2_RESULT_REG;
9104   }
9105   else
9106   {
9107       if (sameRegs (AOP (result), AOP (left)) &&
9108         ((offl + MSB16) == offr))
9109       {
9110           /* don't crash result[offr] */
9111           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9112           emitcode ("xch", "a,%s",
9113                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9114       }
9115       else
9116       {
9117           movLeft2Result (left, offl, result, offr, 0);
9118           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9119       }
9120       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9121       assert(strcmp(*lsb,"a"));
9122   }
9123 }
9124
9125 static void
9126 _storeAxResults(char    *lsb,
9127                 operand *result,
9128                 int     offr)
9129 {
9130   _startLazyDPSEvaluation();
9131   if (AOP_NEEDSACC(result))
9132   {
9133       /* We have to explicitly update the result LSB.
9134        */
9135       emitcode ("xch","a,%s", lsb);
9136       aopPut (result, "a", offr);
9137       emitcode ("mov","a,%s", lsb);
9138   }
9139   if (getDataSize (result) > 1)
9140   {
9141       aopPut (result, "a", offr + MSB16);
9142   }
9143   _endLazyDPSEvaluation();
9144 }
9145
9146 /*-----------------------------------------------------------------*/
9147 /* shiftL2Left2Result - shift left two bytes from left to result   */
9148 /*-----------------------------------------------------------------*/
9149 static void
9150 shiftL2Left2Result (operand * left, int offl,
9151                     operand * result, int offr, int shCount)
9152 {
9153   char *lsb;
9154
9155   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9156
9157   AccAXLsh (lsb, shCount);
9158
9159   _storeAxResults(lsb, result, offr);
9160 }
9161 #endif
9162
9163 #ifdef BETTER_LITERAL_SHIFT
9164 /*-----------------------------------------------------------------*/
9165 /* shiftR2Left2Result - shift right two bytes from left to result  */
9166 /*-----------------------------------------------------------------*/
9167 static void
9168 shiftR2Left2Result (operand * left, int offl,
9169                     operand * result, int offr,
9170                     int shCount, int sign)
9171 {
9172   char *lsb;
9173
9174   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9175
9176   /* a:x >> shCount (x = lsb(result)) */
9177   if (sign)
9178   {
9179      AccAXRshS(lsb, shCount);
9180   }
9181   else
9182   {
9183     AccAXRsh(lsb, shCount);
9184   }
9185
9186   _storeAxResults(lsb, result, offr);
9187 }
9188 #endif
9189
9190 /*-----------------------------------------------------------------*/
9191 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9192 /*-----------------------------------------------------------------*/
9193 static void
9194 shiftLLeftOrResult (operand * left, int offl,
9195                     operand * result, int offr, int shCount)
9196 {
9197   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9198   /* shift left accumulator */
9199   AccLsh (shCount);
9200   /* or with result */
9201   emitcode ("orl", "a,%s",
9202             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9203   /* back to result */
9204   aopPut (result, "a", offr);
9205 }
9206
9207 #if 0
9208 //REMOVE ME!!!
9209 /*-----------------------------------------------------------------*/
9210 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9211 /*-----------------------------------------------------------------*/
9212 static void
9213 shiftRLeftOrResult (operand * left, int offl,
9214                     operand * result, int offr, int shCount)
9215 {
9216   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9217   /* shift right accumulator */
9218   AccRsh (shCount);
9219   /* or with result */
9220   emitcode ("orl", "a,%s",
9221             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9222   /* back to result */
9223   aopPut (result, "a", offr);
9224 }
9225 #endif
9226
9227 #ifdef BETTER_LITERAL_SHIFT
9228 /*-----------------------------------------------------------------*/
9229 /* genlshOne - left shift a one byte quantity by known count       */
9230 /*-----------------------------------------------------------------*/
9231 static void
9232 genlshOne (operand * result, operand * left, int shCount)
9233 {
9234   D (emitcode (";", "genlshOne"));
9235
9236   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9237 }
9238 #endif
9239
9240 #ifdef BETTER_LITERAL_SHIFT
9241 /*-----------------------------------------------------------------*/
9242 /* genlshTwo - left shift two bytes by known amount != 0           */
9243 /*-----------------------------------------------------------------*/
9244 static void
9245 genlshTwo (operand * result, operand * left, int shCount)
9246 {
9247   int size;
9248
9249   D (emitcode (";", "genlshTwo"));
9250
9251   size = getDataSize (result);
9252
9253   /* if shCount >= 8 */
9254   if (shCount >= 8)
9255   {
9256       shCount -= 8;
9257
9258       _startLazyDPSEvaluation();
9259
9260       if (size > 1)
9261         {
9262           if (shCount)
9263           {
9264             _endLazyDPSEvaluation();
9265             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9266             aopPut (result, zero, LSB);
9267           }
9268           else
9269           {
9270             movLeft2Result (left, LSB, result, MSB16, 0);
9271             aopPut (result, zero, LSB);
9272             _endLazyDPSEvaluation();
9273           }
9274         }
9275         else
9276         {
9277           aopPut (result, zero, LSB);
9278           _endLazyDPSEvaluation();
9279         }
9280   }
9281
9282   /*  1 <= shCount <= 7 */
9283   else
9284     {
9285       if (size == 1)
9286         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9287       else
9288         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9289     }
9290 }
9291 #endif
9292
9293 #if 0
9294 //REMOVE ME!!!
9295 /*-----------------------------------------------------------------*/
9296 /* shiftLLong - shift left one long from left to result            */
9297 /* offl = LSB or MSB16                                             */
9298 /*-----------------------------------------------------------------*/
9299 static void
9300 shiftLLong (operand * left, operand * result, int offr)
9301 {
9302   char *l;
9303   int size = AOP_SIZE (result);
9304
9305   if (size >= LSB + offr)
9306     {
9307       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9308       MOVA (l);
9309       emitcode ("add", "a,acc");
9310       if (sameRegs (AOP (left), AOP (result)) &&
9311           size >= MSB16 + offr && offr != LSB)
9312         emitcode ("xch", "a,%s",
9313                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9314       else
9315         aopPut (result, "a", LSB + offr);
9316     }
9317
9318   if (size >= MSB16 + offr)
9319     {
9320       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9321         {
9322           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9323           MOVA (l);
9324         }
9325       emitcode ("rlc", "a");
9326       if (sameRegs (AOP (left), AOP (result)) &&
9327           size >= MSB24 + offr && offr != LSB)
9328         emitcode ("xch", "a,%s",
9329                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9330       else
9331         aopPut (result, "a", MSB16 + offr);
9332     }
9333
9334   if (size >= MSB24 + offr)
9335     {
9336       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9337         {
9338           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9339           MOVA (l);
9340         }
9341       emitcode ("rlc", "a");
9342       if (sameRegs (AOP (left), AOP (result)) &&
9343           size >= MSB32 + offr && offr != LSB)
9344         emitcode ("xch", "a,%s",
9345                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9346       else
9347         aopPut (result, "a", MSB24 + offr);
9348     }
9349
9350   if (size > MSB32 + offr)
9351     {
9352       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9353         {
9354           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9355           MOVA (l);
9356         }
9357       emitcode ("rlc", "a");
9358       aopPut (result, "a", MSB32 + offr);
9359     }
9360   if (offr != LSB)
9361     aopPut (result, zero, LSB);
9362 }
9363 #endif
9364
9365 #if 0
9366 //REMOVE ME!!!
9367 /*-----------------------------------------------------------------*/
9368 /* genlshFour - shift four byte by a known amount != 0             */
9369 /*-----------------------------------------------------------------*/
9370 static void
9371 genlshFour (operand * result, operand * left, int shCount)
9372 {
9373   int size;
9374
9375   D (emitcode (";", "genlshFour"));
9376
9377   size = AOP_SIZE (result);
9378
9379   /* if shifting more that 3 bytes */
9380   if (shCount >= 24)
9381     {
9382       shCount -= 24;
9383       if (shCount)
9384         /* lowest order of left goes to the highest
9385            order of the destination */
9386         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9387       else
9388         movLeft2Result (left, LSB, result, MSB32, 0);
9389       aopPut (result, zero, LSB);
9390       aopPut (result, zero, MSB16);
9391       aopPut (result, zero, MSB24);
9392       return;
9393     }
9394
9395   /* more than two bytes */
9396   else if (shCount >= 16)
9397     {
9398       /* lower order two bytes goes to higher order two bytes */
9399       shCount -= 16;
9400       /* if some more remaining */
9401       if (shCount)
9402         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9403       else
9404         {
9405           movLeft2Result (left, MSB16, result, MSB32, 0);
9406           movLeft2Result (left, LSB, result, MSB24, 0);
9407         }
9408       aopPut (result, zero, MSB16);
9409       aopPut (result, zero, LSB);
9410       return;
9411     }
9412
9413   /* if more than 1 byte */
9414   else if (shCount >= 8)
9415     {
9416       /* lower order three bytes goes to higher order  three bytes */
9417       shCount -= 8;
9418       if (size == 2)
9419         {
9420           if (shCount)
9421             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9422           else
9423             movLeft2Result (left, LSB, result, MSB16, 0);
9424         }
9425       else
9426         {                       /* size = 4 */
9427           if (shCount == 0)
9428             {
9429               movLeft2Result (left, MSB24, result, MSB32, 0);
9430               movLeft2Result (left, MSB16, result, MSB24, 0);
9431               movLeft2Result (left, LSB, result, MSB16, 0);
9432               aopPut (result, zero, LSB);
9433             }
9434           else if (shCount == 1)
9435             shiftLLong (left, result, MSB16);
9436           else
9437             {
9438               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9439               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9440               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9441               aopPut (result, zero, LSB);
9442             }
9443         }
9444     }
9445
9446   /* 1 <= shCount <= 7 */
9447   else if (shCount <= 2)
9448     {
9449       shiftLLong (left, result, LSB);
9450       if (shCount == 2)
9451         shiftLLong (result, result, LSB);
9452     }
9453   /* 3 <= shCount <= 7, optimize */
9454   else
9455     {
9456       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9457       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9458       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9459     }
9460 }
9461 #endif
9462
9463 #ifdef BETTER_LITERAL_SHIFT
9464 /*-----------------------------------------------------------------*/
9465 /* genLeftShiftLiteral - left shifting by known count              */
9466 /*-----------------------------------------------------------------*/
9467 static bool
9468 genLeftShiftLiteral (operand * left,
9469                      operand * right,
9470                      operand * result,
9471                      iCode * ic)
9472 {
9473   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9474   int size;
9475
9476   size = getSize (operandType (result));
9477
9478   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9479
9480   /* We only handle certain easy cases so far. */
9481   if ((shCount != 0)
9482    && (shCount < (size * 8))
9483    && (size != 1)
9484    && (size != 2))
9485   {
9486       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9487       return FALSE;
9488   }
9489
9490   freeAsmop (right, NULL, ic, TRUE);
9491
9492   aopOp(left, ic, FALSE, FALSE);
9493   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9494
9495 #if 0 // debug spew
9496   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9497   {
9498         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9499         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9500         {
9501            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9502         }
9503   }
9504   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9505   {
9506         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9507         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9508         {
9509            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9510         }
9511   }
9512 #endif
9513
9514 #if VIEW_SIZE
9515   emitcode ("; shift left ", "result %d, left %d", size,
9516             AOP_SIZE (left));
9517 #endif
9518
9519   /* I suppose that the left size >= result size */
9520   if (shCount == 0)
9521   {
9522         _startLazyDPSEvaluation();
9523         while (size--)
9524         {
9525           movLeft2Result (left, size, result, size, 0);
9526         }
9527         _endLazyDPSEvaluation();
9528   }
9529   else if (shCount >= (size * 8))
9530   {
9531     _startLazyDPSEvaluation();
9532     while (size--)
9533     {
9534       aopPut (result, zero, size);
9535     }
9536     _endLazyDPSEvaluation();
9537   }
9538   else
9539   {
9540       switch (size)
9541         {
9542         case 1:
9543           genlshOne (result, left, shCount);
9544           break;
9545
9546         case 2:
9547           genlshTwo (result, left, shCount);
9548           break;
9549 #if 0
9550         case 4:
9551           genlshFour (result, left, shCount);
9552           break;
9553 #endif
9554         default:
9555           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9556                   "*** ack! mystery literal shift!\n");
9557           break;
9558         }
9559     }
9560   freeAsmop (result, NULL, ic, TRUE);
9561   freeAsmop (left, NULL, ic, TRUE);
9562   return TRUE;
9563 }
9564 #endif
9565
9566 /*-----------------------------------------------------------------*/
9567 /* genLeftShift - generates code for left shifting                 */
9568 /*-----------------------------------------------------------------*/
9569 static void
9570 genLeftShift (iCode * ic)
9571 {
9572   operand *left, *right, *result;
9573   int size, offset;
9574   char *l;
9575   symbol *tlbl, *tlbl1;
9576   bool pushedB;
9577
9578   D (emitcode (";", "genLeftShift"));
9579
9580   right = IC_RIGHT (ic);
9581   left = IC_LEFT (ic);
9582   result = IC_RESULT (ic);
9583
9584   aopOp (right, ic, FALSE, FALSE);
9585
9586
9587 #ifdef BETTER_LITERAL_SHIFT
9588   /* if the shift count is known then do it
9589      as efficiently as possible */
9590   if (AOP_TYPE (right) == AOP_LIT)
9591     {
9592       if (genLeftShiftLiteral (left, right, result, ic))
9593       {
9594         return;
9595       }
9596     }
9597 #endif
9598
9599   /* shift count is unknown then we have to form
9600      a loop get the loop count in B : Note: we take
9601      only the lower order byte since shifting
9602      more that 32 bits make no sense anyway, ( the
9603      largest size of an object can be only 32 bits ) */
9604
9605   pushedB = pushB ();
9606   if (AOP_TYPE (right) == AOP_LIT)
9607   {
9608       /* Really should be handled by genLeftShiftLiteral,
9609        * but since I'm too lazy to fix that today, at least we can make
9610        * some small improvement.
9611        */
9612        emitcode("mov", "b,#!constbyte",
9613                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9614   }
9615   else
9616   {
9617       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9618       emitcode ("inc", "b");
9619   }
9620   freeAsmop (right, NULL, ic, TRUE);
9621   aopOp (left, ic, FALSE, FALSE);
9622   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9623
9624   /* now move the left to the result if they are not the same */
9625   if (!sameRegs (AOP (left), AOP (result)) &&
9626       AOP_SIZE (result) > 1)
9627     {
9628
9629       size = AOP_SIZE (result);
9630       offset = 0;
9631       _startLazyDPSEvaluation ();
9632       while (size--)
9633         {
9634           l = aopGet (left, offset, FALSE, TRUE, NULL);
9635           if (*l == '@' && (IS_AOP_PREG (result)))
9636             {
9637
9638               emitcode ("mov", "a,%s", l);
9639               aopPut (result, "a", offset);
9640             }
9641           else
9642             aopPut (result, l, offset);
9643           offset++;
9644         }
9645       _endLazyDPSEvaluation ();
9646     }
9647
9648   tlbl = newiTempLabel (NULL);
9649   size = AOP_SIZE (result);
9650   offset = 0;
9651   tlbl1 = newiTempLabel (NULL);
9652
9653   /* if it is only one byte then */
9654   if (size == 1)
9655     {
9656       symbol *tlbl1 = newiTempLabel (NULL);
9657
9658       l = aopGet (left, 0, FALSE, FALSE, NULL);
9659       MOVA (l);
9660       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9661       emitLabel (tlbl);
9662       emitcode ("add", "a,acc");
9663       emitLabel (tlbl1);
9664       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9665       popB (pushedB);
9666       aopPut (result, "a", 0);
9667       goto release;
9668     }
9669
9670   reAdjustPreg (AOP (result));
9671
9672   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9673   emitLabel (tlbl);
9674   l = aopGet (result, offset, FALSE, FALSE, NULL);
9675   MOVA (l);
9676   emitcode ("add", "a,acc");
9677   aopPut (result, "a", offset++);
9678   _startLazyDPSEvaluation ();
9679   while (--size)
9680     {
9681       l = aopGet (result, offset, FALSE, FALSE, NULL);
9682       MOVA (l);
9683       emitcode ("rlc", "a");
9684       aopPut (result, "a", offset++);
9685     }
9686   _endLazyDPSEvaluation ();
9687   reAdjustPreg (AOP (result));
9688
9689   emitLabel (tlbl1);
9690   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9691   popB (pushedB);
9692 release:
9693   freeAsmop (result, NULL, ic, TRUE);
9694   freeAsmop (left, NULL, ic, TRUE);
9695 }
9696
9697 #ifdef BETTER_LITERAL_SHIFT
9698 /*-----------------------------------------------------------------*/
9699 /* genrshOne - right shift a one byte quantity by known count      */
9700 /*-----------------------------------------------------------------*/
9701 static void
9702 genrshOne (operand * result, operand * left,
9703            int shCount, int sign)
9704 {
9705   D (emitcode (";", "genrshOne"));
9706
9707   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9708 }
9709 #endif
9710
9711 #ifdef BETTER_LITERAL_SHIFT
9712 /*-----------------------------------------------------------------*/
9713 /* genrshTwo - right shift two bytes by known amount != 0          */
9714 /*-----------------------------------------------------------------*/
9715 static void
9716 genrshTwo (operand * result, operand * left,
9717            int shCount, int sign)
9718 {
9719   D (emitcode (";", "genrshTwo"));
9720
9721   /* if shCount >= 8 */
9722   if (shCount >= 8)
9723     {
9724       shCount -= 8;
9725       _startLazyDPSEvaluation();
9726       if (shCount)
9727         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9728       else
9729         movLeft2Result (left, MSB16, result, LSB, sign);
9730       addSign (result, MSB16, sign);
9731       _endLazyDPSEvaluation();
9732     }
9733
9734   /*  1 <= shCount <= 7 */
9735   else
9736     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9737 }
9738 #endif
9739
9740 /*-----------------------------------------------------------------*/
9741 /* shiftRLong - shift right one long from left to result           */
9742 /* offl = LSB or MSB16                                             */
9743 /*-----------------------------------------------------------------*/
9744 static void
9745 shiftRLong (operand * left, int offl,
9746             operand * result, int sign)
9747 {
9748   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9749
9750   if (overlapping && offl>1)
9751     {
9752       // we are in big trouble, but this shouldn't happen
9753       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9754     }
9755
9756   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9757
9758   if (offl==MSB16)
9759     {
9760       // shift is > 8
9761       if (sign)
9762         {
9763           emitcode ("rlc", "a");
9764           emitcode ("subb", "a,acc");
9765           emitcode ("xch", "a,%s",
9766                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9767         }
9768       else
9769         {
9770           aopPut (result, zero, MSB32);
9771         }
9772     }
9773
9774   if (!sign)
9775     {
9776       emitcode ("clr", "c");
9777     }
9778   else
9779     {
9780       emitcode ("mov", "c,acc.7");
9781     }
9782
9783   emitcode ("rrc", "a");
9784
9785   if (overlapping && offl==MSB16)
9786     {
9787       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9788     }
9789   else
9790     {
9791       aopPut (result, "a", MSB32 - offl);
9792       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9793     }
9794
9795   emitcode ("rrc", "a");
9796
9797   if (overlapping && offl==MSB16)
9798     {
9799       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9800     }
9801   else
9802     {
9803       aopPut (result, "a", MSB24 - offl);
9804       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9805     }
9806
9807   emitcode ("rrc", "a");
9808   if (offl != LSB)
9809     {
9810       aopPut (result, "a", MSB16 - offl);
9811     }
9812   else
9813     {
9814       if (overlapping && offl==MSB16)
9815         {
9816           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9817         }
9818       else
9819         {
9820           aopPut (result, "a", MSB16 - offl);
9821           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9822         }
9823       emitcode ("rrc", "a");
9824       aopPut (result, "a", LSB);
9825     }
9826 }
9827
9828 /*-----------------------------------------------------------------*/
9829 /* genrshFour - shift four byte by a known amount != 0             */
9830 /*-----------------------------------------------------------------*/
9831 static void
9832 genrshFour (operand * result, operand * left,
9833             int shCount, int sign)
9834 {
9835   D (emitcode (";", "genrshFour"));
9836
9837   /* if shifting more that 3 bytes */
9838   if (shCount >= 24)
9839     {
9840       shCount -= 24;
9841       _startLazyDPSEvaluation();
9842       if (shCount)
9843         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9844       else
9845         movLeft2Result (left, MSB32, result, LSB, sign);
9846       addSign (result, MSB16, sign);
9847       _endLazyDPSEvaluation();
9848     }
9849   else if (shCount >= 16)
9850     {
9851       shCount -= 16;
9852       _startLazyDPSEvaluation();
9853       if (shCount)
9854         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9855       else
9856         {
9857           movLeft2Result (left, MSB24, result, LSB, 0);
9858           movLeft2Result (left, MSB32, result, MSB16, sign);
9859         }
9860       addSign (result, MSB24, sign);
9861       _endLazyDPSEvaluation();
9862     }
9863   else if (shCount >= 8)
9864     {
9865       shCount -= 8;
9866       _startLazyDPSEvaluation();
9867       if (shCount == 1)
9868         {
9869             shiftRLong (left, MSB16, result, sign);
9870         }
9871       else if (shCount == 0)
9872         {
9873           movLeft2Result (left, MSB16, result, LSB, 0);
9874           movLeft2Result (left, MSB24, result, MSB16, 0);
9875           movLeft2Result (left, MSB32, result, MSB24, sign);
9876           addSign (result, MSB32, sign);
9877         }
9878       else
9879         {
9880           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9881           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9882           /* the last shift is signed */
9883           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9884           addSign (result, MSB32, sign);
9885         }
9886         _endLazyDPSEvaluation();
9887     }
9888   else
9889     {
9890       /* 1 <= shCount <= 7 */
9891       if (shCount <= 2)
9892         {
9893           shiftRLong (left, LSB, result, sign);
9894           if (shCount == 2)
9895             shiftRLong (result, LSB, result, sign);
9896         }
9897       else
9898         {
9899           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9900           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9901           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9902         }
9903     }
9904 }
9905
9906 #ifdef BETTER_LITERAL_SHIFT
9907 /*-----------------------------------------------------------------*/
9908 /* genRightShiftLiteral - right shifting by known count            */
9909 /*-----------------------------------------------------------------*/
9910 static bool
9911 genRightShiftLiteral (operand * left,
9912                       operand * right,
9913                       operand * result,
9914                       iCode * ic,
9915                       int sign)
9916 {
9917   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9918   int size;
9919
9920   size = getSize (operandType (result));
9921
9922   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9923
9924   /* We only handle certain easy cases so far. */
9925   if ((shCount != 0)
9926    && (shCount < (size * 8))
9927    && (size != 1)
9928    && (size != 2)
9929    && (size != 4))
9930   {
9931       D(emitcode (";", "genRightShiftLiteral wimping out"););
9932       return FALSE;
9933   }
9934
9935   freeAsmop (right, NULL, ic, TRUE);
9936
9937   aopOp (left, ic, FALSE, FALSE);
9938   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9939
9940 #if VIEW_SIZE
9941   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9942             AOP_SIZE (left));
9943 #endif
9944
9945   /* test the LEFT size !!! */
9946
9947   /* I suppose that the left size >= result size */
9948   if (shCount == 0)
9949   {
9950       size = getDataSize (result);
9951       _startLazyDPSEvaluation();
9952       while (size--)
9953         movLeft2Result (left, size, result, size, 0);
9954       _endLazyDPSEvaluation();
9955   }
9956   else if (shCount >= (size * 8))
9957     {
9958       if (sign)
9959         {
9960           /* get sign in acc.7 */
9961           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9962         }
9963       addSign (result, LSB, sign);
9964     }
9965   else
9966     {
9967       switch (size)
9968         {
9969         case 1:
9970           genrshOne (result, left, shCount, sign);
9971           break;
9972
9973         case 2:
9974           genrshTwo (result, left, shCount, sign);
9975           break;
9976 #if 1
9977         case 4:
9978           genrshFour (result, left, shCount, sign);
9979           break;
9980 #endif
9981         default:
9982           break;
9983         }
9984     }
9985   freeAsmop (result, NULL, ic, TRUE);
9986   freeAsmop (left, NULL, ic, TRUE);
9987
9988   return TRUE;
9989 }
9990 #endif
9991
9992 /*-----------------------------------------------------------------*/
9993 /* genSignedRightShift - right shift of signed number              */
9994 /*-----------------------------------------------------------------*/
9995 static void
9996 genSignedRightShift (iCode * ic)
9997 {
9998   operand *right, *left, *result;
9999   int size, offset;
10000   char *l;
10001   symbol *tlbl, *tlbl1;
10002   bool pushedB;
10003
10004   D (emitcode (";", "genSignedRightShift"));
10005
10006   /* we do it the hard way put the shift count in b
10007      and loop thru preserving the sign */
10008
10009   right = IC_RIGHT (ic);
10010   left = IC_LEFT (ic);
10011   result = IC_RESULT (ic);
10012
10013   aopOp (right, ic, FALSE, FALSE);
10014
10015 #ifdef BETTER_LITERAL_SHIFT
10016   if (AOP_TYPE (right) == AOP_LIT)
10017     {
10018       if (genRightShiftLiteral (left, right, result, ic, 1))
10019       {
10020         return;
10021       }
10022     }
10023 #endif
10024   /* shift count is unknown then we have to form
10025      a loop get the loop count in B : Note: we take
10026      only the lower order byte since shifting
10027      more that 32 bits make no sense anyway, ( the
10028      largest size of an object can be only 32 bits ) */
10029
10030   pushedB = pushB ();
10031   if (AOP_TYPE (right) == AOP_LIT)
10032   {
10033       /* Really should be handled by genRightShiftLiteral,
10034        * but since I'm too lazy to fix that today, at least we can make
10035        * some small improvement.
10036        */
10037        emitcode("mov", "b,#!constbyte",
10038                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10039   }
10040   else
10041   {
10042         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10043         emitcode ("inc", "b");
10044   }
10045   freeAsmop (right, NULL, ic, TRUE);
10046   aopOp (left, ic, FALSE, FALSE);
10047   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10048
10049   /* now move the left to the result if they are not the
10050      same */
10051   if (!sameRegs (AOP (left), AOP (result)) &&
10052       AOP_SIZE (result) > 1)
10053     {
10054
10055       size = AOP_SIZE (result);
10056       offset = 0;
10057       _startLazyDPSEvaluation ();
10058       while (size--)
10059         {
10060           l = aopGet (left, offset, FALSE, TRUE, NULL);
10061           if (*l == '@' && IS_AOP_PREG (result))
10062             {
10063
10064               emitcode ("mov", "a,%s", l);
10065               aopPut (result, "a", offset);
10066             }
10067           else
10068             aopPut (result, l, offset);
10069           offset++;
10070         }
10071       _endLazyDPSEvaluation ();
10072     }
10073
10074   /* mov the highest order bit to OVR */
10075   tlbl = newiTempLabel (NULL);
10076   tlbl1 = newiTempLabel (NULL);
10077
10078   size = AOP_SIZE (result);
10079   offset = size - 1;
10080   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10081   emitcode ("rlc", "a");
10082   emitcode ("mov", "ov,c");
10083   /* if it is only one byte then */
10084   if (size == 1)
10085     {
10086       l = aopGet (left, 0, FALSE, FALSE, NULL);
10087       MOVA (l);
10088       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10089       emitLabel (tlbl);
10090       emitcode ("mov", "c,ov");
10091       emitcode ("rrc", "a");
10092       emitLabel (tlbl1);
10093       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10094       popB (pushedB);
10095       aopPut (result, "a", 0);
10096       goto release;
10097     }
10098
10099   reAdjustPreg (AOP (result));
10100   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10101   emitLabel (tlbl);
10102   emitcode ("mov", "c,ov");
10103   _startLazyDPSEvaluation ();
10104   while (size--)
10105     {
10106       l = aopGet (result, offset, FALSE, FALSE, NULL);
10107       MOVA (l);
10108       emitcode ("rrc", "a");
10109       aopPut (result, "a", offset--);
10110     }
10111   _endLazyDPSEvaluation ();
10112   reAdjustPreg (AOP (result));
10113   emitLabel (tlbl1);
10114   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10115   popB (pushedB);
10116
10117 release:
10118   freeAsmop (result, NULL, ic, TRUE);
10119   freeAsmop (left, NULL, ic, TRUE);
10120 }
10121
10122 /*-----------------------------------------------------------------*/
10123 /* genRightShift - generate code for right shifting                */
10124 /*-----------------------------------------------------------------*/
10125 static void
10126 genRightShift (iCode * ic)
10127 {
10128   operand *right, *left, *result;
10129   sym_link *letype;
10130   int size, offset;
10131   char *l;
10132   symbol *tlbl, *tlbl1;
10133   bool pushedB;
10134
10135   D (emitcode (";", "genRightShift"));
10136
10137   /* if signed then we do it the hard way preserve the
10138      sign bit moving it inwards */
10139   letype = getSpec (operandType (IC_LEFT (ic)));
10140
10141   if (!SPEC_USIGN (letype))
10142     {
10143       genSignedRightShift (ic);
10144       return;
10145     }
10146
10147   /* signed & unsigned types are treated the same : i.e. the
10148      signed is NOT propagated inwards : quoting from the
10149      ANSI - standard : "for E1 >> E2, is equivalent to division
10150      by 2**E2 if unsigned or if it has a non-negative value,
10151      otherwise the result is implementation defined ", MY definition
10152      is that the sign does not get propagated */
10153
10154   right = IC_RIGHT (ic);
10155   left = IC_LEFT (ic);
10156   result = IC_RESULT (ic);
10157
10158   aopOp (right, ic, FALSE, FALSE);
10159
10160 #ifdef BETTER_LITERAL_SHIFT
10161   /* if the shift count is known then do it
10162      as efficiently as possible */
10163   if (AOP_TYPE (right) == AOP_LIT)
10164     {
10165       if (genRightShiftLiteral (left, right, result, ic, 0))
10166       {
10167         return;
10168       }
10169     }
10170 #endif
10171
10172   /* shift count is unknown then we have to form
10173      a loop get the loop count in B : Note: we take
10174      only the lower order byte since shifting
10175      more that 32 bits make no sense anyway, ( the
10176      largest size of an object can be only 32 bits ) */
10177
10178   pushedB = pushB ();
10179   if (AOP_TYPE (right) == AOP_LIT)
10180   {
10181       /* Really should be handled by genRightShiftLiteral,
10182        * but since I'm too lazy to fix that today, at least we can make
10183        * some small improvement.
10184        */
10185        emitcode("mov", "b,#!constbyte",
10186                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10187   }
10188   else
10189   {
10190       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10191       emitcode ("inc", "b");
10192   }
10193   freeAsmop (right, NULL, ic, TRUE);
10194   aopOp (left, ic, FALSE, FALSE);
10195   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10196
10197   /* now move the left to the result if they are not the
10198      same */
10199   if (!sameRegs (AOP (left), AOP (result)) &&
10200       AOP_SIZE (result) > 1)
10201     {
10202       size = AOP_SIZE (result);
10203       offset = 0;
10204       _startLazyDPSEvaluation ();
10205       while (size--)
10206         {
10207           l = aopGet (left, offset, FALSE, TRUE, NULL);
10208           if (*l == '@' && IS_AOP_PREG (result))
10209             {
10210
10211               emitcode ("mov", "a,%s", l);
10212               aopPut (result, "a", offset);
10213             }
10214           else
10215             aopPut (result, l, offset);
10216           offset++;
10217         }
10218       _endLazyDPSEvaluation ();
10219     }
10220
10221   tlbl = newiTempLabel (NULL);
10222   tlbl1 = newiTempLabel (NULL);
10223   size = AOP_SIZE (result);
10224   offset = size - 1;
10225
10226   /* if it is only one byte then */
10227   if (size == 1)
10228     {
10229       l = aopGet (left, 0, FALSE, FALSE, NULL);
10230       MOVA (l);
10231       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10232       emitLabel (tlbl);
10233       CLRC;
10234       emitcode ("rrc", "a");
10235       emitLabel (tlbl1);
10236       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10237       popB (pushedB);
10238       aopPut (result, "a", 0);
10239       goto release;
10240     }
10241
10242   reAdjustPreg (AOP (result));
10243   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10244   emitLabel (tlbl);
10245   CLRC;
10246   _startLazyDPSEvaluation ();
10247   while (size--)
10248     {
10249       l = aopGet (result, offset, FALSE, FALSE, NULL);
10250       MOVA (l);
10251       emitcode ("rrc", "a");
10252       aopPut (result, "a", offset--);
10253     }
10254   _endLazyDPSEvaluation ();
10255   reAdjustPreg (AOP (result));
10256
10257   emitLabel (tlbl1);
10258   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10259   popB (pushedB);
10260
10261 release:
10262   freeAsmop (result, NULL, ic, TRUE);
10263   freeAsmop (left, NULL, ic, TRUE);
10264 }
10265
10266 /*-----------------------------------------------------------------*/
10267 /* emitPtrByteGet - emits code to get a byte into A through a      */
10268 /*                  pointer register (R0, R1, or DPTR). The        */
10269 /*                  original value of A can be preserved in B.     */
10270 /*-----------------------------------------------------------------*/
10271 static void
10272 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10273 {
10274   switch (p_type)
10275     {
10276     case IPOINTER:
10277     case POINTER:
10278       if (preserveAinB)
10279         emitcode ("mov", "b,a");
10280       emitcode ("mov", "a,@%s", rname);
10281       break;
10282
10283     case PPOINTER:
10284       if (preserveAinB)
10285         emitcode ("mov", "b,a");
10286       emitcode ("movx", "a,@%s", rname);
10287       break;
10288
10289     case FPOINTER:
10290       if (preserveAinB)
10291         emitcode ("mov", "b,a");
10292       emitcode ("movx", "a,@dptr");
10293       break;
10294
10295     case CPOINTER:
10296       if (preserveAinB)
10297         emitcode ("mov", "b,a");
10298       emitcode ("clr", "a");
10299       emitcode ("movc", "a,@a+dptr");
10300       break;
10301
10302     case GPOINTER:
10303       if (preserveAinB)
10304         {
10305           emitcode ("push", "b");
10306           emitcode ("push", "acc");
10307         }
10308       emitcode ("lcall", "__gptrget");
10309       if (preserveAinB)
10310         emitcode ("pop", "b");
10311       break;
10312     }
10313 }
10314
10315 /*-----------------------------------------------------------------*/
10316 /* emitPtrByteSet - emits code to set a byte from src through a    */
10317 /*                  pointer register (R0, R1, or DPTR).            */
10318 /*-----------------------------------------------------------------*/
10319 static void
10320 emitPtrByteSet (char *rname, int p_type, char *src)
10321 {
10322   switch (p_type)
10323     {
10324     case IPOINTER:
10325     case POINTER:
10326       if (*src=='@')
10327         {
10328           MOVA (src);
10329           emitcode ("mov", "@%s,a", rname);
10330         }
10331       else
10332         emitcode ("mov", "@%s,%s", rname, src);
10333       break;
10334
10335     case PPOINTER:
10336       MOVA (src);
10337       emitcode ("movx", "@%s,a", rname);
10338       break;
10339
10340     case FPOINTER:
10341       MOVA (src);
10342       emitcode ("movx", "@dptr,a");
10343       break;
10344
10345     case GPOINTER:
10346       MOVA (src);
10347       emitcode ("lcall", "__gptrput");
10348       break;
10349     }
10350 }
10351
10352 /*-----------------------------------------------------------------*/
10353 /* genUnpackBits - generates code for unpacking bits               */
10354 /*-----------------------------------------------------------------*/
10355 static void
10356 genUnpackBits (operand * result, char *rname, int ptype)
10357 {
10358   int offset = 0;       /* result byte offset */
10359   int rsize;            /* result size */
10360   int rlen = 0;         /* remaining bitfield length */
10361   sym_link *etype;      /* bitfield type information */
10362   int blen;             /* bitfield length */
10363   int bstr;             /* bitfield starting bit within byte */
10364
10365   D(emitcode (";     genUnpackBits",""));
10366
10367   etype = getSpec (operandType (result));
10368   rsize = getSize (operandType (result));
10369   blen = SPEC_BLEN (etype);
10370   bstr = SPEC_BSTR (etype);
10371
10372   /* If the bitfield length is less than a byte */
10373   if (blen < 8)
10374     {
10375       emitPtrByteGet (rname, ptype, FALSE);
10376       AccRol (8 - bstr);
10377       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10378       if (!SPEC_USIGN (etype))
10379         {
10380           /* signed bitfield */
10381           symbol *tlbl = newiTempLabel (NULL);
10382
10383           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10384           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10385           emitLabel (tlbl);
10386         }
10387       aopPut (result, "a", offset++);
10388       goto finish;
10389     }
10390
10391   /* Bit field did not fit in a byte. Copy all
10392      but the partial byte at the end.  */
10393   for (rlen=blen;rlen>=8;rlen-=8)
10394     {
10395       emitPtrByteGet (rname, ptype, FALSE);
10396       aopPut (result, "a", offset++);
10397       if (rlen>8)
10398         emitcode ("inc", "%s", rname);
10399     }
10400
10401   /* Handle the partial byte at the end */
10402   if (rlen)
10403     {
10404       emitPtrByteGet (rname, ptype, FALSE);
10405       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10406       if (!SPEC_USIGN (etype))
10407         {
10408           /* signed bitfield */
10409           symbol *tlbl = newiTempLabel (NULL);
10410
10411           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10412           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10413           emitLabel (tlbl);
10414         }
10415       aopPut (result, "a", offset++);
10416     }
10417
10418 finish:
10419   if (offset < rsize)
10420     {
10421       char *source;
10422
10423       if (SPEC_USIGN (etype))
10424         source = zero;
10425       else
10426         {
10427           /* signed bitfield: sign extension with 0x00 or 0xff */
10428           emitcode ("rlc", "a");
10429           emitcode ("subb", "a,acc");
10430
10431           source = "a";
10432         }
10433       rsize -= offset;
10434       while (rsize--)
10435         aopPut (result, source, offset++);
10436     }
10437 }
10438
10439
10440 /*-----------------------------------------------------------------*/
10441 /* genDataPointerGet - generates code when ptr offset is known     */
10442 /*-----------------------------------------------------------------*/
10443 static void
10444 genDataPointerGet (operand * left,
10445                    operand * result,
10446                    iCode * ic)
10447 {
10448   char *l;
10449   char buffer[256];
10450   int size, offset = 0;
10451   aopOp (result, ic, TRUE, FALSE);
10452
10453   /* get the string representation of the name */
10454   l = aopGet (left, 0, FALSE, TRUE, NULL);
10455   size = AOP_SIZE (result);
10456   _startLazyDPSEvaluation ();
10457   while (size--)
10458     {
10459         if (offset)
10460         {
10461             SNPRINTF (buffer, sizeof(buffer),
10462                       "(%s + %d)", l + 1, offset);
10463         }
10464         else
10465         {
10466             SNPRINTF (buffer, sizeof(buffer),
10467                       "%s", l + 1);
10468         }
10469       aopPut (result, buffer, offset++);
10470     }
10471   _endLazyDPSEvaluation ();
10472
10473   freeAsmop (result, NULL, ic, TRUE);
10474   freeAsmop (left, NULL, ic, TRUE);
10475 }
10476
10477 /*-----------------------------------------------------------------*/
10478 /* genNearPointerGet - emitcode for near pointer fetch             */
10479 /*-----------------------------------------------------------------*/
10480 static void
10481 genNearPointerGet (operand * left,
10482                    operand * result,
10483                    iCode * ic,
10484                    iCode *pi)
10485 {
10486   asmop *aop = NULL;
10487   regs *preg;
10488   char *rname;
10489   sym_link *rtype, *retype, *letype;
10490   sym_link *ltype = operandType (left);
10491   char buffer[80];
10492
10493   rtype = operandType (result);
10494   retype = getSpec (rtype);
10495   letype = getSpec (ltype);
10496
10497   aopOp (left, ic, FALSE, FALSE);
10498
10499   /* if left is rematerialisable and
10500      result is not bitfield variable type and
10501      the left is pointer to data space i.e
10502      lower 128 bytes of space */
10503   if (AOP_TYPE (left) == AOP_IMMD &&
10504       !IS_BITFIELD (retype) &&
10505       !IS_BITFIELD (letype) &&
10506       DCL_TYPE (ltype) == POINTER)
10507     {
10508       genDataPointerGet (left, result, ic);
10509       return;
10510     }
10511
10512   /* if the value is already in a pointer register
10513      then don't need anything more */
10514   if (!AOP_INPREG (AOP (left)))
10515     {
10516       /* otherwise get a free pointer register */
10517       aop = newAsmop (0);
10518       preg = getFreePtr (ic, &aop, FALSE);
10519       emitcode ("mov", "%s,%s",
10520                 preg->name,
10521                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10522       rname = preg->name;
10523     }
10524   else
10525     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10526
10527   freeAsmop (left, NULL, ic, TRUE);
10528   aopOp (result, ic, FALSE, FALSE);
10529
10530   /* if bitfield then unpack the bits */
10531   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10532     genUnpackBits (result, rname, POINTER);
10533   else
10534     {
10535       /* we have can just get the values */
10536       int size = AOP_SIZE (result);
10537       int offset = 0;
10538
10539       while (size--)
10540         {
10541           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10542             {
10543
10544               emitcode ("mov", "a,@%s", rname);
10545               aopPut (result, "a", offset);
10546             }
10547           else
10548             {
10549               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10550               aopPut (result, buffer, offset);
10551             }
10552           offset++;
10553           if (size || pi)
10554             emitcode ("inc", "%s", rname);
10555         }
10556     }
10557
10558   /* now some housekeeping stuff */
10559   if (aop)      /* we had to allocate for this iCode */
10560     {
10561       if (pi) { /* post increment present */
10562         aopPut (left, rname, 0);
10563       }
10564       freeAsmop (NULL, aop, ic, TRUE);
10565     }
10566   else
10567     {
10568       /* we did not allocate which means left
10569          already in a pointer register, then
10570          if size > 0 && this could be used again
10571          we have to point it back to where it
10572          belongs */
10573       if (AOP_SIZE (result) > 1 &&
10574           !OP_SYMBOL (left)->remat &&
10575           (OP_SYMBOL (left)->liveTo > ic->seq ||
10576            ic->depth) &&
10577           !pi)
10578         {
10579           int size = AOP_SIZE (result) - 1;
10580           while (size--)
10581             emitcode ("dec", "%s", rname);
10582         }
10583     }
10584
10585   /* done */
10586   freeAsmop (result, NULL, ic, TRUE);
10587   if (pi) pi->generated = 1;
10588 }
10589
10590 /*-----------------------------------------------------------------*/
10591 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10592 /*-----------------------------------------------------------------*/
10593 static void
10594 genPagedPointerGet (operand * left,
10595                     operand * result,
10596                     iCode * ic,
10597                     iCode * pi)
10598 {
10599   asmop *aop = NULL;
10600   regs *preg;
10601   char *rname;
10602   sym_link *rtype, *retype, *letype;
10603
10604   rtype = operandType (result);
10605   retype = getSpec (rtype);
10606   letype = getSpec (operandType (left));
10607   aopOp (left, ic, FALSE, FALSE);
10608
10609   /* if the value is already in a pointer register
10610      then don't need anything more */
10611   if (!AOP_INPREG (AOP (left)))
10612     {
10613       /* otherwise get a free pointer register */
10614       aop = newAsmop (0);
10615       preg = getFreePtr (ic, &aop, FALSE);
10616       emitcode ("mov", "%s,%s",
10617                 preg->name,
10618                 aopGet (left, 0, FALSE, TRUE, NULL));
10619       rname = preg->name;
10620     }
10621   else
10622     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10623
10624   freeAsmop (left, NULL, ic, TRUE);
10625   aopOp (result, ic, FALSE, FALSE);
10626
10627   /* if bitfield then unpack the bits */
10628   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10629     genUnpackBits (result, rname, PPOINTER);
10630   else
10631     {
10632       /* we have can just get the values */
10633       int size = AOP_SIZE (result);
10634       int offset = 0;
10635
10636       while (size--)
10637         {
10638
10639           emitcode ("movx", "a,@%s", rname);
10640           aopPut (result, "a", offset);
10641
10642           offset++;
10643
10644           if (size || pi)
10645             emitcode ("inc", "%s", rname);
10646         }
10647     }
10648
10649   /* now some housekeeping stuff */
10650   if (aop)      /* we had to allocate for this iCode */
10651     {
10652       if (pi)
10653         aopPut (left, rname, 0);
10654       freeAsmop (NULL, aop, ic, TRUE);
10655     }
10656   else
10657     {
10658       /* we did not allocate which means left
10659          already in a pointer register, then
10660          if size > 0 && this could be used again
10661          we have to point it back to where it
10662          belongs */
10663       if (AOP_SIZE (result) > 1 &&
10664           !OP_SYMBOL (left)->remat &&
10665           (OP_SYMBOL (left)->liveTo > ic->seq ||
10666            ic->depth) &&
10667           !pi)
10668         {
10669           int size = AOP_SIZE (result) - 1;
10670           while (size--)
10671             emitcode ("dec", "%s", rname);
10672         }
10673     }
10674
10675   /* done */
10676   freeAsmop (result, NULL, ic, TRUE);
10677   if (pi) pi->generated = 1;
10678 }
10679
10680 /*-----------------------------------------------------------------*/
10681 /* genFarPointerGet - get value from far space                     */
10682 /*-----------------------------------------------------------------*/
10683 static void
10684 genFarPointerGet (operand * left,
10685                   operand * result, iCode * ic, iCode *pi)
10686 {
10687   int size, offset, dopi=1;
10688   sym_link *retype = getSpec (operandType (result));
10689   sym_link *letype = getSpec (operandType (left));
10690   D (emitcode (";", "genFarPointerGet"););
10691
10692   aopOp (left, ic, FALSE, FALSE);
10693
10694   /* if the operand is already in dptr
10695      then we do nothing else we move the value to dptr */
10696   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10697     {
10698       /* if this is rematerializable */
10699       if (AOP_TYPE (left) == AOP_IMMD)
10700         {
10701           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10702         }
10703       else
10704         {
10705           /* we need to get it byte by byte */
10706           _startLazyDPSEvaluation ();
10707           if (AOP_TYPE (left) != AOP_DPTR)
10708             {
10709               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10710               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10711               if (options.model == MODEL_FLAT24)
10712                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10713             }
10714           else
10715             {
10716               /* We need to generate a load to DPTR indirect through DPTR. */
10717               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10718               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10719               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10720               if (options.model == MODEL_FLAT24)
10721                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10722               emitcode ("pop", "dph");
10723               emitcode ("pop", "dpl");
10724               dopi =0;
10725             }
10726           _endLazyDPSEvaluation ();
10727         }
10728     }
10729   /* so dptr now contains the address */
10730   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10731
10732   /* if bit then unpack */
10733   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10734       if (AOP_INDPTRn(left)) {
10735           genSetDPTR(AOP(left)->aopu.dptr);
10736       }
10737       genUnpackBits (result, "dptr", FPOINTER);
10738       if (AOP_INDPTRn(left)) {
10739           genSetDPTR(0);
10740       }
10741   } else
10742     {
10743       size = AOP_SIZE (result);
10744       offset = 0;
10745
10746       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10747           while (size--) {
10748               genSetDPTR(AOP(left)->aopu.dptr);
10749               emitcode ("movx", "a,@dptr");
10750               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10751                   emitcode ("inc", "dptr");
10752               genSetDPTR (0);
10753               aopPut (result, "a", offset++);
10754           }
10755       } else {
10756           _startLazyDPSEvaluation ();
10757           while (size--) {
10758               if (AOP_INDPTRn(left)) {
10759                   genSetDPTR(AOP(left)->aopu.dptr);
10760               } else {
10761                   genSetDPTR (0);
10762               }
10763               _flushLazyDPS ();
10764
10765               emitcode ("movx", "a,@dptr");
10766               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10767                   emitcode ("inc", "dptr");
10768
10769               aopPut (result, "a", offset++);
10770           }
10771           _endLazyDPSEvaluation ();
10772       }
10773     }
10774   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10775       if (!AOP_INDPTRn(left)) {
10776           _startLazyDPSEvaluation ();
10777           aopPut (left, "dpl", 0);
10778           aopPut (left, "dph", 1);
10779           if (options.model == MODEL_FLAT24)
10780               aopPut (left, "dpx", 2);
10781           _endLazyDPSEvaluation ();
10782       }
10783     pi->generated = 1;
10784   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10785              AOP_SIZE(result) > 1 &&
10786              IS_SYMOP(left) &&
10787              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10788
10789       size = AOP_SIZE (result) - 1;
10790       if (AOP_INDPTRn(left)) {
10791           genSetDPTR(AOP(left)->aopu.dptr);
10792       }
10793       while (size--) emitcode ("lcall","__decdptr");
10794       if (AOP_INDPTRn(left)) {
10795           genSetDPTR(0);
10796       }
10797   }
10798
10799   freeAsmop (result, NULL, ic, TRUE);
10800   freeAsmop (left, NULL, ic, TRUE);
10801 }
10802
10803 /*-----------------------------------------------------------------*/
10804 /* genCodePointerGet - get value from code space                   */
10805 /*-----------------------------------------------------------------*/
10806 static void
10807 genCodePointerGet (operand * left,
10808                     operand * result, iCode * ic, iCode *pi)
10809 {
10810   int size, offset, dopi=1;
10811   sym_link *retype = getSpec (operandType (result));
10812
10813   aopOp (left, ic, FALSE, FALSE);
10814
10815   /* if the operand is already in dptr
10816      then we do nothing else we move the value to dptr */
10817   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10818     {
10819       /* if this is rematerializable */
10820       if (AOP_TYPE (left) == AOP_IMMD)
10821         {
10822           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10823         }
10824       else
10825         {                       /* we need to get it byte by byte */
10826           _startLazyDPSEvaluation ();
10827           if (AOP_TYPE (left) != AOP_DPTR)
10828             {
10829               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10830               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10831               if (options.model == MODEL_FLAT24)
10832                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10833             }
10834           else
10835             {
10836               /* We need to generate a load to DPTR indirect through DPTR. */
10837               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10838               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10839               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10840               if (options.model == MODEL_FLAT24)
10841                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10842               emitcode ("pop", "dph");
10843               emitcode ("pop", "dpl");
10844               dopi=0;
10845             }
10846           _endLazyDPSEvaluation ();
10847         }
10848     }
10849   /* so dptr now contains the address */
10850   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10851
10852   /* if bit then unpack */
10853   if (IS_BITFIELD (retype)) {
10854       if (AOP_INDPTRn(left)) {
10855           genSetDPTR(AOP(left)->aopu.dptr);
10856       }
10857       genUnpackBits (result, "dptr", CPOINTER);
10858       if (AOP_INDPTRn(left)) {
10859           genSetDPTR(0);
10860       }
10861   } else
10862     {
10863       size = AOP_SIZE (result);
10864       offset = 0;
10865       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10866           while (size--) {
10867               genSetDPTR(AOP(left)->aopu.dptr);
10868               emitcode ("clr", "a");
10869               emitcode ("movc", "a,@a+dptr");
10870               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10871                   emitcode ("inc", "dptr");
10872               genSetDPTR (0);
10873               aopPut (result, "a", offset++);
10874           }
10875       } else {
10876           _startLazyDPSEvaluation ();
10877           while (size--)
10878               {
10879                   if (AOP_INDPTRn(left)) {
10880                       genSetDPTR(AOP(left)->aopu.dptr);
10881                   } else {
10882                       genSetDPTR (0);
10883                   }
10884                   _flushLazyDPS ();
10885
10886                   emitcode ("clr", "a");
10887                   emitcode ("movc", "a,@a+dptr");
10888                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10889                       emitcode ("inc", "dptr");
10890                   aopPut (result, "a", offset++);
10891               }
10892           _endLazyDPSEvaluation ();
10893       }
10894     }
10895   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10896       if (!AOP_INDPTRn(left)) {
10897           _startLazyDPSEvaluation ();
10898
10899           aopPut (left, "dpl", 0);
10900           aopPut (left, "dph", 1);
10901           if (options.model == MODEL_FLAT24)
10902               aopPut (left, "dpx", 2);
10903
10904           _endLazyDPSEvaluation ();
10905       }
10906       pi->generated = 1;
10907   } else if (IS_SYMOP(left) &&
10908              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10909              AOP_SIZE(result) > 1 &&
10910              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10911
10912       size = AOP_SIZE (result) - 1;
10913       if (AOP_INDPTRn(left)) {
10914           genSetDPTR(AOP(left)->aopu.dptr);
10915       }
10916       while (size--) emitcode ("lcall","__decdptr");
10917       if (AOP_INDPTRn(left)) {
10918           genSetDPTR(0);
10919       }
10920   }
10921
10922   freeAsmop (result, NULL, ic, TRUE);
10923   freeAsmop (left, NULL, ic, TRUE);
10924 }
10925
10926 /*-----------------------------------------------------------------*/
10927 /* genGenPointerGet - get value from generic pointer space         */
10928 /*-----------------------------------------------------------------*/
10929 static void
10930 genGenPointerGet (operand * left,
10931                   operand * result, iCode * ic, iCode * pi)
10932 {
10933   int size, offset;
10934   bool pushedB;
10935   sym_link *retype = getSpec (operandType (result));
10936   sym_link *letype = getSpec (operandType (left));
10937
10938   D (emitcode (";", "genGenPointerGet"));
10939
10940   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10941
10942   pushedB = pushB ();
10943   /* if the operand is already in dptr
10944      then we do nothing else we move the value to dptr */
10945   if (AOP_TYPE (left) != AOP_STR)
10946     {
10947       /* if this is rematerializable */
10948       if (AOP_TYPE (left) == AOP_IMMD)
10949         {
10950           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10951           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10952             {
10953               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10954             }
10955           else
10956             {
10957               emitcode ("mov", "b,#%d", pointerCode (retype));
10958             }
10959         }
10960       else
10961         {                       /* we need to get it byte by byte */
10962           _startLazyDPSEvaluation ();
10963           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10964           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10965           if (options.model == MODEL_FLAT24) {
10966               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10967               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10968           } else {
10969               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10970           }
10971           _endLazyDPSEvaluation ();
10972         }
10973     }
10974
10975   /* so dptr-b now contains the address */
10976   aopOp (result, ic, FALSE, TRUE);
10977
10978   /* if bit then unpack */
10979   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10980   {
10981     genUnpackBits (result, "dptr", GPOINTER);
10982   }
10983   else
10984     {
10985         size = AOP_SIZE (result);
10986         offset = 0;
10987
10988         while (size--)
10989         {
10990             if (size)
10991             {
10992                 // Get two bytes at a time, results in _AP & A.
10993                 // dptr will be incremented ONCE by __gptrgetWord.
10994                 //
10995                 // Note: any change here must be coordinated
10996                 // with the implementation of __gptrgetWord
10997                 // in device/lib/_gptrget.c
10998                 emitcode ("lcall", "__gptrgetWord");
10999                 aopPut (result, DP2_RESULT_REG, offset++);
11000                 aopPut (result, "a", offset++);
11001                 size--;
11002             }
11003             else
11004             {
11005                 // Only one byte to get.
11006                 emitcode ("lcall", "__gptrget");
11007                 aopPut (result, "a", offset++);
11008             }
11009
11010             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11011             {
11012                 emitcode ("inc", "dptr");
11013             }
11014         }
11015     }
11016
11017   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11018     _startLazyDPSEvaluation ();
11019
11020     aopPut (left, "dpl", 0);
11021     aopPut (left, "dph", 1);
11022     if (options.model == MODEL_FLAT24) {
11023         aopPut (left, "dpx", 2);
11024         aopPut (left, "b", 3);
11025     } else  aopPut (left, "b", 2);
11026
11027     _endLazyDPSEvaluation ();
11028
11029     pi->generated = 1;
11030   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11031              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11032
11033       size = AOP_SIZE (result) - 1;
11034       while (size--) emitcode ("lcall","__decdptr");
11035   }
11036   popB (pushedB);
11037
11038   freeAsmop (result, NULL, ic, TRUE);
11039   freeAsmop (left, NULL, ic, TRUE);
11040 }
11041
11042 /*-----------------------------------------------------------------*/
11043 /* genPointerGet - generate code for pointer get                   */
11044 /*-----------------------------------------------------------------*/
11045 static void
11046 genPointerGet (iCode * ic, iCode *pi)
11047 {
11048   operand *left, *result;
11049   sym_link *type, *etype;
11050   int p_type;
11051
11052   D (emitcode (";", "genPointerGet"));
11053
11054   left = IC_LEFT (ic);
11055   result = IC_RESULT (ic);
11056
11057   /* depending on the type of pointer we need to
11058      move it to the correct pointer register */
11059   type = operandType (left);
11060   etype = getSpec (type);
11061   /* if left is of type of pointer then it is simple */
11062   if (IS_PTR (type) && !IS_FUNC (type->next))
11063     p_type = DCL_TYPE (type);
11064   else
11065     {
11066       /* we have to go by the storage class */
11067       p_type = PTR_TYPE (SPEC_OCLS (etype));
11068     }
11069
11070   /* special case when cast remat */
11071   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11072       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11073     {
11074       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11075       type = operandType (left);
11076       p_type = DCL_TYPE (type);
11077     }
11078   /* now that we have the pointer type we assign
11079      the pointer values */
11080   switch (p_type)
11081     {
11082
11083     case POINTER:
11084     case IPOINTER:
11085       genNearPointerGet (left, result, ic, pi);
11086       break;
11087
11088     case PPOINTER:
11089       genPagedPointerGet (left, result, ic, pi);
11090       break;
11091
11092     case FPOINTER:
11093       genFarPointerGet (left, result, ic, pi);
11094       break;
11095
11096     case CPOINTER:
11097       genCodePointerGet (left, result, ic, pi);
11098       break;
11099
11100     case GPOINTER:
11101       genGenPointerGet (left, result, ic, pi);
11102       break;
11103     }
11104 }
11105
11106
11107 /*-----------------------------------------------------------------*/
11108 /* genPackBits - generates code for packed bit storage             */
11109 /*-----------------------------------------------------------------*/
11110 static void
11111 genPackBits (sym_link * etype,
11112              operand * right,
11113              char *rname, int p_type)
11114 {
11115   int offset = 0;       /* source byte offset */
11116   int rlen = 0;         /* remaining bitfield length */
11117   int blen;             /* bitfield length */
11118   int bstr;             /* bitfield starting bit within byte */
11119   int litval;           /* source literal value (if AOP_LIT) */
11120   unsigned char mask;   /* bitmask within current byte */
11121
11122   D(emitcode (";     genPackBits",""));
11123
11124   blen = SPEC_BLEN (etype);
11125   bstr = SPEC_BSTR (etype);
11126
11127   /* If the bitfield length is less than a byte */
11128   if (blen < 8)
11129     {
11130       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11131               (unsigned char) (0xFF >> (8 - bstr)));
11132
11133       if (AOP_TYPE (right) == AOP_LIT)
11134         {
11135           /* Case with a bitfield length <8 and literal source
11136           */
11137           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11138           litval <<= bstr;
11139           litval &= (~mask) & 0xff;
11140           emitPtrByteGet (rname, p_type, FALSE);
11141           if ((mask|litval)!=0xff)
11142             emitcode ("anl","a,#!constbyte", mask);
11143           if (litval)
11144             emitcode ("orl","a,#!constbyte", litval);
11145         }
11146       else
11147         {
11148           if ((blen==1) && (p_type!=GPOINTER))
11149             {
11150               /* Case with a bitfield length == 1 and no generic pointer
11151               */
11152               if (AOP_TYPE (right) == AOP_CRY)
11153                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11154               else
11155                 {
11156                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11157                   emitcode ("rrc","a");
11158                 }
11159               emitPtrByteGet (rname, p_type, FALSE);
11160               emitcode ("mov","acc.%d,c",bstr);
11161             }
11162           else
11163             {
11164               bool pushedB;
11165               /* Case with a bitfield length < 8 and arbitrary source
11166               */
11167               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11168               /* shift and mask source value */
11169               AccLsh (bstr);
11170               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11171
11172               pushedB = pushB ();
11173               /* transfer A to B and get next byte */
11174               emitPtrByteGet (rname, p_type, TRUE);
11175
11176               emitcode ("anl", "a,#!constbyte", mask);
11177               emitcode ("orl", "a,b");
11178               if (p_type == GPOINTER)
11179                 emitcode ("pop", "b");
11180
11181               popB (pushedB);
11182            }
11183         }
11184
11185       emitPtrByteSet (rname, p_type, "a");
11186       return;
11187     }
11188
11189   /* Bit length is greater than 7 bits. In this case, copy  */
11190   /* all except the partial byte at the end                 */
11191   for (rlen=blen;rlen>=8;rlen-=8)
11192     {
11193       emitPtrByteSet (rname, p_type,
11194                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11195       if (rlen>8)
11196         emitcode ("inc", "%s", rname);
11197     }
11198
11199   /* If there was a partial byte at the end */
11200   if (rlen)
11201     {
11202       mask = (((unsigned char) -1 << rlen) & 0xff);
11203
11204       if (AOP_TYPE (right) == AOP_LIT)
11205         {
11206           /* Case with partial byte and literal source
11207           */
11208           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11209           litval >>= (blen-rlen);
11210           litval &= (~mask) & 0xff;
11211           emitPtrByteGet (rname, p_type, FALSE);
11212           if ((mask|litval)!=0xff)
11213             emitcode ("anl","a,#!constbyte", mask);
11214           if (litval)
11215             emitcode ("orl","a,#!constbyte", litval);
11216         }
11217       else
11218         {
11219           bool pushedB;
11220           /* Case with partial byte and arbitrary source
11221           */
11222           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11223           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11224
11225           pushedB = pushB ();
11226           /* transfer A to B and get next byte */
11227           emitPtrByteGet (rname, p_type, TRUE);
11228
11229           emitcode ("anl", "a,#!constbyte", mask);
11230           emitcode ("orl", "a,b");
11231           if (p_type == GPOINTER)
11232             emitcode ("pop", "b");
11233
11234           popB (pushedB);
11235         }
11236       emitPtrByteSet (rname, p_type, "a");
11237     }
11238 }
11239
11240
11241 /*-----------------------------------------------------------------*/
11242 /* genDataPointerSet - remat pointer to data space                 */
11243 /*-----------------------------------------------------------------*/
11244 static void
11245 genDataPointerSet (operand * right,
11246                    operand * result,
11247                    iCode * ic)
11248 {
11249   int size, offset = 0;
11250   char *l, buffer[256];
11251
11252   D (emitcode (";", "genDataPointerSet"));
11253
11254   aopOp (right, ic, FALSE, FALSE);
11255
11256   l = aopGet (result, 0, FALSE, TRUE, NULL);
11257   size = AOP_SIZE (right);
11258   while (size--)
11259     {
11260       if (offset)
11261           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11262       else
11263           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11264       emitcode ("mov", "%s,%s", buffer,
11265                 aopGet (right, offset++, FALSE, FALSE, NULL));
11266     }
11267
11268   freeAsmop (result, NULL, ic, TRUE);
11269   freeAsmop (right, NULL, ic, TRUE);
11270 }
11271
11272 /*-----------------------------------------------------------------*/
11273 /* genNearPointerSet - emitcode for near pointer put                */
11274 /*-----------------------------------------------------------------*/
11275 static void
11276 genNearPointerSet (operand * right,
11277                    operand * result,
11278                    iCode * ic,
11279                    iCode * pi)
11280 {
11281   asmop *aop = NULL;
11282   char *rname, *l;
11283   sym_link *retype, *letype;
11284   sym_link *ptype = operandType (result);
11285
11286   D (emitcode (";", "genNearPointerSet"));
11287
11288   retype = getSpec (operandType (right));
11289   letype = getSpec (ptype);
11290
11291   aopOp (result, ic, FALSE, FALSE);
11292
11293   /* if the result is rematerializable &
11294      in data space & not a bit variable */
11295   if (AOP_TYPE (result) == AOP_IMMD &&
11296       DCL_TYPE (ptype) == POINTER &&
11297       !IS_BITVAR (retype) &&
11298       !IS_BITVAR (letype))
11299     {
11300       genDataPointerSet (right, result, ic);
11301       return;
11302     }
11303
11304   /* if the value is already in a pointer register
11305      then don't need anything more */
11306   if (!AOP_INPREG (AOP (result)))
11307     {
11308       /* otherwise get a free pointer register */
11309       regs *preg;
11310
11311       aop = newAsmop (0);
11312       preg = getFreePtr (ic, &aop, FALSE);
11313       emitcode ("mov", "%s,%s",
11314                 preg->name,
11315                 aopGet (result, 0, FALSE, TRUE, NULL));
11316       rname = preg->name;
11317     }
11318   else
11319     {
11320       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11321     }
11322
11323   aopOp (right, ic, FALSE, FALSE);
11324
11325   /* if bitfield then unpack the bits */
11326   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11327     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11328   else
11329     {
11330       /* we can just get the values */
11331       int size = AOP_SIZE (right);
11332       int offset = 0;
11333
11334       while (size--)
11335         {
11336           l = aopGet (right, offset, FALSE, TRUE, NULL);
11337           if ((*l == '@') || (strcmp (l, "acc") == 0))
11338             {
11339               MOVA (l);
11340               emitcode ("mov", "@%s,a", rname);
11341             }
11342           else
11343             emitcode ("mov", "@%s,%s", rname, l);
11344           if (size || pi)
11345             emitcode ("inc", "%s", rname);
11346           offset++;
11347         }
11348     }
11349
11350   /* now some housekeeping stuff */
11351   if (aop)      /* we had to allocate for this iCode */
11352     {
11353       if (pi)
11354         aopPut (result, rname, 0);
11355       freeAsmop (NULL, aop, ic, TRUE);
11356     }
11357   else
11358     {
11359       /* we did not allocate which means left
11360          already in a pointer register, then
11361          if size > 0 && this could be used again
11362          we have to point it back to where it
11363          belongs */
11364       if (AOP_SIZE (right) > 1 &&
11365           !OP_SYMBOL (result)->remat &&
11366           (OP_SYMBOL (result)->liveTo > ic->seq ||
11367            ic->depth) &&
11368           !pi)
11369         {
11370           int size = AOP_SIZE (right) - 1;
11371           while (size--)
11372             emitcode ("dec", "%s", rname);
11373         }
11374     }
11375
11376   /* done */
11377   if (pi) pi->generated = 1;
11378   freeAsmop (result, NULL, ic, TRUE);
11379   freeAsmop (right, NULL, ic, TRUE);
11380 }
11381
11382 /*-----------------------------------------------------------------*/
11383 /* genPagedPointerSet - emitcode for Paged pointer put             */
11384 /*-----------------------------------------------------------------*/
11385 static void
11386 genPagedPointerSet (operand * right,
11387                     operand * result,
11388                     iCode * ic,
11389                     iCode *pi)
11390 {
11391   asmop *aop = NULL;
11392   char *rname, *l;
11393   sym_link *retype, *letype;
11394
11395   D (emitcode (";", "genPagedPointerSet"));
11396
11397   retype = getSpec (operandType (right));
11398   letype = getSpec (operandType (result));
11399
11400   aopOp (result, ic, FALSE, FALSE);
11401
11402   /* if the value is already in a pointer register
11403      then don't need anything more */
11404   if (!AOP_INPREG (AOP (result)))
11405     {
11406       /* otherwise get a free pointer register */
11407       regs *preg;
11408
11409       aop = newAsmop (0);
11410       preg = getFreePtr (ic, &aop, FALSE);
11411       emitcode ("mov", "%s,%s",
11412                 preg->name,
11413                 aopGet (result, 0, FALSE, TRUE, NULL));
11414       rname = preg->name;
11415     }
11416   else
11417     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11418
11419   aopOp (right, ic, FALSE, FALSE);
11420
11421   /* if bitfield then unpack the bits */
11422   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11423     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11424   else
11425     {
11426       /* we have can just get the values */
11427       int size = AOP_SIZE (right);
11428       int offset = 0;
11429
11430       while (size--)
11431         {
11432           l = aopGet (right, offset, FALSE, TRUE, NULL);
11433           MOVA (l);
11434           emitcode ("movx", "@%s,a", rname);
11435
11436           if (size || pi)
11437             emitcode ("inc", "%s", rname);
11438
11439           offset++;
11440         }
11441     }
11442
11443   /* now some housekeeping stuff */
11444   if (aop)
11445     {
11446       if (pi)
11447         aopPut (result, rname, 0);
11448       /* we had to allocate for this iCode */
11449       freeAsmop (NULL, aop, ic, TRUE);
11450     }
11451   else
11452     {
11453       /* we did not allocate which means left
11454          already in a pointer register, then
11455          if size > 0 && this could be used again
11456          we have to point it back to where it
11457          belongs */
11458       if (AOP_SIZE (right) > 1 &&
11459           !OP_SYMBOL (result)->remat &&
11460           (OP_SYMBOL (result)->liveTo > ic->seq ||
11461            ic->depth) &&
11462           !pi)
11463         {
11464           int size = AOP_SIZE (right) - 1;
11465           while (size--)
11466             emitcode ("dec", "%s", rname);
11467         }
11468     }
11469
11470   /* done */
11471   if (pi) pi->generated = 1;
11472   freeAsmop (result, NULL, ic, TRUE);
11473   freeAsmop (right, NULL, ic, TRUE);
11474 }
11475
11476 /*-----------------------------------------------------------------*/
11477 /* genFarPointerSet - set value from far space                     */
11478 /*-----------------------------------------------------------------*/
11479 static void
11480 genFarPointerSet (operand * right,
11481                   operand * result, iCode * ic, iCode *pi)
11482 {
11483   int size, offset, dopi=1;
11484   sym_link *retype = getSpec (operandType (right));
11485   sym_link *letype = getSpec (operandType (result));
11486
11487   aopOp (result, ic, FALSE, FALSE);
11488
11489   /* if the operand is already in dptr
11490      then we do nothing else we move the value to dptr */
11491   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11492     {
11493       /* if this is remateriazable */
11494       if (AOP_TYPE (result) == AOP_IMMD)
11495         emitcode ("mov", "dptr,%s",
11496                   aopGet (result, 0, TRUE, FALSE, NULL));
11497       else
11498         {
11499           /* we need to get it byte by byte */
11500           _startLazyDPSEvaluation ();
11501           if (AOP_TYPE (result) != AOP_DPTR)
11502             {
11503               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11504               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11505               if (options.model == MODEL_FLAT24)
11506                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11507             }
11508           else
11509             {
11510               /* We need to generate a load to DPTR indirect through DPTR. */
11511               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11512
11513               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11514               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11515               if (options.model == MODEL_FLAT24)
11516                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11517               emitcode ("pop", "dph");
11518               emitcode ("pop", "dpl");
11519               dopi=0;
11520             }
11521           _endLazyDPSEvaluation ();
11522         }
11523     }
11524   /* so dptr now contains the address */
11525   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11526
11527   /* if bit then unpack */
11528   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11529   {
11530       if (AOP_INDPTRn(result)) {
11531           genSetDPTR(AOP(result)->aopu.dptr);
11532       }
11533       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11534       if (AOP_INDPTRn(result)) {
11535           genSetDPTR(0);
11536       }
11537   } else {
11538       size = AOP_SIZE (right);
11539       offset = 0;
11540       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11541           while (size--) {
11542               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11543
11544               genSetDPTR(AOP(result)->aopu.dptr);
11545               emitcode ("movx", "@dptr,a");
11546               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11547                   emitcode ("inc", "dptr");
11548               genSetDPTR (0);
11549           }
11550       } else {
11551           _startLazyDPSEvaluation ();
11552           while (size--) {
11553               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11554
11555               if (AOP_INDPTRn(result)) {
11556                   genSetDPTR(AOP(result)->aopu.dptr);
11557               } else {
11558                   genSetDPTR (0);
11559               }
11560               _flushLazyDPS ();
11561
11562               emitcode ("movx", "@dptr,a");
11563               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11564                   emitcode ("inc", "dptr");
11565           }
11566           _endLazyDPSEvaluation ();
11567       }
11568   }
11569
11570   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11571       if (!AOP_INDPTRn(result)) {
11572           _startLazyDPSEvaluation ();
11573
11574           aopPut (result,"dpl",0);
11575           aopPut (result,"dph",1);
11576           if (options.model == MODEL_FLAT24)
11577               aopPut (result,"dpx",2);
11578
11579           _endLazyDPSEvaluation ();
11580       }
11581       pi->generated=1;
11582   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11583              AOP_SIZE(right) > 1 &&
11584              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11585
11586       size = AOP_SIZE (right) - 1;
11587       if (AOP_INDPTRn(result)) {
11588           genSetDPTR(AOP(result)->aopu.dptr);
11589       }
11590       while (size--) emitcode ("lcall","__decdptr");
11591       if (AOP_INDPTRn(result)) {
11592           genSetDPTR(0);
11593       }
11594   }
11595   freeAsmop (result, NULL, ic, TRUE);
11596   freeAsmop (right, NULL, ic, TRUE);
11597 }
11598
11599 /*-----------------------------------------------------------------*/
11600 /* genGenPointerSet - set value from generic pointer space         */
11601 /*-----------------------------------------------------------------*/
11602 static void
11603 genGenPointerSet (operand * right,
11604                   operand * result, iCode * ic, iCode *pi)
11605 {
11606   int size, offset;
11607   bool pushedB;
11608   sym_link *retype = getSpec (operandType (right));
11609   sym_link *letype = getSpec (operandType (result));
11610
11611   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11612
11613   pushedB = pushB ();
11614   /* if the operand is already in dptr
11615      then we do nothing else we move the value to dptr */
11616   if (AOP_TYPE (result) != AOP_STR)
11617     {
11618       _startLazyDPSEvaluation ();
11619       /* if this is remateriazable */
11620       if (AOP_TYPE (result) == AOP_IMMD)
11621         {
11622           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11623           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11624           {
11625               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11626           }
11627           else
11628           {
11629               emitcode ("mov",
11630                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11631           }
11632         }
11633       else
11634         {                       /* we need to get it byte by byte */
11635           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11636           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11637           if (options.model == MODEL_FLAT24) {
11638             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11639             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11640           } else {
11641             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11642           }
11643         }
11644       _endLazyDPSEvaluation ();
11645     }
11646   /* so dptr + b now contains the address */
11647   aopOp (right, ic, FALSE, TRUE);
11648
11649   /* if bit then unpack */
11650   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11651     {
11652         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11653     }
11654   else
11655     {
11656         size = AOP_SIZE (right);
11657         offset = 0;
11658
11659         _startLazyDPSEvaluation ();
11660         while (size--)
11661         {
11662             if (size)
11663             {
11664                 // Set two bytes at a time, passed in _AP & A.
11665                 // dptr will be incremented ONCE by __gptrputWord.
11666                 //
11667                 // Note: any change here must be coordinated
11668                 // with the implementation of __gptrputWord
11669                 // in device/lib/_gptrput.c
11670                 emitcode("mov", "_ap, %s",
11671                          aopGet (right, offset++, FALSE, FALSE, NULL));
11672                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11673
11674                 genSetDPTR (0);
11675                 _flushLazyDPS ();
11676                 emitcode ("lcall", "__gptrputWord");
11677                 size--;
11678             }
11679             else
11680             {
11681                 // Only one byte to put.
11682                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11683
11684                 genSetDPTR (0);
11685                 _flushLazyDPS ();
11686                 emitcode ("lcall", "__gptrput");
11687             }
11688
11689             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11690             {
11691                 emitcode ("inc", "dptr");
11692             }
11693         }
11694         _endLazyDPSEvaluation ();
11695     }
11696
11697   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11698       _startLazyDPSEvaluation ();
11699
11700       aopPut (result, "dpl",0);
11701       aopPut (result, "dph",1);
11702       if (options.model == MODEL_FLAT24) {
11703           aopPut (result, "dpx",2);
11704           aopPut (result, "b",3);
11705       } else {
11706           aopPut (result, "b",2);
11707       }
11708       _endLazyDPSEvaluation ();
11709
11710       pi->generated=1;
11711   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11712              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11713
11714       size = AOP_SIZE (right) - 1;
11715       while (size--) emitcode ("lcall","__decdptr");
11716   }
11717   popB (pushedB);
11718
11719   freeAsmop (result, NULL, ic, TRUE);
11720   freeAsmop (right, NULL, ic, TRUE);
11721 }
11722
11723 /*-----------------------------------------------------------------*/
11724 /* genPointerSet - stores the value into a pointer location        */
11725 /*-----------------------------------------------------------------*/
11726 static void
11727 genPointerSet (iCode * ic, iCode *pi)
11728 {
11729   operand *right, *result;
11730   sym_link *type, *etype;
11731   int p_type;
11732
11733   D (emitcode (";", "genPointerSet"));
11734
11735   right = IC_RIGHT (ic);
11736   result = IC_RESULT (ic);
11737
11738   /* depending on the type of pointer we need to
11739      move it to the correct pointer register */
11740   type = operandType (result);
11741   etype = getSpec (type);
11742   /* if left is of type of pointer then it is simple */
11743   if (IS_PTR (type) && !IS_FUNC (type->next))
11744     {
11745       p_type = DCL_TYPE (type);
11746     }
11747   else
11748     {
11749       /* we have to go by the storage class */
11750       p_type = PTR_TYPE (SPEC_OCLS (etype));
11751     }
11752
11753   /* special case when cast remat */
11754   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11755       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11756           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11757           type = operandType (result);
11758           p_type = DCL_TYPE (type);
11759   }
11760
11761   /* now that we have the pointer type we assign
11762      the pointer values */
11763   switch (p_type)
11764     {
11765
11766     case POINTER:
11767     case IPOINTER:
11768       genNearPointerSet (right, result, ic, pi);
11769       break;
11770
11771     case PPOINTER:
11772       genPagedPointerSet (right, result, ic, pi);
11773       break;
11774
11775     case FPOINTER:
11776       genFarPointerSet (right, result, ic, pi);
11777       break;
11778
11779     case GPOINTER:
11780       genGenPointerSet (right, result, ic, pi);
11781       break;
11782
11783     default:
11784       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11785               "genPointerSet: illegal pointer type");
11786     }
11787 }
11788
11789 /*-----------------------------------------------------------------*/
11790 /* genIfx - generate code for Ifx statement                        */
11791 /*-----------------------------------------------------------------*/
11792 static void
11793 genIfx (iCode * ic, iCode * popIc)
11794 {
11795   operand *cond = IC_COND (ic);
11796   int isbit = 0;
11797   char *dup = NULL;
11798
11799   D (emitcode (";", "genIfx"));
11800
11801   aopOp (cond, ic, FALSE, FALSE);
11802
11803   /* get the value into acc */
11804   if (AOP_TYPE (cond) != AOP_CRY)
11805     {
11806       toBoolean (cond);
11807     }
11808   else
11809     {
11810       isbit = 1;
11811       if (AOP(cond)->aopu.aop_dir)
11812         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11813     }
11814
11815   /* the result is now in the accumulator or a directly addressable bit */
11816   freeAsmop (cond, NULL, ic, TRUE);
11817
11818   /* if there was something to be popped then do it */
11819   if (popIc)
11820     genIpop (popIc);
11821
11822   /* if the condition is a bit variable */
11823   if (isbit && dup)
11824     genIfxJump (ic, dup);
11825   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11826     genIfxJump (ic, SPIL_LOC (cond)->rname);
11827   else if (isbit && !IS_ITEMP (cond))
11828     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11829   else
11830     genIfxJump (ic, "a");
11831
11832   ic->generated = 1;
11833 }
11834
11835 /*-----------------------------------------------------------------*/
11836 /* genAddrOf - generates code for address of                       */
11837 /*-----------------------------------------------------------------*/
11838 static void
11839 genAddrOf (iCode * ic)
11840 {
11841   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11842   int size, offset;
11843
11844   D (emitcode (";", "genAddrOf"));
11845
11846   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11847
11848   /* if the operand is on the stack then we
11849      need to get the stack offset of this
11850      variable */
11851   if (sym->onStack)
11852   {
11853
11854       /* if 10 bit stack */
11855       if (options.stack10bit) {
11856           char buff[10];
11857           int  offset;
11858
11859           tsprintf(buff, sizeof(buff),
11860                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11861           /* if it has an offset then we need to compute it */
11862 /*        emitcode ("subb", "a,#!constbyte", */
11863 /*                  -((sym->stack < 0) ? */
11864 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11865 /*                    ((short) sym->stack)) & 0xff); */
11866 /*        emitcode ("mov","b,a"); */
11867 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11868 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11869 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11870           if (sym->stack) {
11871               emitcode ("mov", "a,_bpx");
11872               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11873                                              ((char) (sym->stack - _G.nRegsSaved)) :
11874                                              ((char) sym->stack )) & 0xff);
11875               emitcode ("mov", "b,a");
11876               emitcode ("mov", "a,_bpx+1");
11877
11878               offset = (((sym->stack < 0) ?
11879                          ((short) (sym->stack - _G.nRegsSaved)) :
11880                          ((short) sym->stack )) >> 8) & 0xff;
11881
11882               emitcode ("addc","a,#!constbyte", offset);
11883
11884               aopPut (IC_RESULT (ic), "b", 0);
11885               aopPut (IC_RESULT (ic), "a", 1);
11886               aopPut (IC_RESULT (ic), buff, 2);
11887           } else {
11888               /* we can just move _bp */
11889               aopPut (IC_RESULT (ic), "_bpx", 0);
11890               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11891               aopPut (IC_RESULT (ic), buff, 2);
11892           }
11893       } else {
11894           /* if it has an offset then we need to compute it */
11895           if (sym->stack)
11896             {
11897               emitcode ("mov", "a,_bp");
11898               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11899               aopPut (IC_RESULT (ic), "a", 0);
11900             }
11901           else
11902             {
11903               /* we can just move _bp */
11904               aopPut (IC_RESULT (ic), "_bp", 0);
11905             }
11906           /* fill the result with zero */
11907           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11908
11909
11910           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11911               fprintf (stderr,
11912                        "*** warning: pointer to stack var truncated.\n");
11913           }
11914
11915           offset = 1;
11916           while (size--)
11917             {
11918               aopPut (IC_RESULT (ic), zero, offset++);
11919             }
11920       }
11921       goto release;
11922   }
11923
11924   /* object not on stack then we need the name */
11925   size = AOP_SIZE (IC_RESULT (ic));
11926   offset = 0;
11927
11928   while (size--)
11929     {
11930       char s[SDCC_NAME_MAX];
11931       if (offset) {
11932           switch (offset) {
11933           case 1:
11934               tsprintf(s, sizeof(s), "#!his",sym->rname);
11935               break;
11936           case 2:
11937               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11938               break;
11939           case 3:
11940               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11941               break;
11942           default: /* should not need this (just in case) */
11943               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11944                        sym->rname,
11945                        offset * 8);
11946           }
11947       }
11948       else
11949       {
11950           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11951       }
11952
11953       aopPut (IC_RESULT (ic), s, offset++);
11954     }
11955
11956 release:
11957   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11958
11959 }
11960
11961 #if 0 // obsolete, and buggy for != xdata
11962 /*-----------------------------------------------------------------*/
11963 /* genArrayInit - generates code for address of                       */
11964 /*-----------------------------------------------------------------*/
11965 static void
11966 genArrayInit (iCode * ic)
11967 {
11968     literalList *iLoop;
11969     int         ix, count;
11970     int         elementSize = 0, eIndex;
11971     unsigned    val, lastVal;
11972     sym_link    *type;
11973     operand     *left=IC_LEFT(ic);
11974
11975     D (emitcode (";", "genArrayInit"));
11976
11977     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11978
11979     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11980     {
11981         // Load immediate value into DPTR.
11982         emitcode("mov", "dptr, %s",
11983              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11984     }
11985     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11986     {
11987 #if 0
11988       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11989               "Unexpected operand to genArrayInit.\n");
11990       exit(1);
11991 #else
11992       // a regression because of SDCCcse.c:1.52
11993       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11994       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11995       if (options.model == MODEL_FLAT24)
11996         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11997 #endif
11998     }
11999
12000     type = operandType(IC_LEFT(ic));
12001
12002     if (type && type->next)
12003     {
12004         elementSize = getSize(type->next);
12005     }
12006     else
12007     {
12008         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12009                                 "can't determine element size in genArrayInit.\n");
12010         exit(1);
12011     }
12012
12013     iLoop = IC_ARRAYILIST(ic);
12014     lastVal = 0xffff;
12015
12016     while (iLoop)
12017     {
12018         bool firstpass = TRUE;
12019
12020         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12021                  iLoop->count, (int)iLoop->literalValue, elementSize);
12022
12023         ix = iLoop->count;
12024
12025         while (ix)
12026         {
12027             symbol *tlbl = NULL;
12028
12029             count = ix > 256 ? 256 : ix;
12030
12031             if (count > 1)
12032             {
12033                 tlbl = newiTempLabel (NULL);
12034                 if (firstpass || (count & 0xff))
12035                 {
12036                     emitcode("mov", "b, #!constbyte", count & 0xff);
12037                 }
12038
12039                 emitLabel (tlbl);
12040             }
12041
12042             firstpass = FALSE;
12043
12044             for (eIndex = 0; eIndex < elementSize; eIndex++)
12045             {
12046                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12047                 if (val != lastVal)
12048                 {
12049                     emitcode("mov", "a, #!constbyte", val);
12050                     lastVal = val;
12051                 }
12052
12053                 emitcode("movx", "@dptr, a");
12054                 emitcode("inc", "dptr");
12055             }
12056
12057             if (count > 1)
12058             {
12059                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12060             }
12061
12062             ix -= count;
12063         }
12064
12065         iLoop = iLoop->next;
12066     }
12067
12068     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12069 }
12070 #endif
12071
12072 /*-----------------------------------------------------------------*/
12073 /* genFarFarAssign - assignment when both are in far space         */
12074 /*-----------------------------------------------------------------*/
12075 static void
12076 genFarFarAssign (operand * result, operand * right, iCode * ic)
12077 {
12078   int size = AOP_SIZE (right);
12079   int offset = 0;
12080   symbol *rSym = NULL;
12081
12082   if (size == 1)
12083   {
12084       /* quick & easy case. */
12085       D (emitcode(";","genFarFarAssign (1 byte case)"));
12086       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12087       freeAsmop (right, NULL, ic, FALSE);
12088       /* now assign DPTR to result */
12089       _G.accInUse++;
12090       aopOp(result, ic, FALSE, FALSE);
12091       _G.accInUse--;
12092       aopPut (result, "a", 0);
12093       freeAsmop(result, NULL, ic, FALSE);
12094       return;
12095   }
12096
12097   /* See if we've got an underlying symbol to abuse. */
12098   if (IS_SYMOP(result) && OP_SYMBOL(result))
12099   {
12100       if (IS_TRUE_SYMOP(result))
12101       {
12102           rSym = OP_SYMBOL(result);
12103       }
12104       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12105       {
12106           rSym = OP_SYMBOL(result)->usl.spillLoc;
12107       }
12108   }
12109
12110   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12111   {
12112       /* We can use the '390 auto-toggle feature to good effect here. */
12113
12114       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12115       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12116       emitcode ("mov", "dptr,#%s", rSym->rname);
12117       /* DP2 = result, DP1 = right, DP1 is current. */
12118       while (size)
12119       {
12120           emitcode("movx", "a,@dptr");
12121           emitcode("movx", "@dptr,a");
12122           if (--size)
12123           {
12124                emitcode("inc", "dptr");
12125                emitcode("inc", "dptr");
12126           }
12127       }
12128       emitcode("mov", "dps,#0");
12129       freeAsmop (right, NULL, ic, FALSE);
12130 #if 0
12131 some alternative code for processors without auto-toggle
12132 no time to test now, so later well put in...kpb
12133         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12134         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12135         emitcode ("mov", "dptr,#%s", rSym->rname);
12136         /* DP2 = result, DP1 = right, DP1 is current. */
12137         while (size)
12138         {
12139           --size;
12140           emitcode("movx", "a,@dptr");
12141           if (size)
12142             emitcode("inc", "dptr");
12143           emitcode("inc", "dps");
12144           emitcode("movx", "@dptr,a");
12145           if (size)
12146             emitcode("inc", "dptr");
12147           emitcode("inc", "dps");
12148         }
12149         emitcode("mov", "dps,#0");
12150         freeAsmop (right, NULL, ic, FALSE);
12151 #endif
12152   }
12153   else
12154   {
12155       D (emitcode (";", "genFarFarAssign"));
12156       aopOp (result, ic, TRUE, TRUE);
12157
12158       _startLazyDPSEvaluation ();
12159
12160       while (size--)
12161         {
12162           aopPut (result,
12163                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12164           offset++;
12165         }
12166       _endLazyDPSEvaluation ();
12167       freeAsmop (result, NULL, ic, FALSE);
12168       freeAsmop (right, NULL, ic, FALSE);
12169   }
12170 }
12171
12172 /*-----------------------------------------------------------------*/
12173 /* genAssign - generate code for assignment                        */
12174 /*-----------------------------------------------------------------*/
12175 static void
12176 genAssign (iCode * ic)
12177 {
12178   operand *result, *right;
12179   int size, offset;
12180   unsigned long lit = 0L;
12181
12182   D (emitcode (";", "genAssign"));
12183
12184   result = IC_RESULT (ic);
12185   right = IC_RIGHT (ic);
12186
12187   /* if they are the same */
12188   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12189     return;
12190
12191   aopOp (right, ic, FALSE, FALSE);
12192
12193   emitcode (";", "genAssign: resultIsFar = %s",
12194             isOperandInFarSpace (result) ?
12195             "TRUE" : "FALSE");
12196
12197   /* special case both in far space */
12198   if ((AOP_TYPE (right) == AOP_DPTR ||
12199        AOP_TYPE (right) == AOP_DPTR2) &&
12200   /* IS_TRUE_SYMOP(result)       && */
12201       isOperandInFarSpace (result))
12202     {
12203       genFarFarAssign (result, right, ic);
12204       return;
12205     }
12206
12207   aopOp (result, ic, TRUE, FALSE);
12208
12209   /* if they are the same registers */
12210   if (sameRegs (AOP (right), AOP (result)))
12211     goto release;
12212
12213   /* if the result is a bit */
12214   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12215     {
12216       /* if the right size is a literal then
12217          we know what the value is */
12218       if (AOP_TYPE (right) == AOP_LIT)
12219         {
12220           if (((int) operandLitValue (right)))
12221             aopPut (result, one, 0);
12222           else
12223             aopPut (result, zero, 0);
12224           goto release;
12225         }
12226
12227       /* the right is also a bit variable */
12228       if (AOP_TYPE (right) == AOP_CRY)
12229         {
12230           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12231           aopPut (result, "c", 0);
12232           goto release;
12233         }
12234
12235       /* we need to or */
12236       toBoolean (right);
12237       aopPut (result, "a", 0);
12238       goto release;
12239     }
12240
12241   /* bit variables done */
12242   /* general case */
12243   size = AOP_SIZE (result);
12244   offset = 0;
12245   if (AOP_TYPE (right) == AOP_LIT)
12246     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12247
12248   if ((size > 1) &&
12249       (AOP_TYPE (result) != AOP_REG) &&
12250       (AOP_TYPE (right) == AOP_LIT) &&
12251       !IS_FLOAT (operandType (right)))
12252     {
12253       _startLazyDPSEvaluation ();
12254       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12255         {
12256           aopPut (result,
12257                   aopGet (right, offset, FALSE, FALSE, NULL),
12258                   offset);
12259           offset++;
12260           size--;
12261         }
12262       /* And now fill the rest with zeros. */
12263       if (size)
12264         {
12265           emitcode ("clr", "a");
12266         }
12267       while (size--)
12268         {
12269           aopPut (result, "a", offset++);
12270         }
12271       _endLazyDPSEvaluation ();
12272     }
12273   else
12274     {
12275       _startLazyDPSEvaluation ();
12276       while (size--)
12277         {
12278           aopPut (result,
12279                   aopGet (right, offset, FALSE, FALSE, NULL),
12280                   offset);
12281           offset++;
12282         }
12283       _endLazyDPSEvaluation ();
12284     }
12285
12286 release:
12287   freeAsmop (result, NULL, ic, TRUE);
12288   freeAsmop (right, NULL, ic, TRUE);
12289 }
12290
12291 /*-----------------------------------------------------------------*/
12292 /* genJumpTab - generates code for jump table                      */
12293 /*-----------------------------------------------------------------*/
12294 static void
12295 genJumpTab (iCode * ic)
12296 {
12297   symbol *jtab;
12298   char *l;
12299
12300   D (emitcode (";", "genJumpTab"));
12301
12302   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12303   /* get the condition into accumulator */
12304   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12305   MOVA (l);
12306   /* multiply by four! */
12307   emitcode ("add", "a,acc");
12308   emitcode ("add", "a,acc");
12309   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12310
12311   jtab = newiTempLabel (NULL);
12312   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12313   emitcode ("jmp", "@a+dptr");
12314   emitLabel (jtab);
12315   /* now generate the jump labels */
12316   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12317        jtab = setNextItem (IC_JTLABELS (ic)))
12318     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12319
12320 }
12321
12322 /*-----------------------------------------------------------------*/
12323 /* genCast - gen code for casting                                  */
12324 /*-----------------------------------------------------------------*/
12325 static void
12326 genCast (iCode * ic)
12327 {
12328   operand *result = IC_RESULT (ic);
12329   sym_link *ctype = operandType (IC_LEFT (ic));
12330   sym_link *rtype = operandType (IC_RIGHT (ic));
12331   operand *right = IC_RIGHT (ic);
12332   int size, offset;
12333
12334   D (emitcode (";", "genCast"));
12335
12336   /* if they are equivalent then do nothing */
12337   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12338     return;
12339
12340   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12341   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12342
12343   /* if the result is a bit (and not a bitfield) */
12344   if (IS_BIT (OP_SYMBOL (result)->type))
12345     {
12346       /* if the right size is a literal then
12347          we know what the value is */
12348       if (AOP_TYPE (right) == AOP_LIT)
12349         {
12350           if (((int) operandLitValue (right)))
12351             aopPut (result, one, 0);
12352           else
12353             aopPut (result, zero, 0);
12354
12355           goto release;
12356         }
12357
12358       /* the right is also a bit variable */
12359       if (AOP_TYPE (right) == AOP_CRY)
12360         {
12361           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12362           aopPut (result, "c", 0);
12363           goto release;
12364         }
12365
12366       /* we need to or */
12367       toBoolean (right);
12368       aopPut (result, "a", 0);
12369       goto release;
12370     }
12371
12372   /* if they are the same size : or less */
12373   if (AOP_SIZE (result) <= AOP_SIZE (right))
12374     {
12375
12376       /* if they are in the same place */
12377       if (sameRegs (AOP (right), AOP (result)))
12378         goto release;
12379
12380       /* if they in different places then copy */
12381       size = AOP_SIZE (result);
12382       offset = 0;
12383       _startLazyDPSEvaluation ();
12384       while (size--)
12385         {
12386           aopPut (result,
12387                   aopGet (right, offset, FALSE, FALSE, NULL),
12388                   offset);
12389           offset++;
12390         }
12391       _endLazyDPSEvaluation ();
12392       goto release;
12393     }
12394
12395   /* if the result is of type pointer */
12396   if (IS_PTR (ctype))
12397     {
12398
12399       int p_type;
12400       sym_link *type = operandType (right);
12401
12402       /* pointer to generic pointer */
12403       if (IS_GENPTR (ctype))
12404         {
12405           if (IS_PTR (type))
12406             {
12407               p_type = DCL_TYPE (type);
12408             }
12409           else
12410             {
12411 #if OLD_CAST_BEHAVIOR
12412               /* KV: we are converting a non-pointer type to
12413                * a generic pointer. This (ifdef'd out) code
12414                * says that the resulting generic pointer
12415                * should have the same class as the storage
12416                * location of the non-pointer variable.
12417                *
12418                * For example, converting an int (which happens
12419                * to be stored in DATA space) to a pointer results
12420                * in a DATA generic pointer; if the original int
12421                * in XDATA space, so will be the resulting pointer.
12422                *
12423                * I don't like that behavior, and thus this change:
12424                * all such conversions will be forced to XDATA and
12425                * throw a warning. If you want some non-XDATA
12426                * type, or you want to suppress the warning, you
12427                * must go through an intermediate cast, like so:
12428                *
12429                * char _generic *gp = (char _xdata *)(intVar);
12430                */
12431               sym_link *etype = getSpec (type);
12432
12433               /* we have to go by the storage class */
12434               if (SPEC_OCLS (etype) != generic)
12435                 {
12436                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12437                 }
12438               else
12439 #endif
12440                 {
12441                   /* Converting unknown class (i.e. register variable)
12442                    * to generic pointer. This is not good, but
12443                    * we'll make a guess (and throw a warning).
12444                    */
12445                   p_type = FPOINTER;
12446                   werror (W_INT_TO_GEN_PTR_CAST);
12447                 }
12448             }
12449
12450           /* the first two bytes are known */
12451           size = GPTRSIZE - 1;
12452           offset = 0;
12453           _startLazyDPSEvaluation ();
12454           while (size--)
12455             {
12456               aopPut (result,
12457                       aopGet (right, offset, FALSE, FALSE, NULL),
12458                       offset);
12459               offset++;
12460             }
12461           _endLazyDPSEvaluation ();
12462
12463           /* the last byte depending on type */
12464             {
12465                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12466                 char gpValStr[10];
12467
12468                 if (gpVal == -1)
12469                 {
12470                     // pointerTypeToGPByte will have bitched.
12471                     exit(1);
12472                 }
12473
12474                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12475                 aopPut (result, gpValStr, GPTRSIZE - 1);
12476             }
12477           goto release;
12478         }
12479
12480       /* just copy the pointers */
12481       size = AOP_SIZE (result);
12482       offset = 0;
12483       _startLazyDPSEvaluation ();
12484       while (size--)
12485         {
12486           aopPut (result,
12487                   aopGet (right, offset, FALSE, FALSE, NULL),
12488                   offset);
12489           offset++;
12490         }
12491       _endLazyDPSEvaluation ();
12492       goto release;
12493     }
12494
12495   /* so we now know that the size of destination is greater
12496      than the size of the source */
12497   /* we move to result for the size of source */
12498   size = AOP_SIZE (right);
12499   offset = 0;
12500   _startLazyDPSEvaluation ();
12501   while (size--)
12502     {
12503       aopPut (result,
12504               aopGet (right, offset, FALSE, FALSE, NULL),
12505               offset);
12506       offset++;
12507     }
12508   _endLazyDPSEvaluation ();
12509
12510   /* now depending on the sign of the source && destination */
12511   size = AOP_SIZE (result) - AOP_SIZE (right);
12512   /* if unsigned or not an integral type */
12513   /* also, if the source is a bit, we don't need to sign extend, because
12514    * it can't possibly have set the sign bit.
12515    */
12516   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12517     {
12518       while (size--)
12519         {
12520           aopPut (result, zero, offset++);
12521         }
12522     }
12523   else
12524     {
12525       /* we need to extend the sign :{ */
12526       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12527                         FALSE, FALSE, NULL));
12528       emitcode ("rlc", "a");
12529       emitcode ("subb", "a,acc");
12530       while (size--)
12531         aopPut (result, "a", offset++);
12532     }
12533
12534   /* we are done hurray !!!! */
12535
12536 release:
12537   freeAsmop (right, NULL, ic, TRUE);
12538   freeAsmop (result, NULL, ic, TRUE);
12539
12540 }
12541
12542 /*-----------------------------------------------------------------*/
12543 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12544 /*-----------------------------------------------------------------*/
12545 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12546 {
12547     operand *from , *to , *count;
12548     symbol *lbl;
12549     bitVect *rsave;
12550     int i;
12551
12552     /* we know it has to be 3 parameters */
12553     assert (nparms == 3);
12554
12555     rsave = newBitVect(16);
12556     /* save DPTR if it needs to be saved */
12557     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12558             if (bitVectBitValue(ic->rMask,i))
12559                     rsave = bitVectSetBit(rsave,i);
12560     }
12561     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12562                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12563     savermask(rsave);
12564
12565     to = parms[0];
12566     from = parms[1];
12567     count = parms[2];
12568
12569     aopOp (from, ic->next, FALSE, FALSE);
12570
12571     /* get from into DPTR1 */
12572     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12573     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12574     if (options.model == MODEL_FLAT24) {
12575         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12576     }
12577
12578     freeAsmop (from, NULL, ic, FALSE);
12579     aopOp (to, ic, FALSE, FALSE);
12580     /* get "to" into DPTR */
12581     /* if the operand is already in dptr
12582        then we do nothing else we move the value to dptr */
12583     if (AOP_TYPE (to) != AOP_STR) {
12584         /* if already in DPTR then we need to push */
12585         if (AOP_TYPE(to) == AOP_DPTR) {
12586             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12587             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12588             if (options.model == MODEL_FLAT24)
12589                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12590             emitcode ("pop", "dph");
12591             emitcode ("pop", "dpl");
12592         } else {
12593             _startLazyDPSEvaluation ();
12594             /* if this is remateriazable */
12595             if (AOP_TYPE (to) == AOP_IMMD) {
12596                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12597             } else {                    /* we need to get it byte by byte */
12598                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12599                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12600                 if (options.model == MODEL_FLAT24) {
12601                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12602                 }
12603             }
12604             _endLazyDPSEvaluation ();
12605         }
12606     }
12607     freeAsmop (to, NULL, ic, FALSE);
12608     _G.dptrInUse = _G.dptr1InUse = 1;
12609     aopOp (count, ic->next->next, FALSE,FALSE);
12610     lbl =newiTempLabel(NULL);
12611
12612     /* now for the actual copy */
12613     if (AOP_TYPE(count) == AOP_LIT &&
12614         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12615         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12616         if (fromc) {
12617             emitcode ("lcall","__bi_memcpyc2x_s");
12618         } else {
12619             emitcode ("lcall","__bi_memcpyx2x_s");
12620         }
12621         freeAsmop (count, NULL, ic, FALSE);
12622     } else {
12623         symbol *lbl1 = newiTempLabel(NULL);
12624
12625         emitcode (";"," Auto increment but no djnz");
12626         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12627         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12628         freeAsmop (count, NULL, ic, FALSE);
12629         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12630         emitcode ("","!tlabeldef",lbl->key+100);
12631         if (fromc) {
12632             emitcode ("clr","a");
12633             emitcode ("movc", "a,@a+dptr");
12634         } else
12635             emitcode ("movx", "a,@dptr");
12636         emitcode ("movx", "@dptr,a");
12637         emitcode ("inc", "dptr");
12638         emitcode ("inc", "dptr");
12639         emitcode ("mov","a,b");
12640         emitcode ("orl","a,_ap");
12641         emitcode ("jz","!tlabel",lbl1->key+100);
12642         emitcode ("mov","a,_ap");
12643         emitcode ("add","a,#!constbyte",0xFF);
12644         emitcode ("mov","_ap,a");
12645         emitcode ("mov","a,b");
12646         emitcode ("addc","a,#!constbyte",0xFF);
12647         emitcode ("mov","b,a");
12648         emitcode ("sjmp","!tlabel",lbl->key+100);
12649         emitcode ("","!tlabeldef",lbl1->key+100);
12650     }
12651     emitcode ("mov", "dps,#0");
12652     _G.dptrInUse = _G.dptr1InUse = 0;
12653     unsavermask(rsave);
12654
12655 }
12656
12657 /*-----------------------------------------------------------------*/
12658 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12659 /*-----------------------------------------------------------------*/
12660 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12661 {
12662     operand *from , *to , *count;
12663     symbol *lbl,*lbl2;
12664     bitVect *rsave;
12665     int i;
12666
12667     /* we know it has to be 3 parameters */
12668     assert (nparms == 3);
12669
12670     rsave = newBitVect(16);
12671     /* save DPTR if it needs to be saved */
12672     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12673             if (bitVectBitValue(ic->rMask,i))
12674                     rsave = bitVectSetBit(rsave,i);
12675     }
12676     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12677                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12678     savermask(rsave);
12679
12680     to = parms[0];
12681     from = parms[1];
12682     count = parms[2];
12683
12684     aopOp (from, ic->next, FALSE, FALSE);
12685
12686     /* get from into DPTR1 */
12687     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12688     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12689     if (options.model == MODEL_FLAT24) {
12690         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12691     }
12692
12693     freeAsmop (from, NULL, ic, FALSE);
12694     aopOp (to, ic, FALSE, FALSE);
12695     /* get "to" into DPTR */
12696     /* if the operand is already in dptr
12697        then we do nothing else we move the value to dptr */
12698     if (AOP_TYPE (to) != AOP_STR) {
12699         /* if already in DPTR then we need to push */
12700         if (AOP_TYPE(to) == AOP_DPTR) {
12701             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12702             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12703             if (options.model == MODEL_FLAT24)
12704                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12705             emitcode ("pop", "dph");
12706             emitcode ("pop", "dpl");
12707         } else {
12708             _startLazyDPSEvaluation ();
12709             /* if this is remateriazable */
12710             if (AOP_TYPE (to) == AOP_IMMD) {
12711                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12712             } else {                    /* we need to get it byte by byte */
12713                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12714                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12715                 if (options.model == MODEL_FLAT24) {
12716                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12717                 }
12718             }
12719             _endLazyDPSEvaluation ();
12720         }
12721     }
12722     freeAsmop (to, NULL, ic, FALSE);
12723     _G.dptrInUse = _G.dptr1InUse = 1;
12724     aopOp (count, ic->next->next, FALSE,FALSE);
12725     lbl =newiTempLabel(NULL);
12726     lbl2 =newiTempLabel(NULL);
12727
12728     /* now for the actual compare */
12729     if (AOP_TYPE(count) == AOP_LIT &&
12730         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12731         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12732         if (fromc)
12733             emitcode("lcall","__bi_memcmpc2x_s");
12734         else
12735             emitcode("lcall","__bi_memcmpx2x_s");
12736         freeAsmop (count, NULL, ic, FALSE);
12737         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12738         aopPut(IC_RESULT(ic),"a",0);
12739         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12740     } else {
12741         symbol *lbl1 = newiTempLabel(NULL);
12742
12743         emitcode("push","ar0");
12744         emitcode (";"," Auto increment but no djnz");
12745         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12746         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12747         freeAsmop (count, NULL, ic, FALSE);
12748         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12749         emitcode ("","!tlabeldef",lbl->key+100);
12750         if (fromc) {
12751             emitcode ("clr","a");
12752             emitcode ("movc", "a,@a+dptr");
12753         } else
12754             emitcode ("movx", "a,@dptr");
12755         emitcode ("mov","r0,a");
12756         emitcode ("movx", "a,@dptr");
12757         emitcode ("clr","c");
12758         emitcode ("subb","a,r0");
12759         emitcode ("jnz","!tlabel",lbl2->key+100);
12760         emitcode ("inc", "dptr");
12761         emitcode ("inc", "dptr");
12762         emitcode ("mov","a,b");
12763         emitcode ("orl","a,_ap");
12764         emitcode ("jz","!tlabel",lbl1->key+100);
12765         emitcode ("mov","a,_ap");
12766         emitcode ("add","a,#!constbyte",0xFF);
12767         emitcode ("mov","_ap,a");
12768         emitcode ("mov","a,b");
12769         emitcode ("addc","a,#!constbyte",0xFF);
12770         emitcode ("mov","b,a");
12771         emitcode ("sjmp","!tlabel",lbl->key+100);
12772         emitcode ("","!tlabeldef",lbl1->key+100);
12773         emitcode ("clr","a");
12774         emitcode ("","!tlabeldef",lbl2->key+100);
12775         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12776         aopPut(IC_RESULT(ic),"a",0);
12777         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12778         emitcode("pop","ar0");
12779         emitcode ("mov", "dps,#0");
12780     }
12781     _G.dptrInUse = _G.dptr1InUse = 0;
12782     unsavermask(rsave);
12783
12784 }
12785
12786 /*-----------------------------------------------------------------*/
12787 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12788 /* port, first parameter output area second parameter pointer to   */
12789 /* port third parameter count                                      */
12790 /*-----------------------------------------------------------------*/
12791 static void genInp( iCode *ic, int nparms, operand **parms)
12792 {
12793     operand *from , *to , *count;
12794     symbol *lbl;
12795     bitVect *rsave;
12796     int i;
12797
12798     /* we know it has to be 3 parameters */
12799     assert (nparms == 3);
12800
12801     rsave = newBitVect(16);
12802     /* save DPTR if it needs to be saved */
12803     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12804             if (bitVectBitValue(ic->rMask,i))
12805                     rsave = bitVectSetBit(rsave,i);
12806     }
12807     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12808                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12809     savermask(rsave);
12810
12811     to = parms[0];
12812     from = parms[1];
12813     count = parms[2];
12814
12815     aopOp (from, ic->next, FALSE, FALSE);
12816
12817     /* get from into DPTR1 */
12818     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12819     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12820     if (options.model == MODEL_FLAT24) {
12821         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12822     }
12823
12824     freeAsmop (from, NULL, ic, FALSE);
12825     aopOp (to, ic, FALSE, FALSE);
12826     /* get "to" into DPTR */
12827     /* if the operand is already in dptr
12828        then we do nothing else we move the value to dptr */
12829     if (AOP_TYPE (to) != AOP_STR) {
12830         /* if already in DPTR then we need to push */
12831         if (AOP_TYPE(to) == AOP_DPTR) {
12832             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12833             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12834             if (options.model == MODEL_FLAT24)
12835                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12836             emitcode ("pop", "dph");
12837             emitcode ("pop", "dpl");
12838         } else {
12839             _startLazyDPSEvaluation ();
12840             /* if this is remateriazable */
12841             if (AOP_TYPE (to) == AOP_IMMD) {
12842                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12843             } else {                    /* we need to get it byte by byte */
12844                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12845                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12846                 if (options.model == MODEL_FLAT24) {
12847                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12848                 }
12849             }
12850             _endLazyDPSEvaluation ();
12851         }
12852     }
12853     freeAsmop (to, NULL, ic, FALSE);
12854
12855     _G.dptrInUse = _G.dptr1InUse = 1;
12856     aopOp (count, ic->next->next, FALSE,FALSE);
12857     lbl =newiTempLabel(NULL);
12858
12859     /* now for the actual copy */
12860     if (AOP_TYPE(count) == AOP_LIT &&
12861         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12862         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12863         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12864         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12865         freeAsmop (count, NULL, ic, FALSE);
12866         emitcode ("","!tlabeldef",lbl->key+100);
12867         emitcode ("movx", "a,@dptr");   /* read data from port */
12868         emitcode ("dec","dps");         /* switch to DPTR */
12869         emitcode ("movx", "@dptr,a");   /* save into location */
12870         emitcode ("inc", "dptr");       /* point to next area */
12871         emitcode ("inc","dps");         /* switch to DPTR2 */
12872         emitcode ("djnz","b,!tlabel",lbl->key+100);
12873     } else {
12874         symbol *lbl1 = newiTempLabel(NULL);
12875
12876         emitcode (";"," Auto increment but no djnz");
12877         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12878         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12879         freeAsmop (count, NULL, ic, FALSE);
12880         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12881         emitcode ("","!tlabeldef",lbl->key+100);
12882         emitcode ("movx", "a,@dptr");
12883         emitcode ("dec","dps");         /* switch to DPTR */
12884         emitcode ("movx", "@dptr,a");
12885         emitcode ("inc", "dptr");
12886         emitcode ("inc","dps");         /* switch to DPTR2 */
12887 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12888 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12889         emitcode ("mov","a,b");
12890         emitcode ("orl","a,_ap");
12891         emitcode ("jz","!tlabel",lbl1->key+100);
12892         emitcode ("mov","a,_ap");
12893         emitcode ("add","a,#!constbyte",0xFF);
12894         emitcode ("mov","_ap,a");
12895         emitcode ("mov","a,b");
12896         emitcode ("addc","a,#!constbyte",0xFF);
12897         emitcode ("mov","b,a");
12898         emitcode ("sjmp","!tlabel",lbl->key+100);
12899         emitcode ("","!tlabeldef",lbl1->key+100);
12900     }
12901     emitcode ("mov", "dps,#0");
12902     _G.dptrInUse = _G.dptr1InUse = 0;
12903     unsavermask(rsave);
12904
12905 }
12906
12907 /*-----------------------------------------------------------------*/
12908 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12909 /* port, first parameter output area second parameter pointer to   */
12910 /* port third parameter count                                      */
12911 /*-----------------------------------------------------------------*/
12912 static void genOutp( iCode *ic, int nparms, operand **parms)
12913 {
12914     operand *from , *to , *count;
12915     symbol *lbl;
12916     bitVect *rsave;
12917     int i;
12918
12919     /* we know it has to be 3 parameters */
12920     assert (nparms == 3);
12921
12922     rsave = newBitVect(16);
12923     /* save DPTR if it needs to be saved */
12924     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12925             if (bitVectBitValue(ic->rMask,i))
12926                     rsave = bitVectSetBit(rsave,i);
12927     }
12928     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12929                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12930     savermask(rsave);
12931
12932     to = parms[0];
12933     from = parms[1];
12934     count = parms[2];
12935
12936     aopOp (from, ic->next, FALSE, FALSE);
12937
12938     /* get from into DPTR1 */
12939     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12940     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12941     if (options.model == MODEL_FLAT24) {
12942         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12943     }
12944
12945     freeAsmop (from, NULL, ic, FALSE);
12946     aopOp (to, ic, FALSE, FALSE);
12947     /* get "to" into DPTR */
12948     /* if the operand is already in dptr
12949        then we do nothing else we move the value to dptr */
12950     if (AOP_TYPE (to) != AOP_STR) {
12951         /* if already in DPTR then we need to push */
12952         if (AOP_TYPE(to) == AOP_DPTR) {
12953             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12954             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12955             if (options.model == MODEL_FLAT24)
12956                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12957             emitcode ("pop", "dph");
12958             emitcode ("pop", "dpl");
12959         } else {
12960             _startLazyDPSEvaluation ();
12961             /* if this is remateriazable */
12962             if (AOP_TYPE (to) == AOP_IMMD) {
12963                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12964             } else {                    /* we need to get it byte by byte */
12965                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12966                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12967                 if (options.model == MODEL_FLAT24) {
12968                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12969                 }
12970             }
12971             _endLazyDPSEvaluation ();
12972         }
12973     }
12974     freeAsmop (to, NULL, ic, FALSE);
12975
12976     _G.dptrInUse = _G.dptr1InUse = 1;
12977     aopOp (count, ic->next->next, FALSE,FALSE);
12978     lbl =newiTempLabel(NULL);
12979
12980     /* now for the actual copy */
12981     if (AOP_TYPE(count) == AOP_LIT &&
12982         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12983         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12984         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12985         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12986         emitcode ("","!tlabeldef",lbl->key+100);
12987         emitcode ("movx", "a,@dptr");   /* read data from port */
12988         emitcode ("inc","dps");         /* switch to DPTR2 */
12989         emitcode ("movx", "@dptr,a");   /* save into location */
12990         emitcode ("inc", "dptr");       /* point to next area */
12991         emitcode ("dec","dps");         /* switch to DPTR */
12992         emitcode ("djnz","b,!tlabel",lbl->key+100);
12993         freeAsmop (count, NULL, ic, FALSE);
12994     } else {
12995         symbol *lbl1 = newiTempLabel(NULL);
12996
12997         emitcode (";"," Auto increment but no djnz");
12998         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12999         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13000         freeAsmop (count, NULL, ic, FALSE);
13001         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13002         emitcode ("","!tlabeldef",lbl->key+100);
13003         emitcode ("movx", "a,@dptr");
13004         emitcode ("inc", "dptr");
13005         emitcode ("inc","dps");         /* switch to DPTR2 */
13006         emitcode ("movx", "@dptr,a");
13007         emitcode ("dec","dps");         /* switch to DPTR */
13008         emitcode ("mov","a,b");
13009         emitcode ("orl","a,_ap");
13010         emitcode ("jz","!tlabel",lbl1->key+100);
13011         emitcode ("mov","a,_ap");
13012         emitcode ("add","a,#!constbyte",0xFF);
13013         emitcode ("mov","_ap,a");
13014         emitcode ("mov","a,b");
13015         emitcode ("addc","a,#!constbyte",0xFF);
13016         emitcode ("mov","b,a");
13017         emitcode ("sjmp","!tlabel",lbl->key+100);
13018         emitcode ("","!tlabeldef",lbl1->key+100);
13019     }
13020     emitcode ("mov", "dps,#0");
13021     _G.dptrInUse = _G.dptr1InUse = 0;
13022     unsavermask(rsave);
13023
13024 }
13025
13026 /*-----------------------------------------------------------------*/
13027 /* genSwapW - swap lower & high order bytes                        */
13028 /*-----------------------------------------------------------------*/
13029 static void genSwapW(iCode *ic, int nparms, operand **parms)
13030 {
13031     operand *dest;
13032     operand *src;
13033     assert (nparms==1);
13034
13035     src = parms[0];
13036     dest=IC_RESULT(ic);
13037
13038     assert(getSize(operandType(src))==2);
13039
13040     aopOp (src, ic, FALSE, FALSE);
13041     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13042     _G.accInUse++;
13043     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13044     _G.accInUse--;
13045     freeAsmop (src, NULL, ic, FALSE);
13046
13047     aopOp (dest,ic, FALSE, FALSE);
13048     aopPut(dest,"b",0);
13049     aopPut(dest,"a",1);
13050     freeAsmop (dest, NULL, ic, FALSE);
13051 }
13052
13053 /*-----------------------------------------------------------------*/
13054 /* genMemsetX - gencode for memSetX data                           */
13055 /*-----------------------------------------------------------------*/
13056 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13057 {
13058     operand *to , *val , *count;
13059     symbol *lbl;
13060     char *l;
13061     int i;
13062     bitVect *rsave;
13063
13064     /* we know it has to be 3 parameters */
13065     assert (nparms == 3);
13066
13067     to = parms[0];
13068     val = parms[1];
13069     count = parms[2];
13070
13071     /* save DPTR if it needs to be saved */
13072     rsave = newBitVect(16);
13073     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13074             if (bitVectBitValue(ic->rMask,i))
13075                     rsave = bitVectSetBit(rsave,i);
13076     }
13077     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13078                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13079     savermask(rsave);
13080
13081     aopOp (to, ic, FALSE, FALSE);
13082     /* get "to" into DPTR */
13083     /* if the operand is already in dptr
13084        then we do nothing else we move the value to dptr */
13085     if (AOP_TYPE (to) != AOP_STR) {
13086         /* if already in DPTR then we need to push */
13087         if (AOP_TYPE(to) == AOP_DPTR) {
13088             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13089             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13090             if (options.model == MODEL_FLAT24)
13091                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13092             emitcode ("pop", "dph");
13093             emitcode ("pop", "dpl");
13094         } else {
13095             _startLazyDPSEvaluation ();
13096             /* if this is remateriazable */
13097             if (AOP_TYPE (to) == AOP_IMMD) {
13098                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13099             } else {                    /* we need to get it byte by byte */
13100                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13101                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13102                 if (options.model == MODEL_FLAT24) {
13103                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13104                 }
13105             }
13106             _endLazyDPSEvaluation ();
13107         }
13108     }
13109     freeAsmop (to, NULL, ic, FALSE);
13110
13111     aopOp (val, ic->next->next, FALSE,FALSE);
13112     aopOp (count, ic->next->next, FALSE,FALSE);
13113     lbl =newiTempLabel(NULL);
13114     /* now for the actual copy */
13115     if (AOP_TYPE(count) == AOP_LIT &&
13116         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13117         l = aopGet(val, 0, FALSE, FALSE, NULL);
13118         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13119         MOVA(l);
13120         emitcode ("","!tlabeldef",lbl->key+100);
13121         emitcode ("movx", "@dptr,a");
13122         emitcode ("inc", "dptr");
13123         emitcode ("djnz","b,!tlabel",lbl->key+100);
13124     } else {
13125         symbol *lbl1 = newiTempLabel(NULL);
13126
13127         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13128         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13129         emitcode ("","!tlabeldef",lbl->key+100);
13130         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13131         emitcode ("movx", "@dptr,a");
13132         emitcode ("inc", "dptr");
13133         emitcode ("mov","a,b");
13134         emitcode ("orl","a,_ap");
13135         emitcode ("jz","!tlabel",lbl1->key+100);
13136         emitcode ("mov","a,_ap");
13137         emitcode ("add","a,#!constbyte",0xFF);
13138         emitcode ("mov","_ap,a");
13139         emitcode ("mov","a,b");
13140         emitcode ("addc","a,#!constbyte",0xFF);
13141         emitcode ("mov","b,a");
13142         emitcode ("sjmp","!tlabel",lbl->key+100);
13143         emitcode ("","!tlabeldef",lbl1->key+100);
13144     }
13145     freeAsmop (count, NULL, ic, FALSE);
13146     unsavermask(rsave);
13147 }
13148
13149 /*-----------------------------------------------------------------*/
13150 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13151 /*-----------------------------------------------------------------*/
13152 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13153 {
13154         bitVect *rsave ;
13155         operand *pnum, *result;
13156         int i;
13157
13158         assert (nparms==1);
13159         /* save registers that need to be saved */
13160         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13161                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13162
13163         pnum = parms[0];
13164         aopOp (pnum, ic, FALSE, FALSE);
13165         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13166         freeAsmop (pnum, NULL, ic, FALSE);
13167         emitcode ("lcall","NatLib_LoadPrimitive");
13168         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13169         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13170             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13171                 for (i = (size-1) ; i >= 0 ; i-- ) {
13172                         emitcode ("push","a%s",javaRet[i]);
13173                 }
13174                 for (i=0; i < size ; i++ ) {
13175                         emitcode ("pop","a%s",
13176                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13177                 }
13178         } else {
13179                 for (i = 0 ; i < size ; i++ ) {
13180                         aopPut(result,javaRet[i],i);
13181                 }
13182         }
13183         freeAsmop (result, NULL, ic, FALSE);
13184         unsavermask(rsave);
13185 }
13186
13187 /*-----------------------------------------------------------------*/
13188 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13189 /*-----------------------------------------------------------------*/
13190 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13191 {
13192         bitVect *rsave ;
13193         operand *pnum, *result;
13194         int size = 3;
13195         int i;
13196
13197         assert (nparms==1);
13198         /* save registers that need to be saved */
13199         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13200                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13201
13202         pnum = parms[0];
13203         aopOp (pnum, ic, FALSE, FALSE);
13204         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13205         freeAsmop (pnum, NULL, ic, FALSE);
13206         emitcode ("lcall","NatLib_LoadPointer");
13207         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13208         if (AOP_TYPE(result)!=AOP_STR) {
13209                 for (i = 0 ; i < size ; i++ ) {
13210                         aopPut(result,fReturn[i],i);
13211                 }
13212         }
13213         freeAsmop (result, NULL, ic, FALSE);
13214         unsavermask(rsave);
13215 }
13216
13217 /*-----------------------------------------------------------------*/
13218 /* genNatLibInstallStateBlock -                                    */
13219 /*-----------------------------------------------------------------*/
13220 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13221                                        operand **parms, const char *name)
13222 {
13223         bitVect *rsave ;
13224         operand *psb, *handle;
13225         assert (nparms==2);
13226
13227         /* save registers that need to be saved */
13228         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13229                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13230         psb = parms[0];
13231         handle = parms[1];
13232
13233         /* put pointer to state block into DPTR1 */
13234         aopOp (psb, ic, FALSE, FALSE);
13235         if (AOP_TYPE (psb) == AOP_IMMD) {
13236                 emitcode ("mov","dps,#1");
13237                 emitcode ("mov", "dptr,%s",
13238                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13239                 emitcode ("mov","dps,#0");
13240         } else {
13241                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13242                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13243                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13244         }
13245         freeAsmop (psb, NULL, ic, FALSE);
13246
13247         /* put libraryID into DPTR */
13248         emitcode ("mov","dptr,#LibraryID");
13249
13250         /* put handle into r3:r2 */
13251         aopOp (handle, ic, FALSE, FALSE);
13252         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13253                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13254                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13255                 emitcode ("pop","ar3");
13256                 emitcode ("pop","ar2");
13257         } else {
13258                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13259                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13260         }
13261         freeAsmop (psb, NULL, ic, FALSE);
13262
13263         /* make the call */
13264         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13265
13266         /* put return value into place*/
13267         _G.accInUse++;
13268         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13269         _G.accInUse--;
13270         aopPut(IC_RESULT(ic),"a",0);
13271         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13272         unsavermask(rsave);
13273 }
13274
13275 /*-----------------------------------------------------------------*/
13276 /* genNatLibRemoveStateBlock -                                     */
13277 /*-----------------------------------------------------------------*/
13278 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13279 {
13280         bitVect *rsave ;
13281
13282         assert(nparms==0);
13283
13284         /* save registers that need to be saved */
13285         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13286                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13287
13288         /* put libraryID into DPTR */
13289         emitcode ("mov","dptr,#LibraryID");
13290         /* make the call */
13291         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13292         unsavermask(rsave);
13293 }
13294
13295 /*-----------------------------------------------------------------*/
13296 /* genNatLibGetStateBlock -                                        */
13297 /*-----------------------------------------------------------------*/
13298 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13299                                    operand **parms,const char *name)
13300 {
13301         bitVect *rsave ;
13302         symbol *lbl = newiTempLabel(NULL);
13303
13304         assert(nparms==0);
13305         /* save registers that need to be saved */
13306         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13307                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13308
13309         /* put libraryID into DPTR */
13310         emitcode ("mov","dptr,#LibraryID");
13311         /* make the call */
13312         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13313         emitcode ("jnz","!tlabel",lbl->key+100);
13314
13315         /* put return value into place */
13316         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13317         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13318                 emitcode ("push","ar3");
13319                 emitcode ("push","ar2");
13320                 emitcode ("pop","%s",
13321                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13322                 emitcode ("pop","%s",
13323                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13324         } else {
13325                 aopPut(IC_RESULT(ic),"r2",0);
13326                 aopPut(IC_RESULT(ic),"r3",1);
13327         }
13328         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13329         emitcode ("","!tlabeldef",lbl->key+100);
13330         unsavermask(rsave);
13331 }
13332
13333 /*-----------------------------------------------------------------*/
13334 /* genMMMalloc -                                                   */
13335 /*-----------------------------------------------------------------*/
13336 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13337                          int size, const char *name)
13338 {
13339         bitVect *rsave ;
13340         operand *bsize;
13341         symbol *rsym;
13342         symbol *lbl = newiTempLabel(NULL);
13343
13344         assert (nparms == 1);
13345         /* save registers that need to be saved */
13346         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13347                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13348
13349         bsize=parms[0];
13350         aopOp (bsize,ic,FALSE,FALSE);
13351
13352         /* put the size in R4-R2 */
13353         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13354                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13355                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13356                 if (size==3) {
13357                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13358                         emitcode("pop","ar4");
13359                 }
13360                 emitcode("pop","ar3");
13361                 emitcode("pop","ar2");
13362         } else {
13363                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13364                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13365                 if (size==3) {
13366                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13367                 }
13368         }
13369         freeAsmop (bsize, NULL, ic, FALSE);
13370
13371         /* make the call */
13372         emitcode ("lcall","MM_%s",name);
13373         emitcode ("jz","!tlabel",lbl->key+100);
13374         emitcode ("mov","r2,#!constbyte",0xff);
13375         emitcode ("mov","r3,#!constbyte",0xff);
13376         emitcode ("","!tlabeldef",lbl->key+100);
13377         /* we don't care about the pointer : we just save the handle */
13378         rsym = OP_SYMBOL(IC_RESULT(ic));
13379         if (rsym->liveFrom != rsym->liveTo) {
13380                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13381                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13382                         emitcode ("push","ar3");
13383                         emitcode ("push","ar2");
13384                         emitcode ("pop","%s",
13385                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13386                         emitcode ("pop","%s",
13387                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13388                 } else {
13389                         aopPut(IC_RESULT(ic),"r2",0);
13390                         aopPut(IC_RESULT(ic),"r3",1);
13391                 }
13392                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13393         }
13394         unsavermask(rsave);
13395 }
13396
13397 /*-----------------------------------------------------------------*/
13398 /* genMMDeref -                                                    */
13399 /*-----------------------------------------------------------------*/
13400 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13401 {
13402         bitVect *rsave ;
13403         operand *handle;
13404
13405         assert (nparms == 1);
13406         /* save registers that need to be saved */
13407         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13408                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13409
13410         handle=parms[0];
13411         aopOp (handle,ic,FALSE,FALSE);
13412
13413         /* put the size in R4-R2 */
13414         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13415                 emitcode("push","%s",
13416                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13417                 emitcode("push","%s",
13418                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13419                 emitcode("pop","ar3");
13420                 emitcode("pop","ar2");
13421         } else {
13422                 emitcode ("mov","r2,%s",
13423                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13424                 emitcode ("mov","r3,%s",
13425                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13426         }
13427         freeAsmop (handle, NULL, ic, FALSE);
13428
13429         /* make the call */
13430         emitcode ("lcall","MM_Deref");
13431
13432         {
13433                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13434                 if (rsym->liveFrom != rsym->liveTo) {
13435                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13436                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13437                             _startLazyDPSEvaluation ();
13438
13439                             aopPut(IC_RESULT(ic),"dpl",0);
13440                             aopPut(IC_RESULT(ic),"dph",1);
13441                             aopPut(IC_RESULT(ic),"dpx",2);
13442
13443                             _endLazyDPSEvaluation ();
13444
13445                         }
13446                 }
13447         }
13448         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13449         unsavermask(rsave);
13450 }
13451
13452 /*-----------------------------------------------------------------*/
13453 /* genMMUnrestrictedPersist -                                      */
13454 /*-----------------------------------------------------------------*/
13455 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13456 {
13457         bitVect *rsave ;
13458         operand *handle;
13459
13460         assert (nparms == 1);
13461         /* save registers that need to be saved */
13462         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13463                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13464
13465         handle=parms[0];
13466         aopOp (handle,ic,FALSE,FALSE);
13467
13468         /* put the size in R3-R2 */
13469         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13470                 emitcode("push","%s",
13471                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13472                 emitcode("push","%s",
13473                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13474                 emitcode("pop","ar3");
13475                 emitcode("pop","ar2");
13476         } else {
13477                 emitcode ("mov","r2,%s",
13478                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13479                 emitcode ("mov","r3,%s",
13480                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13481         }
13482         freeAsmop (handle, NULL, ic, FALSE);
13483
13484         /* make the call */
13485         emitcode ("lcall","MM_UnrestrictedPersist");
13486
13487         {
13488                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13489                 if (rsym->liveFrom != rsym->liveTo) {
13490                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13491                         aopPut(IC_RESULT(ic),"a",0);
13492                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13493                 }
13494         }
13495         unsavermask(rsave);
13496 }
13497
13498 /*-----------------------------------------------------------------*/
13499 /* genSystemExecJavaProcess -                                      */
13500 /*-----------------------------------------------------------------*/
13501 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13502 {
13503         bitVect *rsave ;
13504         operand *handle, *pp;
13505
13506         assert (nparms==2);
13507         /* save registers that need to be saved */
13508         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13509                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13510
13511         pp = parms[0];
13512         handle = parms[1];
13513
13514         /* put the handle in R3-R2 */
13515         aopOp (handle,ic,FALSE,FALSE);
13516         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13517                 emitcode("push","%s",
13518                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13519                 emitcode("push","%s",
13520                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13521                 emitcode("pop","ar3");
13522                 emitcode("pop","ar2");
13523         } else {
13524                 emitcode ("mov","r2,%s",
13525                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13526                 emitcode ("mov","r3,%s",
13527                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13528         }
13529         freeAsmop (handle, NULL, ic, FALSE);
13530
13531         /* put pointer in DPTR */
13532         aopOp (pp,ic,FALSE,FALSE);
13533         if (AOP_TYPE(pp) == AOP_IMMD) {
13534                 emitcode ("mov", "dptr,%s",
13535                           aopGet (pp, 0, TRUE, FALSE, NULL));
13536         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13537                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13538                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13539                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13540         }
13541         freeAsmop (handle, NULL, ic, FALSE);
13542
13543         /* make the call */
13544         emitcode ("lcall","System_ExecJavaProcess");
13545
13546         /* put result in place */
13547         {
13548                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13549                 if (rsym->liveFrom != rsym->liveTo) {
13550                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13551                         aopPut(IC_RESULT(ic),"a",0);
13552                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13553                 }
13554         }
13555
13556         unsavermask(rsave);
13557 }
13558
13559 /*-----------------------------------------------------------------*/
13560 /* genSystemRTCRegisters -                                         */
13561 /*-----------------------------------------------------------------*/
13562 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13563                                   char *name)
13564 {
13565         bitVect *rsave ;
13566         operand *pp;
13567
13568         assert (nparms==1);
13569         /* save registers that need to be saved */
13570         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13571                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13572
13573         pp=parms[0];
13574         /* put pointer in DPTR */
13575         aopOp (pp,ic,FALSE,FALSE);
13576         if (AOP_TYPE (pp) == AOP_IMMD) {
13577                 emitcode ("mov","dps,#1");
13578                 emitcode ("mov", "dptr,%s",
13579                           aopGet (pp, 0, TRUE, FALSE, NULL));
13580                 emitcode ("mov","dps,#0");
13581         } else {
13582                 emitcode ("mov","dpl1,%s",
13583                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13584                 emitcode ("mov","dph1,%s",
13585                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13586                 emitcode ("mov","dpx1,%s",
13587                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13588         }
13589         freeAsmop (pp, NULL, ic, FALSE);
13590
13591         /* make the call */
13592         emitcode ("lcall","System_%sRTCRegisters",name);
13593
13594         unsavermask(rsave);
13595 }
13596
13597 /*-----------------------------------------------------------------*/
13598 /* genSystemThreadSleep -                                          */
13599 /*-----------------------------------------------------------------*/
13600 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13601 {
13602         bitVect *rsave ;
13603         operand *to, *s;
13604
13605         assert (nparms==1);
13606         /* save registers that need to be saved */
13607         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13608                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13609
13610         to = parms[0];
13611         aopOp(to,ic,FALSE,FALSE);
13612         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13613             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13614                 emitcode ("push","%s",
13615                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13616                 emitcode ("push","%s",
13617                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13618                 emitcode ("push","%s",
13619                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13620                 emitcode ("push","%s",
13621                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13622                 emitcode ("pop","ar3");
13623                 emitcode ("pop","ar2");
13624                 emitcode ("pop","ar1");
13625                 emitcode ("pop","ar0");
13626         } else {
13627                 emitcode ("mov","r0,%s",
13628                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13629                 emitcode ("mov","r1,%s",
13630                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13631                 emitcode ("mov","r2,%s",
13632                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13633                 emitcode ("mov","r3,%s",
13634                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13635         }
13636         freeAsmop (to, NULL, ic, FALSE);
13637
13638         /* suspend in acc */
13639         s = parms[1];
13640         aopOp(s,ic,FALSE,FALSE);
13641         emitcode ("mov","a,%s",
13642                   aopGet(s,0,FALSE,TRUE,NULL));
13643         freeAsmop (s, NULL, ic, FALSE);
13644
13645         /* make the call */
13646         emitcode ("lcall","System_%s",name);
13647
13648         unsavermask(rsave);
13649 }
13650
13651 /*-----------------------------------------------------------------*/
13652 /* genSystemThreadResume -                                         */
13653 /*-----------------------------------------------------------------*/
13654 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13655 {
13656         bitVect *rsave ;
13657         operand *tid,*pid;
13658
13659         assert (nparms==2);
13660         /* save registers that need to be saved */
13661         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13662                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13663
13664         tid = parms[0];
13665         pid = parms[1];
13666
13667         /* PID in R0 */
13668         aopOp(pid,ic,FALSE,FALSE);
13669         emitcode ("mov","r0,%s",
13670                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13671         freeAsmop (pid, NULL, ic, FALSE);
13672
13673         /* tid into ACC */
13674         aopOp(tid,ic,FALSE,FALSE);
13675         emitcode ("mov","a,%s",
13676                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13677         freeAsmop (tid, NULL, ic, FALSE);
13678
13679         emitcode ("lcall","System_ThreadResume");
13680
13681         /* put result into place */
13682         {
13683                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13684                 if (rsym->liveFrom != rsym->liveTo) {
13685                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13686                         aopPut(IC_RESULT(ic),"a",0);
13687                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13688                 }
13689         }
13690         unsavermask(rsave);
13691 }
13692
13693 /*-----------------------------------------------------------------*/
13694 /* genSystemProcessResume -                                        */
13695 /*-----------------------------------------------------------------*/
13696 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13697 {
13698         bitVect *rsave ;
13699         operand *pid;
13700
13701         assert (nparms==1);
13702         /* save registers that need to be saved */
13703         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13704                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13705
13706         pid = parms[0];
13707
13708         /* pid into ACC */
13709         aopOp(pid,ic,FALSE,FALSE);
13710         emitcode ("mov","a,%s",
13711                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13712         freeAsmop (pid, NULL, ic, FALSE);
13713
13714         emitcode ("lcall","System_ProcessResume");
13715
13716         unsavermask(rsave);
13717 }
13718
13719 /*-----------------------------------------------------------------*/
13720 /* genSystem -                                                     */
13721 /*-----------------------------------------------------------------*/
13722 static void genSystem (iCode *ic,int nparms,char *name)
13723 {
13724         assert(nparms == 0);
13725
13726         emitcode ("lcall","System_%s",name);
13727 }
13728
13729 /*-----------------------------------------------------------------*/
13730 /* genSystemPoll -                                                  */
13731 /*-----------------------------------------------------------------*/
13732 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13733 {
13734         bitVect *rsave ;
13735         operand *fp;
13736
13737         assert (nparms==1);
13738         /* save registers that need to be saved */
13739         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13740                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13741
13742         fp = parms[0];
13743         aopOp (fp,ic,FALSE,FALSE);
13744         if (AOP_TYPE (fp) == AOP_IMMD) {
13745                 emitcode ("mov", "dptr,%s",
13746                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13747         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13748                 emitcode ("mov","dpl,%s",
13749                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13750                 emitcode ("mov","dph,%s",
13751                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13752                 emitcode ("mov","dpx,%s",
13753                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13754         }
13755         freeAsmop (fp, NULL, ic, FALSE);
13756
13757         emitcode ("lcall","System_%sPoll",name);
13758
13759         /* put result into place */
13760         {
13761                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13762                 if (rsym->liveFrom != rsym->liveTo) {
13763                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13764                         aopPut(IC_RESULT(ic),"a",0);
13765                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13766                 }
13767         }
13768         unsavermask(rsave);
13769 }
13770
13771 /*-----------------------------------------------------------------*/
13772 /* genSystemGetCurrentID -                                         */
13773 /*-----------------------------------------------------------------*/
13774 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13775 {
13776         assert (nparms==0);
13777
13778         emitcode ("lcall","System_GetCurrent%sId",name);
13779         /* put result into place */
13780         {
13781                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13782                 if (rsym->liveFrom != rsym->liveTo) {
13783                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13784                         aopPut(IC_RESULT(ic),"a",0);
13785                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13786                 }
13787         }
13788 }
13789
13790 /*-----------------------------------------------------------------*/
13791 /* genDjnz - generate decrement & jump if not zero instrucion      */
13792 /*-----------------------------------------------------------------*/
13793 static int
13794 genDjnz (iCode * ic, iCode * ifx)
13795 {
13796   symbol *lbl, *lbl1;
13797   if (!ifx)
13798     return 0;
13799
13800   /* if the if condition has a false label
13801      then we cannot save */
13802   if (IC_FALSE (ifx))
13803     return 0;
13804
13805   /* if the minus is not of the form a = a - 1 */
13806   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13807       !IS_OP_LITERAL (IC_RIGHT (ic)))
13808     return 0;
13809
13810   if (operandLitValue (IC_RIGHT (ic)) != 1)
13811     return 0;
13812
13813   /* if the size of this greater than one then no
13814      saving */
13815   if (getSize (operandType (IC_RESULT (ic))) > 1)
13816     return 0;
13817
13818   /* otherwise we can save BIG */
13819
13820   D (emitcode (";", "genDjnz"));
13821
13822   lbl = newiTempLabel (NULL);
13823   lbl1 = newiTempLabel (NULL);
13824
13825   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13826
13827   if (AOP_NEEDSACC(IC_RESULT(ic)))
13828   {
13829       /* If the result is accessed indirectly via
13830        * the accumulator, we must explicitly write
13831        * it back after the decrement.
13832        */
13833       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13834
13835       if (strcmp(rByte, "a"))
13836       {
13837            /* Something is hopelessly wrong */
13838            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13839                    __FILE__, __LINE__);
13840            /* We can just give up; the generated code will be inefficient,
13841             * but what the hey.
13842             */
13843            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13844            return 0;
13845       }
13846       emitcode ("dec", "%s", rByte);
13847       aopPut (IC_RESULT (ic), rByte, 0);
13848       emitcode ("jnz", "!tlabel", lbl->key + 100);
13849   }
13850   else if (IS_AOP_PREG (IC_RESULT (ic)))
13851     {
13852       emitcode ("dec", "%s",
13853                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13854       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13855       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13856       ifx->generated = 1;
13857       emitcode ("jnz", "!tlabel", lbl->key + 100);
13858     }
13859   else
13860     {
13861       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13862                 lbl->key + 100);
13863     }
13864   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13865   emitLabel (lbl);
13866   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13867   emitLabel (lbl1);
13868
13869   if (!ifx->generated)
13870       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13871   ifx->generated = 1;
13872   return 1;
13873 }
13874
13875 /*-----------------------------------------------------------------*/
13876 /* genReceive - generate code for a receive iCode                  */
13877 /*-----------------------------------------------------------------*/
13878 static void
13879 genReceive (iCode * ic)
13880 {
13881     int size = getSize (operandType (IC_RESULT (ic)));
13882     int offset = 0;
13883     int rb1off ;
13884
13885     D (emitcode (";", "genReceive"));
13886
13887     if (ic->argreg == 1)
13888     {
13889         /* first parameter */
13890         if (AOP_IS_STR(IC_RESULT(ic)))
13891         {
13892             /* Nothing to do: it's already in the proper place. */
13893             return;
13894         }
13895         else
13896         {
13897             bool useDp2;
13898
13899             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13900                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13901                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13902
13903             _G.accInUse++;
13904             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13905             _G.accInUse--;
13906
13907             /* Sanity checking... */
13908             if (AOP_USESDPTR(IC_RESULT(ic)))
13909             {
13910                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13911                         "genReceive got unexpected DPTR.");
13912             }
13913             assignResultValue (IC_RESULT (ic), NULL);
13914         }
13915     }
13916     else if (ic->argreg > 12)
13917     { /* bit parameters */
13918       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13919         {
13920           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13921           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13922           outBitC(IC_RESULT (ic));
13923         }
13924     }
13925     else
13926     {
13927         /* second receive onwards */
13928         /* this gets a little tricky since unused receives will be
13929          eliminated, we have saved the reg in the type field . and
13930          we use that to figure out which register to use */
13931         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13932         rb1off = ic->argreg;
13933         while (size--)
13934         {
13935             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13936         }
13937     }
13938     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13939 }
13940
13941 /*-----------------------------------------------------------------*/
13942 /* genDummyRead - generate code for dummy read of volatiles        */
13943 /*-----------------------------------------------------------------*/
13944 static void
13945 genDummyRead (iCode * ic)
13946 {
13947   operand *op;
13948   int size, offset;
13949
13950   D (emitcode(";", "genDummyRead"));
13951
13952   op = IC_RIGHT (ic);
13953   if (op && IS_SYMOP (op))
13954     {
13955       aopOp (op, ic, FALSE, FALSE);
13956
13957       /* if the result is a bit */
13958       if (AOP_TYPE (op) == AOP_CRY)
13959         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13960       else
13961         {
13962           /* bit variables done */
13963           /* general case */
13964           size = AOP_SIZE (op);
13965           offset = 0;
13966           while (size--)
13967           {
13968             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13969             offset++;
13970           }
13971         }
13972
13973       freeAsmop (op, NULL, ic, TRUE);
13974     }
13975
13976   op = IC_LEFT (ic);
13977   if (op && IS_SYMOP (op))
13978     {
13979       aopOp (op, ic, FALSE, FALSE);
13980
13981       /* if the result is a bit */
13982       if (AOP_TYPE (op) == AOP_CRY)
13983         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13984       else
13985         {
13986           /* bit variables done */
13987           /* general case */
13988           size = AOP_SIZE (op);
13989           offset = 0;
13990           while (size--)
13991           {
13992             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13993             offset++;
13994           }
13995         }
13996
13997       freeAsmop (op, NULL, ic, TRUE);
13998     }
13999 }
14000
14001 /*-----------------------------------------------------------------*/
14002 /* genCritical - generate code for start of a critical sequence    */
14003 /*-----------------------------------------------------------------*/
14004 static void
14005 genCritical (iCode *ic)
14006 {
14007   symbol *tlbl = newiTempLabel (NULL);
14008
14009   D (emitcode(";", "genCritical"));
14010
14011   if (IC_RESULT (ic))
14012     {
14013       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14014       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14015       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14016       aopPut (IC_RESULT (ic), zero, 0);
14017       emitLabel (tlbl);
14018       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14019     }
14020   else
14021     {
14022       emitcode ("setb", "c");
14023       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14024       emitcode ("clr", "c");
14025       emitLabel (tlbl);
14026       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14027     }
14028 }
14029
14030 /*-----------------------------------------------------------------*/
14031 /* genEndCritical - generate code for end of a critical sequence   */
14032 /*-----------------------------------------------------------------*/
14033 static void
14034 genEndCritical (iCode *ic)
14035 {
14036   D(emitcode(";     genEndCritical",""));
14037
14038   if (IC_RIGHT (ic))
14039     {
14040       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14041       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14042         {
14043           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14044           emitcode ("mov", "ea,c");
14045         }
14046       else
14047         {
14048           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14049           emitcode ("rrc", "a");
14050           emitcode ("mov", "ea,c");
14051         }
14052       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14053     }
14054   else
14055     {
14056       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14057       emitcode ("mov", "ea,c");
14058     }
14059 }
14060
14061
14062
14063 /*-----------------------------------------------------------------*/
14064 /* genBuiltIn - calls the appropriate function to  generating code */
14065 /* for a built in function                                         */
14066 /*-----------------------------------------------------------------*/
14067 static void genBuiltIn (iCode *ic)
14068 {
14069         operand *bi_parms[MAX_BUILTIN_ARGS];
14070         int nbi_parms;
14071         iCode *bi_iCode;
14072         symbol *bif;
14073
14074         /* get all the arguments for a built in function */
14075         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14076
14077         /* which function is it */
14078         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14079         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14080                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14081         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14082                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14083         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14084                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14085         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14086                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14087         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14088                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14089         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14090                 genInp(bi_iCode,nbi_parms,bi_parms);
14091         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14092                 genOutp(bi_iCode,nbi_parms,bi_parms);
14093         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14094                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14095                 /* JavaNative builtIns */
14096         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14097                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14098         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14099                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14100         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14101                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14102         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14103                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14104         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14105                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14106         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14107                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14108         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14109                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14110         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14111                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14112         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14113                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14114         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14115                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14116         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14117                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14118         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14119                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14120         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14121                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14122         } else if (strcmp(bif->name,"MM_Free")==0) {
14123                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14124         } else if (strcmp(bif->name,"MM_Deref")==0) {
14125                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14126         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14127                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14128         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14129                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14130         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14131                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14132         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14133                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14134         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14135                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14136         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14137                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14138         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14139                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14140         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14141                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14142         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14143                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14144         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14145                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14146         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14147                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14148         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14149                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14150         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14151                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14152         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14153                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14154         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14155                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14156         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14157                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14158         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14159                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14160         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14161                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14162         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14163                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14164         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14165                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14166         } else {
14167                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14168                 return ;
14169         }
14170         return ;
14171 }
14172
14173 /*-----------------------------------------------------------------*/
14174 /* gen390Code - generate code for Dallas 390 based controllers     */
14175 /*-----------------------------------------------------------------*/
14176 void
14177 gen390Code (iCode * lic)
14178 {
14179   iCode *ic;
14180   int cln = 0;
14181
14182   _G.currentFunc = NULL;
14183   lineHead = lineCurr = NULL;
14184   dptrn[1][0] = "dpl1";
14185   dptrn[1][1] = "dph1";
14186   dptrn[1][2] = "dpx1";
14187
14188   if (options.model == MODEL_FLAT24) {
14189     fReturnSizeDS390 = 5;
14190     fReturn = fReturn24;
14191   } else {
14192     fReturnSizeDS390 = 4;
14193     fReturn = fReturn16;
14194     options.stack10bit=0;
14195   }
14196 #if 1
14197   /* print the allocation information */
14198   if (allocInfo && currFunc)
14199     printAllocInfo (currFunc, codeOutFile);
14200 #endif
14201   /* if debug information required */
14202   if (options.debug && currFunc)
14203     {
14204       debugFile->writeFunction (currFunc, lic);
14205     }
14206   /* stack pointer name */
14207   if (options.useXstack)
14208     spname = "_spx";
14209   else
14210     spname = "sp";
14211
14212
14213   for (ic = lic; ic; ic = ic->next)
14214     {
14215       _G.current_iCode = ic;
14216
14217       if (ic->lineno && cln != ic->lineno)
14218         {
14219           if (options.debug)
14220             {
14221               debugFile->writeCLine (ic);
14222             }
14223           if (!options.noCcodeInAsm) {
14224             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14225                       printCLine(ic->filename, ic->lineno));
14226           }
14227           cln = ic->lineno;
14228         }
14229       if (options.iCodeInAsm) {
14230         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14231       }
14232       /* if the result is marked as
14233          spilt and rematerializable or code for
14234          this has already been generated then
14235          do nothing */
14236       if (resultRemat (ic) || ic->generated)
14237         continue;
14238
14239       /* depending on the operation */
14240       switch (ic->op)
14241         {
14242         case '!':
14243           genNot (ic);
14244           break;
14245
14246         case '~':
14247           genCpl (ic);
14248           break;
14249
14250         case UNARYMINUS:
14251           genUminus (ic);
14252           break;
14253
14254         case IPUSH:
14255           genIpush (ic);
14256           break;
14257
14258         case IPOP:
14259           /* IPOP happens only when trying to restore a
14260              spilt live range, if there is an ifx statement
14261              following this pop then the if statement might
14262              be using some of the registers being popped which
14263              would destory the contents of the register so
14264              we need to check for this condition and handle it */
14265           if (ic->next &&
14266               ic->next->op == IFX &&
14267               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14268             genIfx (ic->next, ic);
14269           else
14270             genIpop (ic);
14271           break;
14272
14273         case CALL:
14274           genCall (ic);
14275           break;
14276
14277         case PCALL:
14278           genPcall (ic);
14279           break;
14280
14281         case FUNCTION:
14282           genFunction (ic);
14283           break;
14284
14285         case ENDFUNCTION:
14286           genEndFunction (ic);
14287           break;
14288
14289         case RETURN:
14290           genRet (ic);
14291           break;
14292
14293         case LABEL:
14294           genLabel (ic);
14295           break;
14296
14297         case GOTO:
14298           genGoto (ic);
14299           break;
14300
14301         case '+':
14302           genPlus (ic);
14303           break;
14304
14305         case '-':
14306           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14307             genMinus (ic);
14308           break;
14309
14310         case '*':
14311           genMult (ic);
14312           break;
14313
14314         case '/':
14315           genDiv (ic);
14316           break;
14317
14318         case '%':
14319           genMod (ic);
14320           break;
14321
14322         case '>':
14323           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14324           break;
14325
14326         case '<':
14327           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14328           break;
14329
14330         case LE_OP:
14331         case GE_OP:
14332         case NE_OP:
14333
14334           /* note these two are xlated by algebraic equivalence
14335              during parsing SDCC.y */
14336           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14337                   "got '>=' or '<=' shouldn't have come here");
14338           break;
14339
14340         case EQ_OP:
14341           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14342           break;
14343
14344         case AND_OP:
14345           genAndOp (ic);
14346           break;
14347
14348         case OR_OP:
14349           genOrOp (ic);
14350           break;
14351
14352         case '^':
14353           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14354           break;
14355
14356         case '|':
14357           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14358           break;
14359
14360         case BITWISEAND:
14361           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14362           break;
14363
14364         case INLINEASM:
14365           genInline (ic);
14366           break;
14367
14368         case RRC:
14369           genRRC (ic);
14370           break;
14371
14372         case RLC:
14373           genRLC (ic);
14374           break;
14375
14376         case GETHBIT:
14377           genGetHbit (ic);
14378           break;
14379
14380         case LEFT_OP:
14381           genLeftShift (ic);
14382           break;
14383
14384         case RIGHT_OP:
14385           genRightShift (ic);
14386           break;
14387
14388         case GET_VALUE_AT_ADDRESS:
14389           genPointerGet (ic,
14390                          hasInc (IC_LEFT (ic), ic,
14391                                  getSize (operandType (IC_RESULT (ic)))));
14392           break;
14393
14394         case '=':
14395           if (POINTER_SET (ic))
14396             genPointerSet (ic,
14397                            hasInc (IC_RESULT (ic), ic,
14398                                    getSize (operandType (IC_RIGHT (ic)))));
14399           else
14400             genAssign (ic);
14401           break;
14402
14403         case IFX:
14404           genIfx (ic, NULL);
14405           break;
14406
14407         case ADDRESS_OF:
14408           genAddrOf (ic);
14409           break;
14410
14411         case JUMPTABLE:
14412           genJumpTab (ic);
14413           break;
14414
14415         case CAST:
14416           genCast (ic);
14417           break;
14418
14419         case RECEIVE:
14420           genReceive (ic);
14421           break;
14422
14423         case SEND:
14424           if (ic->builtinSEND)
14425             genBuiltIn(ic);
14426           else
14427             addSet (&_G.sendSet, ic);
14428           break;
14429
14430         case DUMMY_READ_VOLATILE:
14431           genDummyRead (ic);
14432           break;
14433
14434         case CRITICAL:
14435           genCritical (ic);
14436           break;
14437
14438         case ENDCRITICAL:
14439           genEndCritical (ic);
14440           break;
14441
14442         case SWAP:
14443           genSwap (ic);
14444           break;
14445
14446 #if 0 // obsolete, and buggy for != xdata
14447         case ARRAYINIT:
14448             genArrayInit(ic);
14449             break;
14450 #endif
14451
14452         default:
14453           ic = ic;
14454         }
14455     }
14456
14457
14458   /* now we are ready to call the
14459      peep hole optimizer */
14460   if (!options.nopeep)
14461     peepHole (&lineHead);
14462
14463   /* now do the actual printing */
14464   printLine (lineHead, codeOutFile);
14465   return;
14466 }