* src/ds390/gen.c (aopGetUsesAcc): handle AOP_DPTR2 and AOP_DPTRn too
[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 ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10908              AOP_SIZE(result) > 1 &&
10909              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10910
10911       size = AOP_SIZE (result) - 1;
10912       if (AOP_INDPTRn(left)) {
10913           genSetDPTR(AOP(left)->aopu.dptr);
10914       }
10915       while (size--) emitcode ("lcall","__decdptr");
10916       if (AOP_INDPTRn(left)) {
10917           genSetDPTR(0);
10918       }
10919   }
10920
10921   freeAsmop (result, NULL, ic, TRUE);
10922   freeAsmop (left, NULL, ic, TRUE);
10923 }
10924
10925 /*-----------------------------------------------------------------*/
10926 /* genGenPointerGet - get value from generic pointer space         */
10927 /*-----------------------------------------------------------------*/
10928 static void
10929 genGenPointerGet (operand * left,
10930                   operand * result, iCode * ic, iCode * pi)
10931 {
10932   int size, offset;
10933   bool pushedB;
10934   sym_link *retype = getSpec (operandType (result));
10935   sym_link *letype = getSpec (operandType (left));
10936
10937   D (emitcode (";", "genGenPointerGet"));
10938
10939   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10940
10941   pushedB = pushB ();
10942   /* if the operand is already in dptr
10943      then we do nothing else we move the value to dptr */
10944   if (AOP_TYPE (left) != AOP_STR)
10945     {
10946       /* if this is rematerializable */
10947       if (AOP_TYPE (left) == AOP_IMMD)
10948         {
10949           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10950           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10951             {
10952               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10953             }
10954           else
10955             {
10956               emitcode ("mov", "b,#%d", pointerCode (retype));
10957             }
10958         }
10959       else
10960         {                       /* we need to get it byte by byte */
10961           _startLazyDPSEvaluation ();
10962           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10963           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10964           if (options.model == MODEL_FLAT24) {
10965               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10966               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10967           } else {
10968               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10969           }
10970           _endLazyDPSEvaluation ();
10971         }
10972     }
10973
10974   /* so dptr-b now contains the address */
10975   aopOp (result, ic, FALSE, TRUE);
10976
10977   /* if bit then unpack */
10978   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10979   {
10980     genUnpackBits (result, "dptr", GPOINTER);
10981   }
10982   else
10983     {
10984         size = AOP_SIZE (result);
10985         offset = 0;
10986
10987         while (size--)
10988         {
10989             if (size)
10990             {
10991                 // Get two bytes at a time, results in _AP & A.
10992                 // dptr will be incremented ONCE by __gptrgetWord.
10993                 //
10994                 // Note: any change here must be coordinated
10995                 // with the implementation of __gptrgetWord
10996                 // in device/lib/_gptrget.c
10997                 emitcode ("lcall", "__gptrgetWord");
10998                 aopPut (result, DP2_RESULT_REG, offset++);
10999                 aopPut (result, "a", offset++);
11000                 size--;
11001             }
11002             else
11003             {
11004                 // Only one byte to get.
11005                 emitcode ("lcall", "__gptrget");
11006                 aopPut (result, "a", offset++);
11007             }
11008
11009             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11010             {
11011                 emitcode ("inc", "dptr");
11012             }
11013         }
11014     }
11015
11016   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11017     _startLazyDPSEvaluation ();
11018
11019     aopPut (left, "dpl", 0);
11020     aopPut (left, "dph", 1);
11021     if (options.model == MODEL_FLAT24) {
11022         aopPut (left, "dpx", 2);
11023         aopPut (left, "b", 3);
11024     } else  aopPut (left, "b", 2);
11025
11026     _endLazyDPSEvaluation ();
11027
11028     pi->generated = 1;
11029   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11030              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11031
11032       size = AOP_SIZE (result) - 1;
11033       while (size--) emitcode ("lcall","__decdptr");
11034   }
11035   popB (pushedB);
11036
11037   freeAsmop (result, NULL, ic, TRUE);
11038   freeAsmop (left, NULL, ic, TRUE);
11039 }
11040
11041 /*-----------------------------------------------------------------*/
11042 /* genPointerGet - generate code for pointer get                   */
11043 /*-----------------------------------------------------------------*/
11044 static void
11045 genPointerGet (iCode * ic, iCode *pi)
11046 {
11047   operand *left, *result;
11048   sym_link *type, *etype;
11049   int p_type;
11050
11051   D (emitcode (";", "genPointerGet"));
11052
11053   left = IC_LEFT (ic);
11054   result = IC_RESULT (ic);
11055
11056   /* depending on the type of pointer we need to
11057      move it to the correct pointer register */
11058   type = operandType (left);
11059   etype = getSpec (type);
11060   /* if left is of type of pointer then it is simple */
11061   if (IS_PTR (type) && !IS_FUNC (type->next))
11062     p_type = DCL_TYPE (type);
11063   else
11064     {
11065       /* we have to go by the storage class */
11066       p_type = PTR_TYPE (SPEC_OCLS (etype));
11067     }
11068
11069   /* special case when cast remat */
11070   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11071       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11072     {
11073       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11074       type = operandType (left);
11075       p_type = DCL_TYPE (type);
11076     }
11077   /* now that we have the pointer type we assign
11078      the pointer values */
11079   switch (p_type)
11080     {
11081
11082     case POINTER:
11083     case IPOINTER:
11084       genNearPointerGet (left, result, ic, pi);
11085       break;
11086
11087     case PPOINTER:
11088       genPagedPointerGet (left, result, ic, pi);
11089       break;
11090
11091     case FPOINTER:
11092       genFarPointerGet (left, result, ic, pi);
11093       break;
11094
11095     case CPOINTER:
11096       genCodePointerGet (left, result, ic, pi);
11097       break;
11098
11099     case GPOINTER:
11100       genGenPointerGet (left, result, ic, pi);
11101       break;
11102     }
11103 }
11104
11105
11106 /*-----------------------------------------------------------------*/
11107 /* genPackBits - generates code for packed bit storage             */
11108 /*-----------------------------------------------------------------*/
11109 static void
11110 genPackBits (sym_link * etype,
11111              operand * right,
11112              char *rname, int p_type)
11113 {
11114   int offset = 0;       /* source byte offset */
11115   int rlen = 0;         /* remaining bitfield length */
11116   int blen;             /* bitfield length */
11117   int bstr;             /* bitfield starting bit within byte */
11118   int litval;           /* source literal value (if AOP_LIT) */
11119   unsigned char mask;   /* bitmask within current byte */
11120
11121   D(emitcode (";     genPackBits",""));
11122
11123   blen = SPEC_BLEN (etype);
11124   bstr = SPEC_BSTR (etype);
11125
11126   /* If the bitfield length is less than a byte */
11127   if (blen < 8)
11128     {
11129       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11130               (unsigned char) (0xFF >> (8 - bstr)));
11131
11132       if (AOP_TYPE (right) == AOP_LIT)
11133         {
11134           /* Case with a bitfield length <8 and literal source
11135           */
11136           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11137           litval <<= bstr;
11138           litval &= (~mask) & 0xff;
11139           emitPtrByteGet (rname, p_type, FALSE);
11140           if ((mask|litval)!=0xff)
11141             emitcode ("anl","a,#!constbyte", mask);
11142           if (litval)
11143             emitcode ("orl","a,#!constbyte", litval);
11144         }
11145       else
11146         {
11147           if ((blen==1) && (p_type!=GPOINTER))
11148             {
11149               /* Case with a bitfield length == 1 and no generic pointer
11150               */
11151               if (AOP_TYPE (right) == AOP_CRY)
11152                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11153               else
11154                 {
11155                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11156                   emitcode ("rrc","a");
11157                 }
11158               emitPtrByteGet (rname, p_type, FALSE);
11159               emitcode ("mov","acc.%d,c",bstr);
11160             }
11161           else
11162             {
11163               bool pushedB;
11164               /* Case with a bitfield length < 8 and arbitrary source
11165               */
11166               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11167               /* shift and mask source value */
11168               AccLsh (bstr);
11169               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11170
11171               pushedB = pushB ();
11172               /* transfer A to B and get next byte */
11173               emitPtrByteGet (rname, p_type, TRUE);
11174
11175               emitcode ("anl", "a,#!constbyte", mask);
11176               emitcode ("orl", "a,b");
11177               if (p_type == GPOINTER)
11178                 emitcode ("pop", "b");
11179
11180               popB (pushedB);
11181            }
11182         }
11183
11184       emitPtrByteSet (rname, p_type, "a");
11185       return;
11186     }
11187
11188   /* Bit length is greater than 7 bits. In this case, copy  */
11189   /* all except the partial byte at the end                 */
11190   for (rlen=blen;rlen>=8;rlen-=8)
11191     {
11192       emitPtrByteSet (rname, p_type,
11193                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11194       if (rlen>8)
11195         emitcode ("inc", "%s", rname);
11196     }
11197
11198   /* If there was a partial byte at the end */
11199   if (rlen)
11200     {
11201       mask = (((unsigned char) -1 << rlen) & 0xff);
11202
11203       if (AOP_TYPE (right) == AOP_LIT)
11204         {
11205           /* Case with partial byte and literal source
11206           */
11207           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11208           litval >>= (blen-rlen);
11209           litval &= (~mask) & 0xff;
11210           emitPtrByteGet (rname, p_type, FALSE);
11211           if ((mask|litval)!=0xff)
11212             emitcode ("anl","a,#!constbyte", mask);
11213           if (litval)
11214             emitcode ("orl","a,#!constbyte", litval);
11215         }
11216       else
11217         {
11218           bool pushedB;
11219           /* Case with partial byte and arbitrary source
11220           */
11221           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11222           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11223
11224           pushedB = pushB ();
11225           /* transfer A to B and get next byte */
11226           emitPtrByteGet (rname, p_type, TRUE);
11227
11228           emitcode ("anl", "a,#!constbyte", mask);
11229           emitcode ("orl", "a,b");
11230           if (p_type == GPOINTER)
11231             emitcode ("pop", "b");
11232
11233           popB (pushedB);
11234         }
11235       emitPtrByteSet (rname, p_type, "a");
11236     }
11237 }
11238
11239
11240 /*-----------------------------------------------------------------*/
11241 /* genDataPointerSet - remat pointer to data space                 */
11242 /*-----------------------------------------------------------------*/
11243 static void
11244 genDataPointerSet (operand * right,
11245                    operand * result,
11246                    iCode * ic)
11247 {
11248   int size, offset = 0;
11249   char *l, buffer[256];
11250
11251   D (emitcode (";", "genDataPointerSet"));
11252
11253   aopOp (right, ic, FALSE, FALSE);
11254
11255   l = aopGet (result, 0, FALSE, TRUE, NULL);
11256   size = AOP_SIZE (right);
11257   while (size--)
11258     {
11259       if (offset)
11260           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11261       else
11262           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11263       emitcode ("mov", "%s,%s", buffer,
11264                 aopGet (right, offset++, FALSE, FALSE, NULL));
11265     }
11266
11267   freeAsmop (result, NULL, ic, TRUE);
11268   freeAsmop (right, NULL, ic, TRUE);
11269 }
11270
11271 /*-----------------------------------------------------------------*/
11272 /* genNearPointerSet - emitcode for near pointer put                */
11273 /*-----------------------------------------------------------------*/
11274 static void
11275 genNearPointerSet (operand * right,
11276                    operand * result,
11277                    iCode * ic,
11278                    iCode * pi)
11279 {
11280   asmop *aop = NULL;
11281   char *rname, *l;
11282   sym_link *retype, *letype;
11283   sym_link *ptype = operandType (result);
11284
11285   D (emitcode (";", "genNearPointerSet"));
11286
11287   retype = getSpec (operandType (right));
11288   letype = getSpec (ptype);
11289
11290   aopOp (result, ic, FALSE, FALSE);
11291
11292   /* if the result is rematerializable &
11293      in data space & not a bit variable */
11294   if (AOP_TYPE (result) == AOP_IMMD &&
11295       DCL_TYPE (ptype) == POINTER &&
11296       !IS_BITVAR (retype) &&
11297       !IS_BITVAR (letype))
11298     {
11299       genDataPointerSet (right, result, ic);
11300       return;
11301     }
11302
11303   /* if the value is already in a pointer register
11304      then don't need anything more */
11305   if (!AOP_INPREG (AOP (result)))
11306     {
11307       /* otherwise get a free pointer register */
11308       regs *preg;
11309
11310       aop = newAsmop (0);
11311       preg = getFreePtr (ic, &aop, FALSE);
11312       emitcode ("mov", "%s,%s",
11313                 preg->name,
11314                 aopGet (result, 0, FALSE, TRUE, NULL));
11315       rname = preg->name;
11316     }
11317   else
11318     {
11319       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11320     }
11321
11322   aopOp (right, ic, FALSE, FALSE);
11323
11324   /* if bitfield then unpack the bits */
11325   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11326     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11327   else
11328     {
11329       /* we can just get the values */
11330       int size = AOP_SIZE (right);
11331       int offset = 0;
11332
11333       while (size--)
11334         {
11335           l = aopGet (right, offset, FALSE, TRUE, NULL);
11336           if ((*l == '@') || (strcmp (l, "acc") == 0))
11337             {
11338               MOVA (l);
11339               emitcode ("mov", "@%s,a", rname);
11340             }
11341           else
11342             emitcode ("mov", "@%s,%s", rname, l);
11343           if (size || pi)
11344             emitcode ("inc", "%s", rname);
11345           offset++;
11346         }
11347     }
11348
11349   /* now some housekeeping stuff */
11350   if (aop)      /* we had to allocate for this iCode */
11351     {
11352       if (pi)
11353         aopPut (result, rname, 0);
11354       freeAsmop (NULL, aop, ic, TRUE);
11355     }
11356   else
11357     {
11358       /* we did not allocate which means left
11359          already in a pointer register, then
11360          if size > 0 && this could be used again
11361          we have to point it back to where it
11362          belongs */
11363       if (AOP_SIZE (right) > 1 &&
11364           !OP_SYMBOL (result)->remat &&
11365           (OP_SYMBOL (result)->liveTo > ic->seq ||
11366            ic->depth) &&
11367           !pi)
11368         {
11369           int size = AOP_SIZE (right) - 1;
11370           while (size--)
11371             emitcode ("dec", "%s", rname);
11372         }
11373     }
11374
11375   /* done */
11376   if (pi) pi->generated = 1;
11377   freeAsmop (result, NULL, ic, TRUE);
11378   freeAsmop (right, NULL, ic, TRUE);
11379 }
11380
11381 /*-----------------------------------------------------------------*/
11382 /* genPagedPointerSet - emitcode for Paged pointer put             */
11383 /*-----------------------------------------------------------------*/
11384 static void
11385 genPagedPointerSet (operand * right,
11386                     operand * result,
11387                     iCode * ic,
11388                     iCode *pi)
11389 {
11390   asmop *aop = NULL;
11391   char *rname, *l;
11392   sym_link *retype, *letype;
11393
11394   D (emitcode (";", "genPagedPointerSet"));
11395
11396   retype = getSpec (operandType (right));
11397   letype = getSpec (operandType (result));
11398
11399   aopOp (result, ic, FALSE, FALSE);
11400
11401   /* if the value is already in a pointer register
11402      then don't need anything more */
11403   if (!AOP_INPREG (AOP (result)))
11404     {
11405       /* otherwise get a free pointer register */
11406       regs *preg;
11407
11408       aop = newAsmop (0);
11409       preg = getFreePtr (ic, &aop, FALSE);
11410       emitcode ("mov", "%s,%s",
11411                 preg->name,
11412                 aopGet (result, 0, FALSE, TRUE, NULL));
11413       rname = preg->name;
11414     }
11415   else
11416     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11417
11418   aopOp (right, ic, FALSE, FALSE);
11419
11420   /* if bitfield then unpack the bits */
11421   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11422     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11423   else
11424     {
11425       /* we have can just get the values */
11426       int size = AOP_SIZE (right);
11427       int offset = 0;
11428
11429       while (size--)
11430         {
11431           l = aopGet (right, offset, FALSE, TRUE, NULL);
11432           MOVA (l);
11433           emitcode ("movx", "@%s,a", rname);
11434
11435           if (size || pi)
11436             emitcode ("inc", "%s", rname);
11437
11438           offset++;
11439         }
11440     }
11441
11442   /* now some housekeeping stuff */
11443   if (aop)
11444     {
11445       if (pi)
11446         aopPut (result, rname, 0);
11447       /* we had to allocate for this iCode */
11448       freeAsmop (NULL, aop, ic, TRUE);
11449     }
11450   else
11451     {
11452       /* we did not allocate which means left
11453          already in a pointer register, then
11454          if size > 0 && this could be used again
11455          we have to point it back to where it
11456          belongs */
11457       if (AOP_SIZE (right) > 1 &&
11458           !OP_SYMBOL (result)->remat &&
11459           (OP_SYMBOL (result)->liveTo > ic->seq ||
11460            ic->depth) &&
11461           !pi)
11462         {
11463           int size = AOP_SIZE (right) - 1;
11464           while (size--)
11465             emitcode ("dec", "%s", rname);
11466         }
11467     }
11468
11469   /* done */
11470   if (pi) pi->generated = 1;
11471   freeAsmop (result, NULL, ic, TRUE);
11472   freeAsmop (right, NULL, ic, TRUE);
11473 }
11474
11475 /*-----------------------------------------------------------------*/
11476 /* genFarPointerSet - set value from far space                     */
11477 /*-----------------------------------------------------------------*/
11478 static void
11479 genFarPointerSet (operand * right,
11480                   operand * result, iCode * ic, iCode *pi)
11481 {
11482   int size, offset, dopi=1;
11483   sym_link *retype = getSpec (operandType (right));
11484   sym_link *letype = getSpec (operandType (result));
11485
11486   aopOp (result, ic, FALSE, FALSE);
11487
11488   /* if the operand is already in dptr
11489      then we do nothing else we move the value to dptr */
11490   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11491     {
11492       /* if this is remateriazable */
11493       if (AOP_TYPE (result) == AOP_IMMD)
11494         emitcode ("mov", "dptr,%s",
11495                   aopGet (result, 0, TRUE, FALSE, NULL));
11496       else
11497         {
11498           /* we need to get it byte by byte */
11499           _startLazyDPSEvaluation ();
11500           if (AOP_TYPE (result) != AOP_DPTR)
11501             {
11502               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11503               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11504               if (options.model == MODEL_FLAT24)
11505                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11506             }
11507           else
11508             {
11509               /* We need to generate a load to DPTR indirect through DPTR. */
11510               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11511
11512               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11513               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11514               if (options.model == MODEL_FLAT24)
11515                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11516               emitcode ("pop", "dph");
11517               emitcode ("pop", "dpl");
11518               dopi=0;
11519             }
11520           _endLazyDPSEvaluation ();
11521         }
11522     }
11523   /* so dptr now contains the address */
11524   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11525
11526   /* if bit then unpack */
11527   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11528   {
11529       if (AOP_INDPTRn(result)) {
11530           genSetDPTR(AOP(result)->aopu.dptr);
11531       }
11532       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11533       if (AOP_INDPTRn(result)) {
11534           genSetDPTR(0);
11535       }
11536   } else {
11537       size = AOP_SIZE (right);
11538       offset = 0;
11539       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11540           while (size--) {
11541               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11542
11543               genSetDPTR(AOP(result)->aopu.dptr);
11544               emitcode ("movx", "@dptr,a");
11545               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11546                   emitcode ("inc", "dptr");
11547               genSetDPTR (0);
11548           }
11549       } else {
11550           _startLazyDPSEvaluation ();
11551           while (size--) {
11552               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11553
11554               if (AOP_INDPTRn(result)) {
11555                   genSetDPTR(AOP(result)->aopu.dptr);
11556               } else {
11557                   genSetDPTR (0);
11558               }
11559               _flushLazyDPS ();
11560
11561               emitcode ("movx", "@dptr,a");
11562               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11563                   emitcode ("inc", "dptr");
11564           }
11565           _endLazyDPSEvaluation ();
11566       }
11567   }
11568
11569   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11570       if (!AOP_INDPTRn(result)) {
11571           _startLazyDPSEvaluation ();
11572
11573           aopPut (result,"dpl",0);
11574           aopPut (result,"dph",1);
11575           if (options.model == MODEL_FLAT24)
11576               aopPut (result,"dpx",2);
11577
11578           _endLazyDPSEvaluation ();
11579       }
11580       pi->generated=1;
11581   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11582              AOP_SIZE(right) > 1 &&
11583              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11584
11585       size = AOP_SIZE (right) - 1;
11586       if (AOP_INDPTRn(result)) {
11587           genSetDPTR(AOP(result)->aopu.dptr);
11588       }
11589       while (size--) emitcode ("lcall","__decdptr");
11590       if (AOP_INDPTRn(result)) {
11591           genSetDPTR(0);
11592       }
11593   }
11594   freeAsmop (result, NULL, ic, TRUE);
11595   freeAsmop (right, NULL, ic, TRUE);
11596 }
11597
11598 /*-----------------------------------------------------------------*/
11599 /* genGenPointerSet - set value from generic pointer space         */
11600 /*-----------------------------------------------------------------*/
11601 static void
11602 genGenPointerSet (operand * right,
11603                   operand * result, iCode * ic, iCode *pi)
11604 {
11605   int size, offset;
11606   bool pushedB;
11607   sym_link *retype = getSpec (operandType (right));
11608   sym_link *letype = getSpec (operandType (result));
11609
11610   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11611
11612   pushedB = pushB ();
11613   /* if the operand is already in dptr
11614      then we do nothing else we move the value to dptr */
11615   if (AOP_TYPE (result) != AOP_STR)
11616     {
11617       _startLazyDPSEvaluation ();
11618       /* if this is remateriazable */
11619       if (AOP_TYPE (result) == AOP_IMMD)
11620         {
11621           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11622           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11623           {
11624               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11625           }
11626           else
11627           {
11628               emitcode ("mov",
11629                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11630           }
11631         }
11632       else
11633         {                       /* we need to get it byte by byte */
11634           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11635           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11636           if (options.model == MODEL_FLAT24) {
11637             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11638             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11639           } else {
11640             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11641           }
11642         }
11643       _endLazyDPSEvaluation ();
11644     }
11645   /* so dptr + b now contains the address */
11646   aopOp (right, ic, FALSE, TRUE);
11647
11648   /* if bit then unpack */
11649   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11650     {
11651         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11652     }
11653   else
11654     {
11655         size = AOP_SIZE (right);
11656         offset = 0;
11657
11658         _startLazyDPSEvaluation ();
11659         while (size--)
11660         {
11661             if (size)
11662             {
11663                 // Set two bytes at a time, passed in _AP & A.
11664                 // dptr will be incremented ONCE by __gptrputWord.
11665                 //
11666                 // Note: any change here must be coordinated
11667                 // with the implementation of __gptrputWord
11668                 // in device/lib/_gptrput.c
11669                 emitcode("mov", "_ap, %s",
11670                          aopGet (right, offset++, FALSE, FALSE, NULL));
11671                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11672
11673                 genSetDPTR (0);
11674                 _flushLazyDPS ();
11675                 emitcode ("lcall", "__gptrputWord");
11676                 size--;
11677             }
11678             else
11679             {
11680                 // Only one byte to put.
11681                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11682
11683                 genSetDPTR (0);
11684                 _flushLazyDPS ();
11685                 emitcode ("lcall", "__gptrput");
11686             }
11687
11688             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11689             {
11690                 emitcode ("inc", "dptr");
11691             }
11692         }
11693         _endLazyDPSEvaluation ();
11694     }
11695
11696   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11697       _startLazyDPSEvaluation ();
11698
11699       aopPut (result, "dpl",0);
11700       aopPut (result, "dph",1);
11701       if (options.model == MODEL_FLAT24) {
11702           aopPut (result, "dpx",2);
11703           aopPut (result, "b",3);
11704       } else {
11705           aopPut (result, "b",2);
11706       }
11707       _endLazyDPSEvaluation ();
11708
11709       pi->generated=1;
11710   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11711              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11712
11713       size = AOP_SIZE (right) - 1;
11714       while (size--) emitcode ("lcall","__decdptr");
11715   }
11716   popB (pushedB);
11717
11718   freeAsmop (result, NULL, ic, TRUE);
11719   freeAsmop (right, NULL, ic, TRUE);
11720 }
11721
11722 /*-----------------------------------------------------------------*/
11723 /* genPointerSet - stores the value into a pointer location        */
11724 /*-----------------------------------------------------------------*/
11725 static void
11726 genPointerSet (iCode * ic, iCode *pi)
11727 {
11728   operand *right, *result;
11729   sym_link *type, *etype;
11730   int p_type;
11731
11732   D (emitcode (";", "genPointerSet"));
11733
11734   right = IC_RIGHT (ic);
11735   result = IC_RESULT (ic);
11736
11737   /* depending on the type of pointer we need to
11738      move it to the correct pointer register */
11739   type = operandType (result);
11740   etype = getSpec (type);
11741   /* if left is of type of pointer then it is simple */
11742   if (IS_PTR (type) && !IS_FUNC (type->next))
11743     {
11744       p_type = DCL_TYPE (type);
11745     }
11746   else
11747     {
11748       /* we have to go by the storage class */
11749       p_type = PTR_TYPE (SPEC_OCLS (etype));
11750     }
11751
11752   /* special case when cast remat */
11753   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11754       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11755           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11756           type = operandType (result);
11757           p_type = DCL_TYPE (type);
11758   }
11759
11760   /* now that we have the pointer type we assign
11761      the pointer values */
11762   switch (p_type)
11763     {
11764
11765     case POINTER:
11766     case IPOINTER:
11767       genNearPointerSet (right, result, ic, pi);
11768       break;
11769
11770     case PPOINTER:
11771       genPagedPointerSet (right, result, ic, pi);
11772       break;
11773
11774     case FPOINTER:
11775       genFarPointerSet (right, result, ic, pi);
11776       break;
11777
11778     case GPOINTER:
11779       genGenPointerSet (right, result, ic, pi);
11780       break;
11781
11782     default:
11783       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11784               "genPointerSet: illegal pointer type");
11785     }
11786 }
11787
11788 /*-----------------------------------------------------------------*/
11789 /* genIfx - generate code for Ifx statement                        */
11790 /*-----------------------------------------------------------------*/
11791 static void
11792 genIfx (iCode * ic, iCode * popIc)
11793 {
11794   operand *cond = IC_COND (ic);
11795   int isbit = 0;
11796   char *dup = NULL;
11797
11798   D (emitcode (";", "genIfx"));
11799
11800   aopOp (cond, ic, FALSE, FALSE);
11801
11802   /* get the value into acc */
11803   if (AOP_TYPE (cond) != AOP_CRY)
11804     {
11805       toBoolean (cond);
11806     }
11807   else
11808     {
11809       isbit = 1;
11810       if (AOP(cond)->aopu.aop_dir)
11811         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11812     }
11813
11814   /* the result is now in the accumulator or a directly addressable bit */
11815   freeAsmop (cond, NULL, ic, TRUE);
11816
11817   /* if there was something to be popped then do it */
11818   if (popIc)
11819     genIpop (popIc);
11820
11821   /* if the condition is a bit variable */
11822   if (isbit && dup)
11823     genIfxJump (ic, dup);
11824   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11825     genIfxJump (ic, SPIL_LOC (cond)->rname);
11826   else if (isbit && !IS_ITEMP (cond))
11827     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11828   else
11829     genIfxJump (ic, "a");
11830
11831   ic->generated = 1;
11832 }
11833
11834 /*-----------------------------------------------------------------*/
11835 /* genAddrOf - generates code for address of                       */
11836 /*-----------------------------------------------------------------*/
11837 static void
11838 genAddrOf (iCode * ic)
11839 {
11840   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11841   int size, offset;
11842
11843   D (emitcode (";", "genAddrOf"));
11844
11845   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11846
11847   /* if the operand is on the stack then we
11848      need to get the stack offset of this
11849      variable */
11850   if (sym->onStack)
11851   {
11852
11853       /* if 10 bit stack */
11854       if (options.stack10bit) {
11855           char buff[10];
11856           int  offset;
11857
11858           tsprintf(buff, sizeof(buff),
11859                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11860           /* if it has an offset then we need to compute it */
11861 /*        emitcode ("subb", "a,#!constbyte", */
11862 /*                  -((sym->stack < 0) ? */
11863 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11864 /*                    ((short) sym->stack)) & 0xff); */
11865 /*        emitcode ("mov","b,a"); */
11866 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11867 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11868 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11869           if (sym->stack) {
11870               emitcode ("mov", "a,_bpx");
11871               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11872                                              ((char) (sym->stack - _G.nRegsSaved)) :
11873                                              ((char) sym->stack )) & 0xff);
11874               emitcode ("mov", "b,a");
11875               emitcode ("mov", "a,_bpx+1");
11876
11877               offset = (((sym->stack < 0) ?
11878                          ((short) (sym->stack - _G.nRegsSaved)) :
11879                          ((short) sym->stack )) >> 8) & 0xff;
11880
11881               emitcode ("addc","a,#!constbyte", offset);
11882
11883               aopPut (IC_RESULT (ic), "b", 0);
11884               aopPut (IC_RESULT (ic), "a", 1);
11885               aopPut (IC_RESULT (ic), buff, 2);
11886           } else {
11887               /* we can just move _bp */
11888               aopPut (IC_RESULT (ic), "_bpx", 0);
11889               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11890               aopPut (IC_RESULT (ic), buff, 2);
11891           }
11892       } else {
11893           /* if it has an offset then we need to compute it */
11894           if (sym->stack)
11895             {
11896               emitcode ("mov", "a,_bp");
11897               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11898               aopPut (IC_RESULT (ic), "a", 0);
11899             }
11900           else
11901             {
11902               /* we can just move _bp */
11903               aopPut (IC_RESULT (ic), "_bp", 0);
11904             }
11905           /* fill the result with zero */
11906           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11907
11908
11909           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11910               fprintf (stderr,
11911                        "*** warning: pointer to stack var truncated.\n");
11912           }
11913
11914           offset = 1;
11915           while (size--)
11916             {
11917               aopPut (IC_RESULT (ic), zero, offset++);
11918             }
11919       }
11920       goto release;
11921   }
11922
11923   /* object not on stack then we need the name */
11924   size = AOP_SIZE (IC_RESULT (ic));
11925   offset = 0;
11926
11927   while (size--)
11928     {
11929       char s[SDCC_NAME_MAX];
11930       if (offset) {
11931           switch (offset) {
11932           case 1:
11933               tsprintf(s, sizeof(s), "#!his",sym->rname);
11934               break;
11935           case 2:
11936               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11937               break;
11938           case 3:
11939               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11940               break;
11941           default: /* should not need this (just in case) */
11942               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11943                        sym->rname,
11944                        offset * 8);
11945           }
11946       }
11947       else
11948       {
11949           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11950       }
11951
11952       aopPut (IC_RESULT (ic), s, offset++);
11953     }
11954
11955 release:
11956   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11957
11958 }
11959
11960 #if 0 // obsolete, and buggy for != xdata
11961 /*-----------------------------------------------------------------*/
11962 /* genArrayInit - generates code for address of                       */
11963 /*-----------------------------------------------------------------*/
11964 static void
11965 genArrayInit (iCode * ic)
11966 {
11967     literalList *iLoop;
11968     int         ix, count;
11969     int         elementSize = 0, eIndex;
11970     unsigned    val, lastVal;
11971     sym_link    *type;
11972     operand     *left=IC_LEFT(ic);
11973
11974     D (emitcode (";", "genArrayInit"));
11975
11976     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11977
11978     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11979     {
11980         // Load immediate value into DPTR.
11981         emitcode("mov", "dptr, %s",
11982              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11983     }
11984     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11985     {
11986 #if 0
11987       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11988               "Unexpected operand to genArrayInit.\n");
11989       exit(1);
11990 #else
11991       // a regression because of SDCCcse.c:1.52
11992       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11993       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11994       if (options.model == MODEL_FLAT24)
11995         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11996 #endif
11997     }
11998
11999     type = operandType(IC_LEFT(ic));
12000
12001     if (type && type->next)
12002     {
12003         elementSize = getSize(type->next);
12004     }
12005     else
12006     {
12007         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12008                                 "can't determine element size in genArrayInit.\n");
12009         exit(1);
12010     }
12011
12012     iLoop = IC_ARRAYILIST(ic);
12013     lastVal = 0xffff;
12014
12015     while (iLoop)
12016     {
12017         bool firstpass = TRUE;
12018
12019         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12020                  iLoop->count, (int)iLoop->literalValue, elementSize);
12021
12022         ix = iLoop->count;
12023
12024         while (ix)
12025         {
12026             symbol *tlbl = NULL;
12027
12028             count = ix > 256 ? 256 : ix;
12029
12030             if (count > 1)
12031             {
12032                 tlbl = newiTempLabel (NULL);
12033                 if (firstpass || (count & 0xff))
12034                 {
12035                     emitcode("mov", "b, #!constbyte", count & 0xff);
12036                 }
12037
12038                 emitLabel (tlbl);
12039             }
12040
12041             firstpass = FALSE;
12042
12043             for (eIndex = 0; eIndex < elementSize; eIndex++)
12044             {
12045                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12046                 if (val != lastVal)
12047                 {
12048                     emitcode("mov", "a, #!constbyte", val);
12049                     lastVal = val;
12050                 }
12051
12052                 emitcode("movx", "@dptr, a");
12053                 emitcode("inc", "dptr");
12054             }
12055
12056             if (count > 1)
12057             {
12058                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12059             }
12060
12061             ix -= count;
12062         }
12063
12064         iLoop = iLoop->next;
12065     }
12066
12067     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12068 }
12069 #endif
12070
12071 /*-----------------------------------------------------------------*/
12072 /* genFarFarAssign - assignment when both are in far space         */
12073 /*-----------------------------------------------------------------*/
12074 static void
12075 genFarFarAssign (operand * result, operand * right, iCode * ic)
12076 {
12077   int size = AOP_SIZE (right);
12078   int offset = 0;
12079   symbol *rSym = NULL;
12080
12081   if (size == 1)
12082   {
12083       /* quick & easy case. */
12084       D (emitcode(";","genFarFarAssign (1 byte case)"));
12085       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12086       freeAsmop (right, NULL, ic, FALSE);
12087       /* now assign DPTR to result */
12088       _G.accInUse++;
12089       aopOp(result, ic, FALSE, FALSE);
12090       _G.accInUse--;
12091       aopPut (result, "a", 0);
12092       freeAsmop(result, NULL, ic, FALSE);
12093       return;
12094   }
12095
12096   /* See if we've got an underlying symbol to abuse. */
12097   if (IS_SYMOP(result) && OP_SYMBOL(result))
12098   {
12099       if (IS_TRUE_SYMOP(result))
12100       {
12101           rSym = OP_SYMBOL(result);
12102       }
12103       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12104       {
12105           rSym = OP_SYMBOL(result)->usl.spillLoc;
12106       }
12107   }
12108
12109   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12110   {
12111       /* We can use the '390 auto-toggle feature to good effect here. */
12112
12113       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12114       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12115       emitcode ("mov", "dptr,#%s", rSym->rname);
12116       /* DP2 = result, DP1 = right, DP1 is current. */
12117       while (size)
12118       {
12119           emitcode("movx", "a,@dptr");
12120           emitcode("movx", "@dptr,a");
12121           if (--size)
12122           {
12123                emitcode("inc", "dptr");
12124                emitcode("inc", "dptr");
12125           }
12126       }
12127       emitcode("mov", "dps,#0");
12128       freeAsmop (right, NULL, ic, FALSE);
12129 #if 0
12130 some alternative code for processors without auto-toggle
12131 no time to test now, so later well put in...kpb
12132         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12133         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12134         emitcode ("mov", "dptr,#%s", rSym->rname);
12135         /* DP2 = result, DP1 = right, DP1 is current. */
12136         while (size)
12137         {
12138           --size;
12139           emitcode("movx", "a,@dptr");
12140           if (size)
12141             emitcode("inc", "dptr");
12142           emitcode("inc", "dps");
12143           emitcode("movx", "@dptr,a");
12144           if (size)
12145             emitcode("inc", "dptr");
12146           emitcode("inc", "dps");
12147         }
12148         emitcode("mov", "dps,#0");
12149         freeAsmop (right, NULL, ic, FALSE);
12150 #endif
12151   }
12152   else
12153   {
12154       D (emitcode (";", "genFarFarAssign"));
12155       aopOp (result, ic, TRUE, TRUE);
12156
12157       _startLazyDPSEvaluation ();
12158
12159       while (size--)
12160         {
12161           aopPut (result,
12162                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12163           offset++;
12164         }
12165       _endLazyDPSEvaluation ();
12166       freeAsmop (result, NULL, ic, FALSE);
12167       freeAsmop (right, NULL, ic, FALSE);
12168   }
12169 }
12170
12171 /*-----------------------------------------------------------------*/
12172 /* genAssign - generate code for assignment                        */
12173 /*-----------------------------------------------------------------*/
12174 static void
12175 genAssign (iCode * ic)
12176 {
12177   operand *result, *right;
12178   int size, offset;
12179   unsigned long lit = 0L;
12180
12181   D (emitcode (";", "genAssign"));
12182
12183   result = IC_RESULT (ic);
12184   right = IC_RIGHT (ic);
12185
12186   /* if they are the same */
12187   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12188     return;
12189
12190   aopOp (right, ic, FALSE, FALSE);
12191
12192   emitcode (";", "genAssign: resultIsFar = %s",
12193             isOperandInFarSpace (result) ?
12194             "TRUE" : "FALSE");
12195
12196   /* special case both in far space */
12197   if ((AOP_TYPE (right) == AOP_DPTR ||
12198        AOP_TYPE (right) == AOP_DPTR2) &&
12199   /* IS_TRUE_SYMOP(result)       && */
12200       isOperandInFarSpace (result))
12201     {
12202       genFarFarAssign (result, right, ic);
12203       return;
12204     }
12205
12206   aopOp (result, ic, TRUE, FALSE);
12207
12208   /* if they are the same registers */
12209   if (sameRegs (AOP (right), AOP (result)))
12210     goto release;
12211
12212   /* if the result is a bit */
12213   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12214     {
12215       /* if the right size is a literal then
12216          we know what the value is */
12217       if (AOP_TYPE (right) == AOP_LIT)
12218         {
12219           if (((int) operandLitValue (right)))
12220             aopPut (result, one, 0);
12221           else
12222             aopPut (result, zero, 0);
12223           goto release;
12224         }
12225
12226       /* the right is also a bit variable */
12227       if (AOP_TYPE (right) == AOP_CRY)
12228         {
12229           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12230           aopPut (result, "c", 0);
12231           goto release;
12232         }
12233
12234       /* we need to or */
12235       toBoolean (right);
12236       aopPut (result, "a", 0);
12237       goto release;
12238     }
12239
12240   /* bit variables done */
12241   /* general case */
12242   size = AOP_SIZE (result);
12243   offset = 0;
12244   if (AOP_TYPE (right) == AOP_LIT)
12245     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12246
12247   if ((size > 1) &&
12248       (AOP_TYPE (result) != AOP_REG) &&
12249       (AOP_TYPE (right) == AOP_LIT) &&
12250       !IS_FLOAT (operandType (right)))
12251     {
12252       _startLazyDPSEvaluation ();
12253       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12254         {
12255           aopPut (result,
12256                   aopGet (right, offset, FALSE, FALSE, NULL),
12257                   offset);
12258           offset++;
12259           size--;
12260         }
12261       /* And now fill the rest with zeros. */
12262       if (size)
12263         {
12264           emitcode ("clr", "a");
12265         }
12266       while (size--)
12267         {
12268           aopPut (result, "a", offset++);
12269         }
12270       _endLazyDPSEvaluation ();
12271     }
12272   else
12273     {
12274       _startLazyDPSEvaluation ();
12275       while (size--)
12276         {
12277           aopPut (result,
12278                   aopGet (right, offset, FALSE, FALSE, NULL),
12279                   offset);
12280           offset++;
12281         }
12282       _endLazyDPSEvaluation ();
12283     }
12284
12285 release:
12286   freeAsmop (result, NULL, ic, TRUE);
12287   freeAsmop (right, NULL, ic, TRUE);
12288 }
12289
12290 /*-----------------------------------------------------------------*/
12291 /* genJumpTab - generates code for jump table                      */
12292 /*-----------------------------------------------------------------*/
12293 static void
12294 genJumpTab (iCode * ic)
12295 {
12296   symbol *jtab;
12297   char *l;
12298
12299   D (emitcode (";", "genJumpTab"));
12300
12301   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12302   /* get the condition into accumulator */
12303   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12304   MOVA (l);
12305   /* multiply by four! */
12306   emitcode ("add", "a,acc");
12307   emitcode ("add", "a,acc");
12308   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12309
12310   jtab = newiTempLabel (NULL);
12311   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12312   emitcode ("jmp", "@a+dptr");
12313   emitLabel (jtab);
12314   /* now generate the jump labels */
12315   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12316        jtab = setNextItem (IC_JTLABELS (ic)))
12317     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12318
12319 }
12320
12321 /*-----------------------------------------------------------------*/
12322 /* genCast - gen code for casting                                  */
12323 /*-----------------------------------------------------------------*/
12324 static void
12325 genCast (iCode * ic)
12326 {
12327   operand *result = IC_RESULT (ic);
12328   sym_link *ctype = operandType (IC_LEFT (ic));
12329   sym_link *rtype = operandType (IC_RIGHT (ic));
12330   operand *right = IC_RIGHT (ic);
12331   int size, offset;
12332
12333   D (emitcode (";", "genCast"));
12334
12335   /* if they are equivalent then do nothing */
12336   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12337     return;
12338
12339   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12340   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12341
12342   /* if the result is a bit (and not a bitfield) */
12343   if (IS_BIT (OP_SYMBOL (result)->type))
12344     {
12345       /* if the right size is a literal then
12346          we know what the value is */
12347       if (AOP_TYPE (right) == AOP_LIT)
12348         {
12349           if (((int) operandLitValue (right)))
12350             aopPut (result, one, 0);
12351           else
12352             aopPut (result, zero, 0);
12353
12354           goto release;
12355         }
12356
12357       /* the right is also a bit variable */
12358       if (AOP_TYPE (right) == AOP_CRY)
12359         {
12360           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12361           aopPut (result, "c", 0);
12362           goto release;
12363         }
12364
12365       /* we need to or */
12366       toBoolean (right);
12367       aopPut (result, "a", 0);
12368       goto release;
12369     }
12370
12371   /* if they are the same size : or less */
12372   if (AOP_SIZE (result) <= AOP_SIZE (right))
12373     {
12374
12375       /* if they are in the same place */
12376       if (sameRegs (AOP (right), AOP (result)))
12377         goto release;
12378
12379       /* if they in different places then copy */
12380       size = AOP_SIZE (result);
12381       offset = 0;
12382       _startLazyDPSEvaluation ();
12383       while (size--)
12384         {
12385           aopPut (result,
12386                   aopGet (right, offset, FALSE, FALSE, NULL),
12387                   offset);
12388           offset++;
12389         }
12390       _endLazyDPSEvaluation ();
12391       goto release;
12392     }
12393
12394   /* if the result is of type pointer */
12395   if (IS_PTR (ctype))
12396     {
12397
12398       int p_type;
12399       sym_link *type = operandType (right);
12400
12401       /* pointer to generic pointer */
12402       if (IS_GENPTR (ctype))
12403         {
12404           if (IS_PTR (type))
12405             {
12406               p_type = DCL_TYPE (type);
12407             }
12408           else
12409             {
12410 #if OLD_CAST_BEHAVIOR
12411               /* KV: we are converting a non-pointer type to
12412                * a generic pointer. This (ifdef'd out) code
12413                * says that the resulting generic pointer
12414                * should have the same class as the storage
12415                * location of the non-pointer variable.
12416                *
12417                * For example, converting an int (which happens
12418                * to be stored in DATA space) to a pointer results
12419                * in a DATA generic pointer; if the original int
12420                * in XDATA space, so will be the resulting pointer.
12421                *
12422                * I don't like that behavior, and thus this change:
12423                * all such conversions will be forced to XDATA and
12424                * throw a warning. If you want some non-XDATA
12425                * type, or you want to suppress the warning, you
12426                * must go through an intermediate cast, like so:
12427                *
12428                * char _generic *gp = (char _xdata *)(intVar);
12429                */
12430               sym_link *etype = getSpec (type);
12431
12432               /* we have to go by the storage class */
12433               if (SPEC_OCLS (etype) != generic)
12434                 {
12435                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12436                 }
12437               else
12438 #endif
12439                 {
12440                   /* Converting unknown class (i.e. register variable)
12441                    * to generic pointer. This is not good, but
12442                    * we'll make a guess (and throw a warning).
12443                    */
12444                   p_type = FPOINTER;
12445                   werror (W_INT_TO_GEN_PTR_CAST);
12446                 }
12447             }
12448
12449           /* the first two bytes are known */
12450           size = GPTRSIZE - 1;
12451           offset = 0;
12452           _startLazyDPSEvaluation ();
12453           while (size--)
12454             {
12455               aopPut (result,
12456                       aopGet (right, offset, FALSE, FALSE, NULL),
12457                       offset);
12458               offset++;
12459             }
12460           _endLazyDPSEvaluation ();
12461
12462           /* the last byte depending on type */
12463             {
12464                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12465                 char gpValStr[10];
12466
12467                 if (gpVal == -1)
12468                 {
12469                     // pointerTypeToGPByte will have bitched.
12470                     exit(1);
12471                 }
12472
12473                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12474                 aopPut (result, gpValStr, GPTRSIZE - 1);
12475             }
12476           goto release;
12477         }
12478
12479       /* just copy the pointers */
12480       size = AOP_SIZE (result);
12481       offset = 0;
12482       _startLazyDPSEvaluation ();
12483       while (size--)
12484         {
12485           aopPut (result,
12486                   aopGet (right, offset, FALSE, FALSE, NULL),
12487                   offset);
12488           offset++;
12489         }
12490       _endLazyDPSEvaluation ();
12491       goto release;
12492     }
12493
12494   /* so we now know that the size of destination is greater
12495      than the size of the source */
12496   /* we move to result for the size of source */
12497   size = AOP_SIZE (right);
12498   offset = 0;
12499   _startLazyDPSEvaluation ();
12500   while (size--)
12501     {
12502       aopPut (result,
12503               aopGet (right, offset, FALSE, FALSE, NULL),
12504               offset);
12505       offset++;
12506     }
12507   _endLazyDPSEvaluation ();
12508
12509   /* now depending on the sign of the source && destination */
12510   size = AOP_SIZE (result) - AOP_SIZE (right);
12511   /* if unsigned or not an integral type */
12512   /* also, if the source is a bit, we don't need to sign extend, because
12513    * it can't possibly have set the sign bit.
12514    */
12515   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12516     {
12517       while (size--)
12518         {
12519           aopPut (result, zero, offset++);
12520         }
12521     }
12522   else
12523     {
12524       /* we need to extend the sign :{ */
12525       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12526                         FALSE, FALSE, NULL));
12527       emitcode ("rlc", "a");
12528       emitcode ("subb", "a,acc");
12529       while (size--)
12530         aopPut (result, "a", offset++);
12531     }
12532
12533   /* we are done hurray !!!! */
12534
12535 release:
12536   freeAsmop (right, NULL, ic, TRUE);
12537   freeAsmop (result, NULL, ic, TRUE);
12538
12539 }
12540
12541 /*-----------------------------------------------------------------*/
12542 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12543 /*-----------------------------------------------------------------*/
12544 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12545 {
12546     operand *from , *to , *count;
12547     symbol *lbl;
12548     bitVect *rsave;
12549     int i;
12550
12551     /* we know it has to be 3 parameters */
12552     assert (nparms == 3);
12553
12554     rsave = newBitVect(16);
12555     /* save DPTR if it needs to be saved */
12556     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12557             if (bitVectBitValue(ic->rMask,i))
12558                     rsave = bitVectSetBit(rsave,i);
12559     }
12560     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12561                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12562     savermask(rsave);
12563
12564     to = parms[0];
12565     from = parms[1];
12566     count = parms[2];
12567
12568     aopOp (from, ic->next, FALSE, FALSE);
12569
12570     /* get from into DPTR1 */
12571     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12572     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12573     if (options.model == MODEL_FLAT24) {
12574         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12575     }
12576
12577     freeAsmop (from, NULL, ic, FALSE);
12578     aopOp (to, ic, FALSE, FALSE);
12579     /* get "to" into DPTR */
12580     /* if the operand is already in dptr
12581        then we do nothing else we move the value to dptr */
12582     if (AOP_TYPE (to) != AOP_STR) {
12583         /* if already in DPTR then we need to push */
12584         if (AOP_TYPE(to) == AOP_DPTR) {
12585             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12586             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12587             if (options.model == MODEL_FLAT24)
12588                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12589             emitcode ("pop", "dph");
12590             emitcode ("pop", "dpl");
12591         } else {
12592             _startLazyDPSEvaluation ();
12593             /* if this is remateriazable */
12594             if (AOP_TYPE (to) == AOP_IMMD) {
12595                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12596             } else {                    /* we need to get it byte by byte */
12597                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12598                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12599                 if (options.model == MODEL_FLAT24) {
12600                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12601                 }
12602             }
12603             _endLazyDPSEvaluation ();
12604         }
12605     }
12606     freeAsmop (to, NULL, ic, FALSE);
12607     _G.dptrInUse = _G.dptr1InUse = 1;
12608     aopOp (count, ic->next->next, FALSE,FALSE);
12609     lbl =newiTempLabel(NULL);
12610
12611     /* now for the actual copy */
12612     if (AOP_TYPE(count) == AOP_LIT &&
12613         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12614         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12615         if (fromc) {
12616             emitcode ("lcall","__bi_memcpyc2x_s");
12617         } else {
12618             emitcode ("lcall","__bi_memcpyx2x_s");
12619         }
12620         freeAsmop (count, NULL, ic, FALSE);
12621     } else {
12622         symbol *lbl1 = newiTempLabel(NULL);
12623
12624         emitcode (";"," Auto increment but no djnz");
12625         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12626         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12627         freeAsmop (count, NULL, ic, FALSE);
12628         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12629         emitcode ("","!tlabeldef",lbl->key+100);
12630         if (fromc) {
12631             emitcode ("clr","a");
12632             emitcode ("movc", "a,@a+dptr");
12633         } else
12634             emitcode ("movx", "a,@dptr");
12635         emitcode ("movx", "@dptr,a");
12636         emitcode ("inc", "dptr");
12637         emitcode ("inc", "dptr");
12638         emitcode ("mov","a,b");
12639         emitcode ("orl","a,_ap");
12640         emitcode ("jz","!tlabel",lbl1->key+100);
12641         emitcode ("mov","a,_ap");
12642         emitcode ("add","a,#!constbyte",0xFF);
12643         emitcode ("mov","_ap,a");
12644         emitcode ("mov","a,b");
12645         emitcode ("addc","a,#!constbyte",0xFF);
12646         emitcode ("mov","b,a");
12647         emitcode ("sjmp","!tlabel",lbl->key+100);
12648         emitcode ("","!tlabeldef",lbl1->key+100);
12649     }
12650     emitcode ("mov", "dps,#0");
12651     _G.dptrInUse = _G.dptr1InUse = 0;
12652     unsavermask(rsave);
12653
12654 }
12655
12656 /*-----------------------------------------------------------------*/
12657 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12658 /*-----------------------------------------------------------------*/
12659 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12660 {
12661     operand *from , *to , *count;
12662     symbol *lbl,*lbl2;
12663     bitVect *rsave;
12664     int i;
12665
12666     /* we know it has to be 3 parameters */
12667     assert (nparms == 3);
12668
12669     rsave = newBitVect(16);
12670     /* save DPTR if it needs to be saved */
12671     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12672             if (bitVectBitValue(ic->rMask,i))
12673                     rsave = bitVectSetBit(rsave,i);
12674     }
12675     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12676                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12677     savermask(rsave);
12678
12679     to = parms[0];
12680     from = parms[1];
12681     count = parms[2];
12682
12683     aopOp (from, ic->next, FALSE, FALSE);
12684
12685     /* get from into DPTR1 */
12686     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12687     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12688     if (options.model == MODEL_FLAT24) {
12689         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12690     }
12691
12692     freeAsmop (from, NULL, ic, FALSE);
12693     aopOp (to, ic, FALSE, FALSE);
12694     /* get "to" into DPTR */
12695     /* if the operand is already in dptr
12696        then we do nothing else we move the value to dptr */
12697     if (AOP_TYPE (to) != AOP_STR) {
12698         /* if already in DPTR then we need to push */
12699         if (AOP_TYPE(to) == AOP_DPTR) {
12700             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12701             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12702             if (options.model == MODEL_FLAT24)
12703                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12704             emitcode ("pop", "dph");
12705             emitcode ("pop", "dpl");
12706         } else {
12707             _startLazyDPSEvaluation ();
12708             /* if this is remateriazable */
12709             if (AOP_TYPE (to) == AOP_IMMD) {
12710                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12711             } else {                    /* we need to get it byte by byte */
12712                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12713                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12714                 if (options.model == MODEL_FLAT24) {
12715                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12716                 }
12717             }
12718             _endLazyDPSEvaluation ();
12719         }
12720     }
12721     freeAsmop (to, NULL, ic, FALSE);
12722     _G.dptrInUse = _G.dptr1InUse = 1;
12723     aopOp (count, ic->next->next, FALSE,FALSE);
12724     lbl =newiTempLabel(NULL);
12725     lbl2 =newiTempLabel(NULL);
12726
12727     /* now for the actual compare */
12728     if (AOP_TYPE(count) == AOP_LIT &&
12729         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12730         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12731         if (fromc)
12732             emitcode("lcall","__bi_memcmpc2x_s");
12733         else
12734             emitcode("lcall","__bi_memcmpx2x_s");
12735         freeAsmop (count, NULL, ic, FALSE);
12736         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12737         aopPut(IC_RESULT(ic),"a",0);
12738         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12739     } else {
12740         symbol *lbl1 = newiTempLabel(NULL);
12741
12742         emitcode("push","ar0");
12743         emitcode (";"," Auto increment but no djnz");
12744         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12745         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12746         freeAsmop (count, NULL, ic, FALSE);
12747         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12748         emitcode ("","!tlabeldef",lbl->key+100);
12749         if (fromc) {
12750             emitcode ("clr","a");
12751             emitcode ("movc", "a,@a+dptr");
12752         } else
12753             emitcode ("movx", "a,@dptr");
12754         emitcode ("mov","r0,a");
12755         emitcode ("movx", "a,@dptr");
12756         emitcode ("clr","c");
12757         emitcode ("subb","a,r0");
12758         emitcode ("jnz","!tlabel",lbl2->key+100);
12759         emitcode ("inc", "dptr");
12760         emitcode ("inc", "dptr");
12761         emitcode ("mov","a,b");
12762         emitcode ("orl","a,_ap");
12763         emitcode ("jz","!tlabel",lbl1->key+100);
12764         emitcode ("mov","a,_ap");
12765         emitcode ("add","a,#!constbyte",0xFF);
12766         emitcode ("mov","_ap,a");
12767         emitcode ("mov","a,b");
12768         emitcode ("addc","a,#!constbyte",0xFF);
12769         emitcode ("mov","b,a");
12770         emitcode ("sjmp","!tlabel",lbl->key+100);
12771         emitcode ("","!tlabeldef",lbl1->key+100);
12772         emitcode ("clr","a");
12773         emitcode ("","!tlabeldef",lbl2->key+100);
12774         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12775         aopPut(IC_RESULT(ic),"a",0);
12776         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12777         emitcode("pop","ar0");
12778         emitcode ("mov", "dps,#0");
12779     }
12780     _G.dptrInUse = _G.dptr1InUse = 0;
12781     unsavermask(rsave);
12782
12783 }
12784
12785 /*-----------------------------------------------------------------*/
12786 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12787 /* port, first parameter output area second parameter pointer to   */
12788 /* port third parameter count                                      */
12789 /*-----------------------------------------------------------------*/
12790 static void genInp( iCode *ic, int nparms, operand **parms)
12791 {
12792     operand *from , *to , *count;
12793     symbol *lbl;
12794     bitVect *rsave;
12795     int i;
12796
12797     /* we know it has to be 3 parameters */
12798     assert (nparms == 3);
12799
12800     rsave = newBitVect(16);
12801     /* save DPTR if it needs to be saved */
12802     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12803             if (bitVectBitValue(ic->rMask,i))
12804                     rsave = bitVectSetBit(rsave,i);
12805     }
12806     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12807                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12808     savermask(rsave);
12809
12810     to = parms[0];
12811     from = parms[1];
12812     count = parms[2];
12813
12814     aopOp (from, ic->next, FALSE, FALSE);
12815
12816     /* get from into DPTR1 */
12817     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12818     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12819     if (options.model == MODEL_FLAT24) {
12820         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12821     }
12822
12823     freeAsmop (from, NULL, ic, FALSE);
12824     aopOp (to, ic, FALSE, FALSE);
12825     /* get "to" into DPTR */
12826     /* if the operand is already in dptr
12827        then we do nothing else we move the value to dptr */
12828     if (AOP_TYPE (to) != AOP_STR) {
12829         /* if already in DPTR then we need to push */
12830         if (AOP_TYPE(to) == AOP_DPTR) {
12831             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12832             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12833             if (options.model == MODEL_FLAT24)
12834                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12835             emitcode ("pop", "dph");
12836             emitcode ("pop", "dpl");
12837         } else {
12838             _startLazyDPSEvaluation ();
12839             /* if this is remateriazable */
12840             if (AOP_TYPE (to) == AOP_IMMD) {
12841                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12842             } else {                    /* we need to get it byte by byte */
12843                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12844                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12845                 if (options.model == MODEL_FLAT24) {
12846                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12847                 }
12848             }
12849             _endLazyDPSEvaluation ();
12850         }
12851     }
12852     freeAsmop (to, NULL, ic, FALSE);
12853
12854     _G.dptrInUse = _G.dptr1InUse = 1;
12855     aopOp (count, ic->next->next, FALSE,FALSE);
12856     lbl =newiTempLabel(NULL);
12857
12858     /* now for the actual copy */
12859     if (AOP_TYPE(count) == AOP_LIT &&
12860         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12861         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12862         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12863         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12864         freeAsmop (count, NULL, ic, FALSE);
12865         emitcode ("","!tlabeldef",lbl->key+100);
12866         emitcode ("movx", "a,@dptr");   /* read data from port */
12867         emitcode ("dec","dps");         /* switch to DPTR */
12868         emitcode ("movx", "@dptr,a");   /* save into location */
12869         emitcode ("inc", "dptr");       /* point to next area */
12870         emitcode ("inc","dps");         /* switch to DPTR2 */
12871         emitcode ("djnz","b,!tlabel",lbl->key+100);
12872     } else {
12873         symbol *lbl1 = newiTempLabel(NULL);
12874
12875         emitcode (";"," Auto increment but no djnz");
12876         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12877         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12878         freeAsmop (count, NULL, ic, FALSE);
12879         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12880         emitcode ("","!tlabeldef",lbl->key+100);
12881         emitcode ("movx", "a,@dptr");
12882         emitcode ("dec","dps");         /* switch to DPTR */
12883         emitcode ("movx", "@dptr,a");
12884         emitcode ("inc", "dptr");
12885         emitcode ("inc","dps");         /* switch to DPTR2 */
12886 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12887 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12888         emitcode ("mov","a,b");
12889         emitcode ("orl","a,_ap");
12890         emitcode ("jz","!tlabel",lbl1->key+100);
12891         emitcode ("mov","a,_ap");
12892         emitcode ("add","a,#!constbyte",0xFF);
12893         emitcode ("mov","_ap,a");
12894         emitcode ("mov","a,b");
12895         emitcode ("addc","a,#!constbyte",0xFF);
12896         emitcode ("mov","b,a");
12897         emitcode ("sjmp","!tlabel",lbl->key+100);
12898         emitcode ("","!tlabeldef",lbl1->key+100);
12899     }
12900     emitcode ("mov", "dps,#0");
12901     _G.dptrInUse = _G.dptr1InUse = 0;
12902     unsavermask(rsave);
12903
12904 }
12905
12906 /*-----------------------------------------------------------------*/
12907 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12908 /* port, first parameter output area second parameter pointer to   */
12909 /* port third parameter count                                      */
12910 /*-----------------------------------------------------------------*/
12911 static void genOutp( iCode *ic, int nparms, operand **parms)
12912 {
12913     operand *from , *to , *count;
12914     symbol *lbl;
12915     bitVect *rsave;
12916     int i;
12917
12918     /* we know it has to be 3 parameters */
12919     assert (nparms == 3);
12920
12921     rsave = newBitVect(16);
12922     /* save DPTR if it needs to be saved */
12923     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12924             if (bitVectBitValue(ic->rMask,i))
12925                     rsave = bitVectSetBit(rsave,i);
12926     }
12927     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12928                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12929     savermask(rsave);
12930
12931     to = parms[0];
12932     from = parms[1];
12933     count = parms[2];
12934
12935     aopOp (from, ic->next, FALSE, FALSE);
12936
12937     /* get from into DPTR1 */
12938     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12939     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12940     if (options.model == MODEL_FLAT24) {
12941         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12942     }
12943
12944     freeAsmop (from, NULL, ic, FALSE);
12945     aopOp (to, ic, FALSE, FALSE);
12946     /* get "to" into DPTR */
12947     /* if the operand is already in dptr
12948        then we do nothing else we move the value to dptr */
12949     if (AOP_TYPE (to) != AOP_STR) {
12950         /* if already in DPTR then we need to push */
12951         if (AOP_TYPE(to) == AOP_DPTR) {
12952             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12953             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12954             if (options.model == MODEL_FLAT24)
12955                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12956             emitcode ("pop", "dph");
12957             emitcode ("pop", "dpl");
12958         } else {
12959             _startLazyDPSEvaluation ();
12960             /* if this is remateriazable */
12961             if (AOP_TYPE (to) == AOP_IMMD) {
12962                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12963             } else {                    /* we need to get it byte by byte */
12964                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12965                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12966                 if (options.model == MODEL_FLAT24) {
12967                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12968                 }
12969             }
12970             _endLazyDPSEvaluation ();
12971         }
12972     }
12973     freeAsmop (to, NULL, ic, FALSE);
12974
12975     _G.dptrInUse = _G.dptr1InUse = 1;
12976     aopOp (count, ic->next->next, FALSE,FALSE);
12977     lbl =newiTempLabel(NULL);
12978
12979     /* now for the actual copy */
12980     if (AOP_TYPE(count) == AOP_LIT &&
12981         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12982         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12983         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12984         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12985         emitcode ("","!tlabeldef",lbl->key+100);
12986         emitcode ("movx", "a,@dptr");   /* read data from port */
12987         emitcode ("inc","dps");         /* switch to DPTR2 */
12988         emitcode ("movx", "@dptr,a");   /* save into location */
12989         emitcode ("inc", "dptr");       /* point to next area */
12990         emitcode ("dec","dps");         /* switch to DPTR */
12991         emitcode ("djnz","b,!tlabel",lbl->key+100);
12992         freeAsmop (count, NULL, ic, FALSE);
12993     } else {
12994         symbol *lbl1 = newiTempLabel(NULL);
12995
12996         emitcode (";"," Auto increment but no djnz");
12997         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12998         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12999         freeAsmop (count, NULL, ic, FALSE);
13000         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13001         emitcode ("","!tlabeldef",lbl->key+100);
13002         emitcode ("movx", "a,@dptr");
13003         emitcode ("inc", "dptr");
13004         emitcode ("inc","dps");         /* switch to DPTR2 */
13005         emitcode ("movx", "@dptr,a");
13006         emitcode ("dec","dps");         /* switch to DPTR */
13007         emitcode ("mov","a,b");
13008         emitcode ("orl","a,_ap");
13009         emitcode ("jz","!tlabel",lbl1->key+100);
13010         emitcode ("mov","a,_ap");
13011         emitcode ("add","a,#!constbyte",0xFF);
13012         emitcode ("mov","_ap,a");
13013         emitcode ("mov","a,b");
13014         emitcode ("addc","a,#!constbyte",0xFF);
13015         emitcode ("mov","b,a");
13016         emitcode ("sjmp","!tlabel",lbl->key+100);
13017         emitcode ("","!tlabeldef",lbl1->key+100);
13018     }
13019     emitcode ("mov", "dps,#0");
13020     _G.dptrInUse = _G.dptr1InUse = 0;
13021     unsavermask(rsave);
13022
13023 }
13024
13025 /*-----------------------------------------------------------------*/
13026 /* genSwapW - swap lower & high order bytes                        */
13027 /*-----------------------------------------------------------------*/
13028 static void genSwapW(iCode *ic, int nparms, operand **parms)
13029 {
13030     operand *dest;
13031     operand *src;
13032     assert (nparms==1);
13033
13034     src = parms[0];
13035     dest=IC_RESULT(ic);
13036
13037     assert(getSize(operandType(src))==2);
13038
13039     aopOp (src, ic, FALSE, FALSE);
13040     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13041     _G.accInUse++;
13042     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13043     _G.accInUse--;
13044     freeAsmop (src, NULL, ic, FALSE);
13045
13046     aopOp (dest,ic, FALSE, FALSE);
13047     aopPut(dest,"b",0);
13048     aopPut(dest,"a",1);
13049     freeAsmop (dest, NULL, ic, FALSE);
13050 }
13051
13052 /*-----------------------------------------------------------------*/
13053 /* genMemsetX - gencode for memSetX data                           */
13054 /*-----------------------------------------------------------------*/
13055 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13056 {
13057     operand *to , *val , *count;
13058     symbol *lbl;
13059     char *l;
13060     int i;
13061     bitVect *rsave;
13062
13063     /* we know it has to be 3 parameters */
13064     assert (nparms == 3);
13065
13066     to = parms[0];
13067     val = parms[1];
13068     count = parms[2];
13069
13070     /* save DPTR if it needs to be saved */
13071     rsave = newBitVect(16);
13072     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13073             if (bitVectBitValue(ic->rMask,i))
13074                     rsave = bitVectSetBit(rsave,i);
13075     }
13076     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13077                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13078     savermask(rsave);
13079
13080     aopOp (to, ic, FALSE, FALSE);
13081     /* get "to" into DPTR */
13082     /* if the operand is already in dptr
13083        then we do nothing else we move the value to dptr */
13084     if (AOP_TYPE (to) != AOP_STR) {
13085         /* if already in DPTR then we need to push */
13086         if (AOP_TYPE(to) == AOP_DPTR) {
13087             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13088             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13089             if (options.model == MODEL_FLAT24)
13090                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13091             emitcode ("pop", "dph");
13092             emitcode ("pop", "dpl");
13093         } else {
13094             _startLazyDPSEvaluation ();
13095             /* if this is remateriazable */
13096             if (AOP_TYPE (to) == AOP_IMMD) {
13097                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13098             } else {                    /* we need to get it byte by byte */
13099                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13100                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13101                 if (options.model == MODEL_FLAT24) {
13102                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13103                 }
13104             }
13105             _endLazyDPSEvaluation ();
13106         }
13107     }
13108     freeAsmop (to, NULL, ic, FALSE);
13109
13110     aopOp (val, ic->next->next, FALSE,FALSE);
13111     aopOp (count, ic->next->next, FALSE,FALSE);
13112     lbl =newiTempLabel(NULL);
13113     /* now for the actual copy */
13114     if (AOP_TYPE(count) == AOP_LIT &&
13115         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13116         l = aopGet(val, 0, FALSE, FALSE, NULL);
13117         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13118         MOVA(l);
13119         emitcode ("","!tlabeldef",lbl->key+100);
13120         emitcode ("movx", "@dptr,a");
13121         emitcode ("inc", "dptr");
13122         emitcode ("djnz","b,!tlabel",lbl->key+100);
13123     } else {
13124         symbol *lbl1 = newiTempLabel(NULL);
13125
13126         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13127         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13128         emitcode ("","!tlabeldef",lbl->key+100);
13129         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13130         emitcode ("movx", "@dptr,a");
13131         emitcode ("inc", "dptr");
13132         emitcode ("mov","a,b");
13133         emitcode ("orl","a,_ap");
13134         emitcode ("jz","!tlabel",lbl1->key+100);
13135         emitcode ("mov","a,_ap");
13136         emitcode ("add","a,#!constbyte",0xFF);
13137         emitcode ("mov","_ap,a");
13138         emitcode ("mov","a,b");
13139         emitcode ("addc","a,#!constbyte",0xFF);
13140         emitcode ("mov","b,a");
13141         emitcode ("sjmp","!tlabel",lbl->key+100);
13142         emitcode ("","!tlabeldef",lbl1->key+100);
13143     }
13144     freeAsmop (count, NULL, ic, FALSE);
13145     unsavermask(rsave);
13146 }
13147
13148 /*-----------------------------------------------------------------*/
13149 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13150 /*-----------------------------------------------------------------*/
13151 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13152 {
13153         bitVect *rsave ;
13154         operand *pnum, *result;
13155         int i;
13156
13157         assert (nparms==1);
13158         /* save registers that need to be saved */
13159         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13160                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13161
13162         pnum = parms[0];
13163         aopOp (pnum, ic, FALSE, FALSE);
13164         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13165         freeAsmop (pnum, NULL, ic, FALSE);
13166         emitcode ("lcall","NatLib_LoadPrimitive");
13167         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13168         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13169             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13170                 for (i = (size-1) ; i >= 0 ; i-- ) {
13171                         emitcode ("push","a%s",javaRet[i]);
13172                 }
13173                 for (i=0; i < size ; i++ ) {
13174                         emitcode ("pop","a%s",
13175                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13176                 }
13177         } else {
13178                 for (i = 0 ; i < size ; i++ ) {
13179                         aopPut(result,javaRet[i],i);
13180                 }
13181         }
13182         freeAsmop (result, NULL, ic, FALSE);
13183         unsavermask(rsave);
13184 }
13185
13186 /*-----------------------------------------------------------------*/
13187 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13188 /*-----------------------------------------------------------------*/
13189 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13190 {
13191         bitVect *rsave ;
13192         operand *pnum, *result;
13193         int size = 3;
13194         int i;
13195
13196         assert (nparms==1);
13197         /* save registers that need to be saved */
13198         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13199                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13200
13201         pnum = parms[0];
13202         aopOp (pnum, ic, FALSE, FALSE);
13203         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13204         freeAsmop (pnum, NULL, ic, FALSE);
13205         emitcode ("lcall","NatLib_LoadPointer");
13206         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13207         if (AOP_TYPE(result)!=AOP_STR) {
13208                 for (i = 0 ; i < size ; i++ ) {
13209                         aopPut(result,fReturn[i],i);
13210                 }
13211         }
13212         freeAsmop (result, NULL, ic, FALSE);
13213         unsavermask(rsave);
13214 }
13215
13216 /*-----------------------------------------------------------------*/
13217 /* genNatLibInstallStateBlock -                                    */
13218 /*-----------------------------------------------------------------*/
13219 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13220                                        operand **parms, const char *name)
13221 {
13222         bitVect *rsave ;
13223         operand *psb, *handle;
13224         assert (nparms==2);
13225
13226         /* save registers that need to be saved */
13227         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13228                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13229         psb = parms[0];
13230         handle = parms[1];
13231
13232         /* put pointer to state block into DPTR1 */
13233         aopOp (psb, ic, FALSE, FALSE);
13234         if (AOP_TYPE (psb) == AOP_IMMD) {
13235                 emitcode ("mov","dps,#1");
13236                 emitcode ("mov", "dptr,%s",
13237                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13238                 emitcode ("mov","dps,#0");
13239         } else {
13240                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13241                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13242                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13243         }
13244         freeAsmop (psb, NULL, ic, FALSE);
13245
13246         /* put libraryID into DPTR */
13247         emitcode ("mov","dptr,#LibraryID");
13248
13249         /* put handle into r3:r2 */
13250         aopOp (handle, ic, FALSE, FALSE);
13251         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13252                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13253                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13254                 emitcode ("pop","ar3");
13255                 emitcode ("pop","ar2");
13256         } else {
13257                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13258                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13259         }
13260         freeAsmop (psb, NULL, ic, FALSE);
13261
13262         /* make the call */
13263         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13264
13265         /* put return value into place*/
13266         _G.accInUse++;
13267         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13268         _G.accInUse--;
13269         aopPut(IC_RESULT(ic),"a",0);
13270         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13271         unsavermask(rsave);
13272 }
13273
13274 /*-----------------------------------------------------------------*/
13275 /* genNatLibRemoveStateBlock -                                     */
13276 /*-----------------------------------------------------------------*/
13277 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13278 {
13279         bitVect *rsave ;
13280
13281         assert(nparms==0);
13282
13283         /* save registers that need to be saved */
13284         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13285                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13286
13287         /* put libraryID into DPTR */
13288         emitcode ("mov","dptr,#LibraryID");
13289         /* make the call */
13290         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13291         unsavermask(rsave);
13292 }
13293
13294 /*-----------------------------------------------------------------*/
13295 /* genNatLibGetStateBlock -                                        */
13296 /*-----------------------------------------------------------------*/
13297 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13298                                    operand **parms,const char *name)
13299 {
13300         bitVect *rsave ;
13301         symbol *lbl = newiTempLabel(NULL);
13302
13303         assert(nparms==0);
13304         /* save registers that need to be saved */
13305         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13306                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13307
13308         /* put libraryID into DPTR */
13309         emitcode ("mov","dptr,#LibraryID");
13310         /* make the call */
13311         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13312         emitcode ("jnz","!tlabel",lbl->key+100);
13313
13314         /* put return value into place */
13315         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13316         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13317                 emitcode ("push","ar3");
13318                 emitcode ("push","ar2");
13319                 emitcode ("pop","%s",
13320                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13321                 emitcode ("pop","%s",
13322                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13323         } else {
13324                 aopPut(IC_RESULT(ic),"r2",0);
13325                 aopPut(IC_RESULT(ic),"r3",1);
13326         }
13327         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13328         emitcode ("","!tlabeldef",lbl->key+100);
13329         unsavermask(rsave);
13330 }
13331
13332 /*-----------------------------------------------------------------*/
13333 /* genMMMalloc -                                                   */
13334 /*-----------------------------------------------------------------*/
13335 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13336                          int size, const char *name)
13337 {
13338         bitVect *rsave ;
13339         operand *bsize;
13340         symbol *rsym;
13341         symbol *lbl = newiTempLabel(NULL);
13342
13343         assert (nparms == 1);
13344         /* save registers that need to be saved */
13345         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13346                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13347
13348         bsize=parms[0];
13349         aopOp (bsize,ic,FALSE,FALSE);
13350
13351         /* put the size in R4-R2 */
13352         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13353                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13354                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13355                 if (size==3) {
13356                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13357                         emitcode("pop","ar4");
13358                 }
13359                 emitcode("pop","ar3");
13360                 emitcode("pop","ar2");
13361         } else {
13362                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13363                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13364                 if (size==3) {
13365                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13366                 }
13367         }
13368         freeAsmop (bsize, NULL, ic, FALSE);
13369
13370         /* make the call */
13371         emitcode ("lcall","MM_%s",name);
13372         emitcode ("jz","!tlabel",lbl->key+100);
13373         emitcode ("mov","r2,#!constbyte",0xff);
13374         emitcode ("mov","r3,#!constbyte",0xff);
13375         emitcode ("","!tlabeldef",lbl->key+100);
13376         /* we don't care about the pointer : we just save the handle */
13377         rsym = OP_SYMBOL(IC_RESULT(ic));
13378         if (rsym->liveFrom != rsym->liveTo) {
13379                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13380                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13381                         emitcode ("push","ar3");
13382                         emitcode ("push","ar2");
13383                         emitcode ("pop","%s",
13384                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13385                         emitcode ("pop","%s",
13386                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13387                 } else {
13388                         aopPut(IC_RESULT(ic),"r2",0);
13389                         aopPut(IC_RESULT(ic),"r3",1);
13390                 }
13391                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13392         }
13393         unsavermask(rsave);
13394 }
13395
13396 /*-----------------------------------------------------------------*/
13397 /* genMMDeref -                                                    */
13398 /*-----------------------------------------------------------------*/
13399 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13400 {
13401         bitVect *rsave ;
13402         operand *handle;
13403
13404         assert (nparms == 1);
13405         /* save registers that need to be saved */
13406         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13407                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13408
13409         handle=parms[0];
13410         aopOp (handle,ic,FALSE,FALSE);
13411
13412         /* put the size in R4-R2 */
13413         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13414                 emitcode("push","%s",
13415                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13416                 emitcode("push","%s",
13417                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13418                 emitcode("pop","ar3");
13419                 emitcode("pop","ar2");
13420         } else {
13421                 emitcode ("mov","r2,%s",
13422                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13423                 emitcode ("mov","r3,%s",
13424                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13425         }
13426         freeAsmop (handle, NULL, ic, FALSE);
13427
13428         /* make the call */
13429         emitcode ("lcall","MM_Deref");
13430
13431         {
13432                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13433                 if (rsym->liveFrom != rsym->liveTo) {
13434                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13435                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13436                             _startLazyDPSEvaluation ();
13437
13438                             aopPut(IC_RESULT(ic),"dpl",0);
13439                             aopPut(IC_RESULT(ic),"dph",1);
13440                             aopPut(IC_RESULT(ic),"dpx",2);
13441
13442                             _endLazyDPSEvaluation ();
13443
13444                         }
13445                 }
13446         }
13447         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13448         unsavermask(rsave);
13449 }
13450
13451 /*-----------------------------------------------------------------*/
13452 /* genMMUnrestrictedPersist -                                      */
13453 /*-----------------------------------------------------------------*/
13454 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13455 {
13456         bitVect *rsave ;
13457         operand *handle;
13458
13459         assert (nparms == 1);
13460         /* save registers that need to be saved */
13461         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13462                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13463
13464         handle=parms[0];
13465         aopOp (handle,ic,FALSE,FALSE);
13466
13467         /* put the size in R3-R2 */
13468         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13469                 emitcode("push","%s",
13470                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13471                 emitcode("push","%s",
13472                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13473                 emitcode("pop","ar3");
13474                 emitcode("pop","ar2");
13475         } else {
13476                 emitcode ("mov","r2,%s",
13477                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13478                 emitcode ("mov","r3,%s",
13479                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13480         }
13481         freeAsmop (handle, NULL, ic, FALSE);
13482
13483         /* make the call */
13484         emitcode ("lcall","MM_UnrestrictedPersist");
13485
13486         {
13487                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13488                 if (rsym->liveFrom != rsym->liveTo) {
13489                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13490                         aopPut(IC_RESULT(ic),"a",0);
13491                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13492                 }
13493         }
13494         unsavermask(rsave);
13495 }
13496
13497 /*-----------------------------------------------------------------*/
13498 /* genSystemExecJavaProcess -                                      */
13499 /*-----------------------------------------------------------------*/
13500 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13501 {
13502         bitVect *rsave ;
13503         operand *handle, *pp;
13504
13505         assert (nparms==2);
13506         /* save registers that need to be saved */
13507         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13508                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13509
13510         pp = parms[0];
13511         handle = parms[1];
13512
13513         /* put the handle in R3-R2 */
13514         aopOp (handle,ic,FALSE,FALSE);
13515         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13516                 emitcode("push","%s",
13517                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13518                 emitcode("push","%s",
13519                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13520                 emitcode("pop","ar3");
13521                 emitcode("pop","ar2");
13522         } else {
13523                 emitcode ("mov","r2,%s",
13524                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13525                 emitcode ("mov","r3,%s",
13526                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13527         }
13528         freeAsmop (handle, NULL, ic, FALSE);
13529
13530         /* put pointer in DPTR */
13531         aopOp (pp,ic,FALSE,FALSE);
13532         if (AOP_TYPE(pp) == AOP_IMMD) {
13533                 emitcode ("mov", "dptr,%s",
13534                           aopGet (pp, 0, TRUE, FALSE, NULL));
13535         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13536                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13537                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13538                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13539         }
13540         freeAsmop (handle, NULL, ic, FALSE);
13541
13542         /* make the call */
13543         emitcode ("lcall","System_ExecJavaProcess");
13544
13545         /* put result in place */
13546         {
13547                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13548                 if (rsym->liveFrom != rsym->liveTo) {
13549                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13550                         aopPut(IC_RESULT(ic),"a",0);
13551                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13552                 }
13553         }
13554
13555         unsavermask(rsave);
13556 }
13557
13558 /*-----------------------------------------------------------------*/
13559 /* genSystemRTCRegisters -                                         */
13560 /*-----------------------------------------------------------------*/
13561 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13562                                   char *name)
13563 {
13564         bitVect *rsave ;
13565         operand *pp;
13566
13567         assert (nparms==1);
13568         /* save registers that need to be saved */
13569         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13570                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13571
13572         pp=parms[0];
13573         /* put pointer in DPTR */
13574         aopOp (pp,ic,FALSE,FALSE);
13575         if (AOP_TYPE (pp) == AOP_IMMD) {
13576                 emitcode ("mov","dps,#1");
13577                 emitcode ("mov", "dptr,%s",
13578                           aopGet (pp, 0, TRUE, FALSE, NULL));
13579                 emitcode ("mov","dps,#0");
13580         } else {
13581                 emitcode ("mov","dpl1,%s",
13582                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13583                 emitcode ("mov","dph1,%s",
13584                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13585                 emitcode ("mov","dpx1,%s",
13586                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13587         }
13588         freeAsmop (pp, NULL, ic, FALSE);
13589
13590         /* make the call */
13591         emitcode ("lcall","System_%sRTCRegisters",name);
13592
13593         unsavermask(rsave);
13594 }
13595
13596 /*-----------------------------------------------------------------*/
13597 /* genSystemThreadSleep -                                          */
13598 /*-----------------------------------------------------------------*/
13599 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13600 {
13601         bitVect *rsave ;
13602         operand *to, *s;
13603
13604         assert (nparms==1);
13605         /* save registers that need to be saved */
13606         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13607                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13608
13609         to = parms[0];
13610         aopOp(to,ic,FALSE,FALSE);
13611         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13612             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13613                 emitcode ("push","%s",
13614                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13615                 emitcode ("push","%s",
13616                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13617                 emitcode ("push","%s",
13618                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13619                 emitcode ("push","%s",
13620                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13621                 emitcode ("pop","ar3");
13622                 emitcode ("pop","ar2");
13623                 emitcode ("pop","ar1");
13624                 emitcode ("pop","ar0");
13625         } else {
13626                 emitcode ("mov","r0,%s",
13627                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13628                 emitcode ("mov","r1,%s",
13629                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13630                 emitcode ("mov","r2,%s",
13631                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13632                 emitcode ("mov","r3,%s",
13633                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13634         }
13635         freeAsmop (to, NULL, ic, FALSE);
13636
13637         /* suspend in acc */
13638         s = parms[1];
13639         aopOp(s,ic,FALSE,FALSE);
13640         emitcode ("mov","a,%s",
13641                   aopGet(s,0,FALSE,TRUE,NULL));
13642         freeAsmop (s, NULL, ic, FALSE);
13643
13644         /* make the call */
13645         emitcode ("lcall","System_%s",name);
13646
13647         unsavermask(rsave);
13648 }
13649
13650 /*-----------------------------------------------------------------*/
13651 /* genSystemThreadResume -                                         */
13652 /*-----------------------------------------------------------------*/
13653 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13654 {
13655         bitVect *rsave ;
13656         operand *tid,*pid;
13657
13658         assert (nparms==2);
13659         /* save registers that need to be saved */
13660         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13661                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13662
13663         tid = parms[0];
13664         pid = parms[1];
13665
13666         /* PID in R0 */
13667         aopOp(pid,ic,FALSE,FALSE);
13668         emitcode ("mov","r0,%s",
13669                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13670         freeAsmop (pid, NULL, ic, FALSE);
13671
13672         /* tid into ACC */
13673         aopOp(tid,ic,FALSE,FALSE);
13674         emitcode ("mov","a,%s",
13675                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13676         freeAsmop (tid, NULL, ic, FALSE);
13677
13678         emitcode ("lcall","System_ThreadResume");
13679
13680         /* put result into place */
13681         {
13682                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13683                 if (rsym->liveFrom != rsym->liveTo) {
13684                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13685                         aopPut(IC_RESULT(ic),"a",0);
13686                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13687                 }
13688         }
13689         unsavermask(rsave);
13690 }
13691
13692 /*-----------------------------------------------------------------*/
13693 /* genSystemProcessResume -                                        */
13694 /*-----------------------------------------------------------------*/
13695 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13696 {
13697         bitVect *rsave ;
13698         operand *pid;
13699
13700         assert (nparms==1);
13701         /* save registers that need to be saved */
13702         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13703                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13704
13705         pid = parms[0];
13706
13707         /* pid into ACC */
13708         aopOp(pid,ic,FALSE,FALSE);
13709         emitcode ("mov","a,%s",
13710                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13711         freeAsmop (pid, NULL, ic, FALSE);
13712
13713         emitcode ("lcall","System_ProcessResume");
13714
13715         unsavermask(rsave);
13716 }
13717
13718 /*-----------------------------------------------------------------*/
13719 /* genSystem -                                                     */
13720 /*-----------------------------------------------------------------*/
13721 static void genSystem (iCode *ic,int nparms,char *name)
13722 {
13723         assert(nparms == 0);
13724
13725         emitcode ("lcall","System_%s",name);
13726 }
13727
13728 /*-----------------------------------------------------------------*/
13729 /* genSystemPoll -                                                  */
13730 /*-----------------------------------------------------------------*/
13731 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13732 {
13733         bitVect *rsave ;
13734         operand *fp;
13735
13736         assert (nparms==1);
13737         /* save registers that need to be saved */
13738         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13739                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13740
13741         fp = parms[0];
13742         aopOp (fp,ic,FALSE,FALSE);
13743         if (AOP_TYPE (fp) == AOP_IMMD) {
13744                 emitcode ("mov", "dptr,%s",
13745                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13746         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13747                 emitcode ("mov","dpl,%s",
13748                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13749                 emitcode ("mov","dph,%s",
13750                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13751                 emitcode ("mov","dpx,%s",
13752                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13753         }
13754         freeAsmop (fp, NULL, ic, FALSE);
13755
13756         emitcode ("lcall","System_%sPoll",name);
13757
13758         /* put result into place */
13759         {
13760                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13761                 if (rsym->liveFrom != rsym->liveTo) {
13762                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13763                         aopPut(IC_RESULT(ic),"a",0);
13764                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13765                 }
13766         }
13767         unsavermask(rsave);
13768 }
13769
13770 /*-----------------------------------------------------------------*/
13771 /* genSystemGetCurrentID -                                         */
13772 /*-----------------------------------------------------------------*/
13773 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13774 {
13775         assert (nparms==0);
13776
13777         emitcode ("lcall","System_GetCurrent%sId",name);
13778         /* put result into place */
13779         {
13780                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13781                 if (rsym->liveFrom != rsym->liveTo) {
13782                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13783                         aopPut(IC_RESULT(ic),"a",0);
13784                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13785                 }
13786         }
13787 }
13788
13789 /*-----------------------------------------------------------------*/
13790 /* genDjnz - generate decrement & jump if not zero instrucion      */
13791 /*-----------------------------------------------------------------*/
13792 static int
13793 genDjnz (iCode * ic, iCode * ifx)
13794 {
13795   symbol *lbl, *lbl1;
13796   if (!ifx)
13797     return 0;
13798
13799   /* if the if condition has a false label
13800      then we cannot save */
13801   if (IC_FALSE (ifx))
13802     return 0;
13803
13804   /* if the minus is not of the form a = a - 1 */
13805   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13806       !IS_OP_LITERAL (IC_RIGHT (ic)))
13807     return 0;
13808
13809   if (operandLitValue (IC_RIGHT (ic)) != 1)
13810     return 0;
13811
13812   /* if the size of this greater than one then no
13813      saving */
13814   if (getSize (operandType (IC_RESULT (ic))) > 1)
13815     return 0;
13816
13817   /* otherwise we can save BIG */
13818
13819   D (emitcode (";", "genDjnz"));
13820
13821   lbl = newiTempLabel (NULL);
13822   lbl1 = newiTempLabel (NULL);
13823
13824   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13825
13826   if (AOP_NEEDSACC(IC_RESULT(ic)))
13827   {
13828       /* If the result is accessed indirectly via
13829        * the accumulator, we must explicitly write
13830        * it back after the decrement.
13831        */
13832       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13833
13834       if (strcmp(rByte, "a"))
13835       {
13836            /* Something is hopelessly wrong */
13837            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13838                    __FILE__, __LINE__);
13839            /* We can just give up; the generated code will be inefficient,
13840             * but what the hey.
13841             */
13842            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13843            return 0;
13844       }
13845       emitcode ("dec", "%s", rByte);
13846       aopPut (IC_RESULT (ic), rByte, 0);
13847       emitcode ("jnz", "!tlabel", lbl->key + 100);
13848   }
13849   else if (IS_AOP_PREG (IC_RESULT (ic)))
13850     {
13851       emitcode ("dec", "%s",
13852                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13853       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13854       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13855       ifx->generated = 1;
13856       emitcode ("jnz", "!tlabel", lbl->key + 100);
13857     }
13858   else
13859     {
13860       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13861                 lbl->key + 100);
13862     }
13863   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13864   emitLabel (lbl);
13865   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13866   emitLabel (lbl1);
13867
13868   if (!ifx->generated)
13869       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13870   ifx->generated = 1;
13871   return 1;
13872 }
13873
13874 /*-----------------------------------------------------------------*/
13875 /* genReceive - generate code for a receive iCode                  */
13876 /*-----------------------------------------------------------------*/
13877 static void
13878 genReceive (iCode * ic)
13879 {
13880     int size = getSize (operandType (IC_RESULT (ic)));
13881     int offset = 0;
13882     int rb1off ;
13883
13884     D (emitcode (";", "genReceive"));
13885
13886     if (ic->argreg == 1)
13887     {
13888         /* first parameter */
13889         if (AOP_IS_STR(IC_RESULT(ic)))
13890         {
13891             /* Nothing to do: it's already in the proper place. */
13892             return;
13893         }
13894         else
13895         {
13896             bool useDp2;
13897
13898             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13899                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13900                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13901
13902             _G.accInUse++;
13903             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13904             _G.accInUse--;
13905
13906             /* Sanity checking... */
13907             if (AOP_USESDPTR(IC_RESULT(ic)))
13908             {
13909                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13910                         "genReceive got unexpected DPTR.");
13911             }
13912             assignResultValue (IC_RESULT (ic), NULL);
13913         }
13914     }
13915     else if (ic->argreg > 12)
13916     { /* bit parameters */
13917       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13918         {
13919           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13920           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13921           outBitC(IC_RESULT (ic));
13922         }
13923     }
13924     else
13925     {
13926         /* second receive onwards */
13927         /* this gets a little tricky since unused receives will be
13928          eliminated, we have saved the reg in the type field . and
13929          we use that to figure out which register to use */
13930         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13931         rb1off = ic->argreg;
13932         while (size--)
13933         {
13934             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13935         }
13936     }
13937     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13938 }
13939
13940 /*-----------------------------------------------------------------*/
13941 /* genDummyRead - generate code for dummy read of volatiles        */
13942 /*-----------------------------------------------------------------*/
13943 static void
13944 genDummyRead (iCode * ic)
13945 {
13946   operand *op;
13947   int size, offset;
13948
13949   D (emitcode(";", "genDummyRead"));
13950
13951   op = IC_RIGHT (ic);
13952   if (op && IS_SYMOP (op))
13953     {
13954       aopOp (op, ic, FALSE, FALSE);
13955
13956       /* if the result is a bit */
13957       if (AOP_TYPE (op) == AOP_CRY)
13958         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13959       else
13960         {
13961           /* bit variables done */
13962           /* general case */
13963           size = AOP_SIZE (op);
13964           offset = 0;
13965           while (size--)
13966           {
13967             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13968             offset++;
13969           }
13970         }
13971
13972       freeAsmop (op, NULL, ic, TRUE);
13973     }
13974
13975   op = IC_LEFT (ic);
13976   if (op && IS_SYMOP (op))
13977     {
13978       aopOp (op, ic, FALSE, FALSE);
13979
13980       /* if the result is a bit */
13981       if (AOP_TYPE (op) == AOP_CRY)
13982         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13983       else
13984         {
13985           /* bit variables done */
13986           /* general case */
13987           size = AOP_SIZE (op);
13988           offset = 0;
13989           while (size--)
13990           {
13991             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13992             offset++;
13993           }
13994         }
13995
13996       freeAsmop (op, NULL, ic, TRUE);
13997     }
13998 }
13999
14000 /*-----------------------------------------------------------------*/
14001 /* genCritical - generate code for start of a critical sequence    */
14002 /*-----------------------------------------------------------------*/
14003 static void
14004 genCritical (iCode *ic)
14005 {
14006   symbol *tlbl = newiTempLabel (NULL);
14007
14008   D (emitcode(";", "genCritical"));
14009
14010   if (IC_RESULT (ic))
14011     {
14012       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14013       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14014       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14015       aopPut (IC_RESULT (ic), zero, 0);
14016       emitLabel (tlbl);
14017       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14018     }
14019   else
14020     {
14021       emitcode ("setb", "c");
14022       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14023       emitcode ("clr", "c");
14024       emitLabel (tlbl);
14025       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14026     }
14027 }
14028
14029 /*-----------------------------------------------------------------*/
14030 /* genEndCritical - generate code for end of a critical sequence   */
14031 /*-----------------------------------------------------------------*/
14032 static void
14033 genEndCritical (iCode *ic)
14034 {
14035   D(emitcode(";     genEndCritical",""));
14036
14037   if (IC_RIGHT (ic))
14038     {
14039       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14040       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14041         {
14042           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14043           emitcode ("mov", "ea,c");
14044         }
14045       else
14046         {
14047           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14048           emitcode ("rrc", "a");
14049           emitcode ("mov", "ea,c");
14050         }
14051       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14052     }
14053   else
14054     {
14055       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14056       emitcode ("mov", "ea,c");
14057     }
14058 }
14059
14060
14061
14062 /*-----------------------------------------------------------------*/
14063 /* genBuiltIn - calls the appropriate function to  generating code */
14064 /* for a built in function                                         */
14065 /*-----------------------------------------------------------------*/
14066 static void genBuiltIn (iCode *ic)
14067 {
14068         operand *bi_parms[MAX_BUILTIN_ARGS];
14069         int nbi_parms;
14070         iCode *bi_iCode;
14071         symbol *bif;
14072
14073         /* get all the arguments for a built in function */
14074         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14075
14076         /* which function is it */
14077         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14078         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14079                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14080         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14081                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14082         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14083                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14084         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14085                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14086         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14087                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14088         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14089                 genInp(bi_iCode,nbi_parms,bi_parms);
14090         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14091                 genOutp(bi_iCode,nbi_parms,bi_parms);
14092         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14093                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14094                 /* JavaNative builtIns */
14095         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14096                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14097         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14098                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14099         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14100                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14101         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14102                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14103         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14104                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14105         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14106                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14107         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14108                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14109         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14110                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14111         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14112                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14113         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14114                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14115         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14116                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14117         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14118                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14119         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14120                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14121         } else if (strcmp(bif->name,"MM_Free")==0) {
14122                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14123         } else if (strcmp(bif->name,"MM_Deref")==0) {
14124                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14125         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14126                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14127         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14128                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14129         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14130                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14131         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14132                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14133         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14134                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14135         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14136                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14137         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14138                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14139         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14140                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14141         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14142                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14143         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14144                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14145         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14146                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14147         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14148                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14149         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14150                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14151         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14152                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14153         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14154                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14155         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14156                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14157         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14158                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14159         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14160                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14161         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14162                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14163         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14164                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14165         } else {
14166                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14167                 return ;
14168         }
14169         return ;
14170 }
14171
14172 /*-----------------------------------------------------------------*/
14173 /* gen390Code - generate code for Dallas 390 based controllers     */
14174 /*-----------------------------------------------------------------*/
14175 void
14176 gen390Code (iCode * lic)
14177 {
14178   iCode *ic;
14179   int cln = 0;
14180
14181   _G.currentFunc = NULL;
14182   lineHead = lineCurr = NULL;
14183   dptrn[1][0] = "dpl1";
14184   dptrn[1][1] = "dph1";
14185   dptrn[1][2] = "dpx1";
14186
14187   if (options.model == MODEL_FLAT24) {
14188     fReturnSizeDS390 = 5;
14189     fReturn = fReturn24;
14190   } else {
14191     fReturnSizeDS390 = 4;
14192     fReturn = fReturn16;
14193     options.stack10bit=0;
14194   }
14195 #if 1
14196   /* print the allocation information */
14197   if (allocInfo && currFunc)
14198     printAllocInfo (currFunc, codeOutFile);
14199 #endif
14200   /* if debug information required */
14201   if (options.debug && currFunc)
14202     {
14203       debugFile->writeFunction (currFunc, lic);
14204     }
14205   /* stack pointer name */
14206   if (options.useXstack)
14207     spname = "_spx";
14208   else
14209     spname = "sp";
14210
14211
14212   for (ic = lic; ic; ic = ic->next)
14213     {
14214       _G.current_iCode = ic;
14215
14216       if (ic->lineno && cln != ic->lineno)
14217         {
14218           if (options.debug)
14219             {
14220               debugFile->writeCLine (ic);
14221             }
14222           if (!options.noCcodeInAsm) {
14223             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14224                       printCLine(ic->filename, ic->lineno));
14225           }
14226           cln = ic->lineno;
14227         }
14228       if (options.iCodeInAsm) {
14229         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14230       }
14231       /* if the result is marked as
14232          spilt and rematerializable or code for
14233          this has already been generated then
14234          do nothing */
14235       if (resultRemat (ic) || ic->generated)
14236         continue;
14237
14238       /* depending on the operation */
14239       switch (ic->op)
14240         {
14241         case '!':
14242           genNot (ic);
14243           break;
14244
14245         case '~':
14246           genCpl (ic);
14247           break;
14248
14249         case UNARYMINUS:
14250           genUminus (ic);
14251           break;
14252
14253         case IPUSH:
14254           genIpush (ic);
14255           break;
14256
14257         case IPOP:
14258           /* IPOP happens only when trying to restore a
14259              spilt live range, if there is an ifx statement
14260              following this pop then the if statement might
14261              be using some of the registers being popped which
14262              would destory the contents of the register so
14263              we need to check for this condition and handle it */
14264           if (ic->next &&
14265               ic->next->op == IFX &&
14266               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14267             genIfx (ic->next, ic);
14268           else
14269             genIpop (ic);
14270           break;
14271
14272         case CALL:
14273           genCall (ic);
14274           break;
14275
14276         case PCALL:
14277           genPcall (ic);
14278           break;
14279
14280         case FUNCTION:
14281           genFunction (ic);
14282           break;
14283
14284         case ENDFUNCTION:
14285           genEndFunction (ic);
14286           break;
14287
14288         case RETURN:
14289           genRet (ic);
14290           break;
14291
14292         case LABEL:
14293           genLabel (ic);
14294           break;
14295
14296         case GOTO:
14297           genGoto (ic);
14298           break;
14299
14300         case '+':
14301           genPlus (ic);
14302           break;
14303
14304         case '-':
14305           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14306             genMinus (ic);
14307           break;
14308
14309         case '*':
14310           genMult (ic);
14311           break;
14312
14313         case '/':
14314           genDiv (ic);
14315           break;
14316
14317         case '%':
14318           genMod (ic);
14319           break;
14320
14321         case '>':
14322           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14323           break;
14324
14325         case '<':
14326           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14327           break;
14328
14329         case LE_OP:
14330         case GE_OP:
14331         case NE_OP:
14332
14333           /* note these two are xlated by algebraic equivalence
14334              during parsing SDCC.y */
14335           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14336                   "got '>=' or '<=' shouldn't have come here");
14337           break;
14338
14339         case EQ_OP:
14340           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14341           break;
14342
14343         case AND_OP:
14344           genAndOp (ic);
14345           break;
14346
14347         case OR_OP:
14348           genOrOp (ic);
14349           break;
14350
14351         case '^':
14352           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14353           break;
14354
14355         case '|':
14356           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14357           break;
14358
14359         case BITWISEAND:
14360           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14361           break;
14362
14363         case INLINEASM:
14364           genInline (ic);
14365           break;
14366
14367         case RRC:
14368           genRRC (ic);
14369           break;
14370
14371         case RLC:
14372           genRLC (ic);
14373           break;
14374
14375         case GETHBIT:
14376           genGetHbit (ic);
14377           break;
14378
14379         case LEFT_OP:
14380           genLeftShift (ic);
14381           break;
14382
14383         case RIGHT_OP:
14384           genRightShift (ic);
14385           break;
14386
14387         case GET_VALUE_AT_ADDRESS:
14388           genPointerGet (ic,
14389                          hasInc (IC_LEFT (ic), ic,
14390                                  getSize (operandType (IC_RESULT (ic)))));
14391           break;
14392
14393         case '=':
14394           if (POINTER_SET (ic))
14395             genPointerSet (ic,
14396                            hasInc (IC_RESULT (ic), ic,
14397                                    getSize (operandType (IC_RIGHT (ic)))));
14398           else
14399             genAssign (ic);
14400           break;
14401
14402         case IFX:
14403           genIfx (ic, NULL);
14404           break;
14405
14406         case ADDRESS_OF:
14407           genAddrOf (ic);
14408           break;
14409
14410         case JUMPTABLE:
14411           genJumpTab (ic);
14412           break;
14413
14414         case CAST:
14415           genCast (ic);
14416           break;
14417
14418         case RECEIVE:
14419           genReceive (ic);
14420           break;
14421
14422         case SEND:
14423           if (ic->builtinSEND)
14424             genBuiltIn(ic);
14425           else
14426             addSet (&_G.sendSet, ic);
14427           break;
14428
14429         case DUMMY_READ_VOLATILE:
14430           genDummyRead (ic);
14431           break;
14432
14433         case CRITICAL:
14434           genCritical (ic);
14435           break;
14436
14437         case ENDCRITICAL:
14438           genEndCritical (ic);
14439           break;
14440
14441         case SWAP:
14442           genSwap (ic);
14443           break;
14444
14445 #if 0 // obsolete, and buggy for != xdata
14446         case ARRAYINIT:
14447             genArrayInit(ic);
14448             break;
14449 #endif
14450
14451         default:
14452           ic = ic;
14453         }
14454     }
14455
14456
14457   /* now we are ready to call the
14458      peep hole optimizer */
14459   if (!options.nopeep)
14460     peepHole (&lineHead);
14461
14462   /* now do the actual printing */
14463   printLine (lineHead, codeOutFile);
14464   return;
14465 }